mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-08-25 18:28:01 +00:00
Handle magisk.db completely natively
Prevent database corruption due to different Android application sqlite default settings
This commit is contained in:
@@ -942,13 +942,16 @@ core_only:
|
||||
} else {
|
||||
// Check whether we have a valid manager installed
|
||||
sqlite3 *db = get_magiskdb();
|
||||
struct db_strings str;
|
||||
memset(&str, 0, sizeof(str));
|
||||
get_db_strings(db, SU_MANAGER, &str);
|
||||
if (validate_manager(str.s[SU_MANAGER], 0, NULL)) {
|
||||
// There is no manager installed, install the stub
|
||||
exec_command_sync("/sbin/magiskinit", "-x", "manager", "/data/magisk.apk", NULL);
|
||||
install_apk("/data/magisk.apk");
|
||||
if (db) {
|
||||
struct db_strings str;
|
||||
memset(&str, 0, sizeof(str));
|
||||
get_db_strings(db, SU_MANAGER, &str);
|
||||
if (validate_manager(str.s[SU_MANAGER], 0, NULL)) {
|
||||
// There is no manager installed, install the stub
|
||||
exec_command_sync("/sbin/magiskinit", "-x", "manager", "/data/magisk.apk", NULL);
|
||||
install_apk("/data/magisk.apk");
|
||||
}
|
||||
sqlite3_close_v2(db);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -8,20 +8,67 @@
|
||||
#include "magisk.h"
|
||||
#include "db.h"
|
||||
|
||||
static int policy_cb(void *v, int col_num, char **data, char **col_name) {
|
||||
struct su_access *su = v;
|
||||
for (int i = 0; i < col_num; i++) {
|
||||
if (strcmp(col_name[i], "policy") == 0)
|
||||
su->policy = (policy_t) atoi(data[i]);
|
||||
else if (strcmp(col_name[i], "logging") == 0)
|
||||
su->log = atoi(data[i]);
|
||||
else if (strcmp(col_name[i], "notification") == 0)
|
||||
su->notify = atoi(data[i]);
|
||||
}
|
||||
LOGD("magiskdb: query policy=[%d] log=[%d] notify=[%d]\n", su->policy, su->log, su->notify);
|
||||
static int ver_cb(void *v, int col_num, char **data, char **col_name) {
|
||||
*((int *) v) = atoi(data[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sqlite3 *get_magiskdb() {
|
||||
sqlite3 *db;
|
||||
char *err;
|
||||
int ret = sqlite3_open(MAGISKDB, &db);
|
||||
if (ret) {
|
||||
LOGE("sqlite3 open failure: %s\n", sqlite3_errstr(ret));
|
||||
return NULL;
|
||||
}
|
||||
int ver, upgrade = 0;
|
||||
sqlite3_exec(db, "PRAGMA user_version", ver_cb, &ver, &err);
|
||||
if (ver < 3) {
|
||||
// Policies
|
||||
sqlite3_exec(db,
|
||||
"CREATE TABLE IF NOT EXISTS policies "
|
||||
"(uid INT, package_name TEXT, policy INT, until INT, "
|
||||
"logging INT, notification INT, PRIMARY KEY(uid))",
|
||||
NULL, NULL, &err);
|
||||
// Logs
|
||||
sqlite3_exec(db,
|
||||
"CREATE TABLE IF NOT EXISTS logs "
|
||||
"(from_uid INT, package_name TEXT, app_name TEXT, from_pid INT, "
|
||||
"to_uid INT, action INT, time INT, command TEXT)",
|
||||
NULL, NULL, &err);
|
||||
// Settings
|
||||
sqlite3_exec(db,
|
||||
"CREATE TABLE IF NOT EXISTS settings "
|
||||
"(key TEXT, value INT, PRIMARY KEY(key))",
|
||||
NULL, NULL, &err);
|
||||
ver = 3;
|
||||
upgrade = 1;
|
||||
}
|
||||
if (ver == 3) {
|
||||
// Strings
|
||||
sqlite3_exec(db,
|
||||
"CREATE TABLE IF NOT EXISTS strings "
|
||||
"(key TEXT, value TEXT, PRIMARY KEY(key))",
|
||||
NULL, NULL, &err);
|
||||
ver = 4;
|
||||
upgrade = 1;
|
||||
}
|
||||
if (ver == 4) {
|
||||
sqlite3_exec(db, "UPDATE policies SET uid=uid%100000", NULL, NULL, &err);
|
||||
/* Skip version 5 */
|
||||
ver = 6;
|
||||
upgrade = 1;
|
||||
}
|
||||
|
||||
if (upgrade) {
|
||||
// Set version
|
||||
char query[32];
|
||||
sprintf(query, "PRAGMA user_version=%d", ver);
|
||||
sqlite3_exec(db, query, NULL, NULL, &err);
|
||||
}
|
||||
return db;
|
||||
}
|
||||
|
||||
static int settings_cb(void *v, int col_num, char **data, char **col_name) {
|
||||
struct db_settings *dbs = v;
|
||||
int key = -1, value;
|
||||
@@ -42,6 +89,24 @@ static int settings_cb(void *v, int col_num, char **data, char **col_name) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_db_settings(sqlite3 *db, int key, struct db_settings *dbs) {
|
||||
if (db == NULL)
|
||||
return 1;
|
||||
char *err;
|
||||
if (key > 0) {
|
||||
char query[128];
|
||||
sprintf(query, "SELECT key, value FROM settings WHERE key=%d", key);
|
||||
sqlite3_exec(db, query, settings_cb, dbs, &err);
|
||||
} else {
|
||||
sqlite3_exec(db, "SELECT key, value FROM settings", settings_cb, dbs, &err);
|
||||
}
|
||||
if (err) {
|
||||
LOGE("sqlite3_exec: %s\n", err);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int strings_cb(void *v, int col_num, char **data, char **col_name) {
|
||||
struct db_strings *dbs = v;
|
||||
int key = -1;
|
||||
@@ -63,38 +128,6 @@ static int strings_cb(void *v, int col_num, char **data, char **col_name) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sqlite3 *get_magiskdb() {
|
||||
sqlite3 *db = NULL;
|
||||
if (access(MAGISKDB, R_OK) == 0) {
|
||||
// Open database
|
||||
int ret = sqlite3_open_v2(MAGISKDB, &db, SQLITE_OPEN_READONLY, NULL);
|
||||
if (ret) {
|
||||
LOGE("sqlite3 open failure: %s\n", sqlite3_errstr(ret));
|
||||
sqlite3_close(db);
|
||||
db = NULL;
|
||||
}
|
||||
}
|
||||
return db;
|
||||
}
|
||||
|
||||
int get_db_settings(sqlite3 *db, int key, struct db_settings *dbs) {
|
||||
if (db == NULL)
|
||||
return 1;
|
||||
char *err;
|
||||
if (key > 0) {
|
||||
char query[128];
|
||||
sprintf(query, "SELECT key, value FROM settings WHERE key=%d", key);
|
||||
sqlite3_exec(db, query, settings_cb, dbs, &err);
|
||||
} else {
|
||||
sqlite3_exec(db, "SELECT key, value FROM settings", settings_cb, dbs, &err);
|
||||
}
|
||||
if (err) {
|
||||
LOGE("sqlite3_exec: %s\n", err);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_db_strings(sqlite3 *db, int key, struct db_strings *str) {
|
||||
if (db == NULL)
|
||||
return 1;
|
||||
@@ -113,6 +146,20 @@ int get_db_strings(sqlite3 *db, int key, struct db_strings *str) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int policy_cb(void *v, int col_num, char **data, char **col_name) {
|
||||
struct su_access *su = v;
|
||||
for (int i = 0; i < col_num; i++) {
|
||||
if (strcmp(col_name[i], "policy") == 0)
|
||||
su->policy = (policy_t) atoi(data[i]);
|
||||
else if (strcmp(col_name[i], "logging") == 0)
|
||||
su->log = atoi(data[i]);
|
||||
else if (strcmp(col_name[i], "notification") == 0)
|
||||
su->notify = atoi(data[i]);
|
||||
}
|
||||
LOGD("magiskdb: query policy=[%d] log=[%d] notify=[%d]\n", su->policy, su->log, su->notify);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_uid_policy(sqlite3 *db, int uid, struct su_access *su) {
|
||||
if (db == NULL)
|
||||
return 1;
|
||||
@@ -127,7 +174,7 @@ int get_uid_policy(sqlite3 *db, int uid, struct su_access *su) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int validate_manager(char *pkg, int userid, struct stat *st) {
|
||||
int validate_manager(char *alt_pkg, int userid, struct stat *st) {
|
||||
if (st == NULL) {
|
||||
struct stat stat;
|
||||
st = &stat;
|
||||
@@ -135,19 +182,44 @@ int validate_manager(char *pkg, int userid, struct stat *st) {
|
||||
// Prefer DE storage
|
||||
const char *base = access("/data/user_de", F_OK) == 0 ? "/data/user_de" : "/data/user";
|
||||
char app_path[128];
|
||||
sprintf(app_path, "%s/%d/%s", base, userid, pkg[0] ? pkg : "xxx");
|
||||
sprintf(app_path, "%s/%d/%s", base, userid, alt_pkg[0] ? alt_pkg : "xxx");
|
||||
if (stat(app_path, st)) {
|
||||
// Check the official package name
|
||||
sprintf(app_path, "%s/%d/"JAVA_PACKAGE_NAME, base, userid);
|
||||
if (stat(app_path, st)) {
|
||||
LOGE("su: cannot find manager");
|
||||
memset(st, 0, sizeof(*st));
|
||||
pkg[0] = '\0';
|
||||
alt_pkg[0] = '\0';
|
||||
return 1;
|
||||
} else {
|
||||
// Switch to official package if exists
|
||||
strcpy(pkg, JAVA_PACKAGE_NAME);
|
||||
strcpy(alt_pkg, JAVA_PACKAGE_NAME);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_cb(void *v, int col_num, char **data, char **col_name) {
|
||||
for (int i = 0; i < col_num; ++i) {
|
||||
if (i) printf("|");
|
||||
printf("%s=%s", col_name[i], data[i]);
|
||||
}
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exec_sql(const char *sql) {
|
||||
sqlite3 *db = get_magiskdb();
|
||||
if (db) {
|
||||
char *err;
|
||||
sqlite3_exec(db, sql, print_cb, NULL, &err);
|
||||
sqlite3_close_v2(db);
|
||||
if (err) {
|
||||
fprintf(stderr, "sql_err: %s\n", err);
|
||||
sqlite3_free(err);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#include "magisk.h"
|
||||
#include "daemon.h"
|
||||
#include "selinux.h"
|
||||
#include "db.h"
|
||||
#include "flags.h"
|
||||
|
||||
static int create_links(const char *bin, const char *path) {
|
||||
@@ -43,6 +44,7 @@ static void usage() {
|
||||
" --unlock-blocks set BLKROSET flag to OFF for all block devices\n"
|
||||
" --restorecon fix selinux context on Magisk files and folders\n"
|
||||
" --clone-attr SRC DEST clone permission, owner, and selinux context\n"
|
||||
" --sqlite SQL exec SQL to Magisk database\n"
|
||||
"\n"
|
||||
"Supported init triggers:\n"
|
||||
" startup, post-fs-data, service, boot-complete\n"
|
||||
@@ -110,6 +112,8 @@ int magisk_main(int argc, char *argv[]) {
|
||||
int fd = connect_daemon();
|
||||
write_int(fd, BOOT_COMPLETE);
|
||||
return read_int(fd);
|
||||
} else if (strcmp(argv[1], "--sqlite") == 0) {
|
||||
return exec_sql(argv[2]);
|
||||
}
|
||||
|
||||
usage();
|
||||
|
@@ -119,6 +119,7 @@ sqlite3 *get_magiskdb();
|
||||
int get_db_settings(sqlite3 *db, int key, struct db_settings *dbs);
|
||||
int get_db_strings(sqlite3 *db, int key, struct db_strings *str);
|
||||
int get_uid_policy(sqlite3 *db, int uid, struct su_access *su);
|
||||
int validate_manager(char *pkg, int userid, struct stat *st);
|
||||
int validate_manager(char *alt_pkg, int userid, struct stat *st);
|
||||
int exec_sql(const char *sql);
|
||||
|
||||
#endif //DB_H
|
||||
|
@@ -75,7 +75,7 @@ static void database_check(struct su_info *info) {
|
||||
|
||||
if (uid > 0)
|
||||
get_uid_policy(db, uid, &info->access);
|
||||
sqlite3_close(db);
|
||||
sqlite3_close_v2(db);
|
||||
}
|
||||
|
||||
// We need to check our manager
|
||||
|
Reference in New Issue
Block a user