From 370015a8538cdfc892e0c781a694630a43588add Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Wed, 6 Mar 2019 08:16:12 -0500 Subject: [PATCH] Modernize database code (again) --- native/jni/core/bootstages.cpp | 2 +- native/jni/core/db.cpp | 213 +++++++++++---------------- native/jni/include/db.h | 74 ++++++---- native/jni/magiskhide/hide_utils.cpp | 19 +-- native/jni/su/connect.cpp | 2 +- native/jni/su/su.h | 6 +- native/jni/su/su_daemon.cpp | 6 +- 7 files changed, 141 insertions(+), 181 deletions(-) diff --git a/native/jni/core/bootstages.cpp b/native/jni/core/bootstages.cpp index 6b9a328c6..eefcf863f 100644 --- a/native/jni/core/bootstages.cpp +++ b/native/jni/core/bootstages.cpp @@ -752,7 +752,7 @@ core_only: } else { // Check whether we have a valid manager installed db_strings str; - get_db_strings(&str, SU_MANAGER); + get_db_strings(str, SU_MANAGER); if (validate_manager(str[SU_MANAGER], 0, nullptr)) { // There is no manager installed, install the stub exec_command_sync("/sbin/magiskinit", "-x", "manager", "/data/magisk.apk"); diff --git a/native/jni/core/db.cpp b/native/jni/core/db.cpp index fe76eaad4..85f7aae63 100644 --- a/native/jni/core/db.cpp +++ b/native/jni/core/db.cpp @@ -11,64 +11,31 @@ #define DB_VERSION 9 +using namespace std; + static sqlite3 *mDB = nullptr; -db_strings::db_strings() { - memset(data, 0, sizeof(data)); -} - -char *db_strings::operator[](const char *key) { - return data[getKeyIdx(key)]; -} - -const char *db_strings::operator[](const char *key) const { - return data[getKeyIdx(key)]; -} - -char *db_strings::operator[](const int idx) { - return data[idx]; -} - -const char *db_strings::operator[](const int idx) const { - return data[idx]; -} - -int db_strings::getKeyIdx(const char *key) const { +int db_strings::getKeyIdx(string_view key) const { int idx = DB_STRING_NUM; for (int i = 0; i < DB_STRING_NUM; ++i) { - if (strcmp(key, DB_STRING_KEYS[i]) == 0) + if (key == DB_STRING_KEYS[i]) idx = i; } return idx; } -db_settings::db_settings() : data { - ROOT_ACCESS_APPS_AND_ADB, - MULTIUSER_MODE_OWNER_ONLY, - NAMESPACE_MODE_REQUESTER, - 1 -} {} - -int &db_settings::operator[](const int idx) { - return data[idx]; +db_settings::db_settings() { + // Default settings + data[0] = ROOT_ACCESS_APPS_AND_ADB; + data[1] = MULTIUSER_MODE_OWNER_ONLY; + data[2] = NAMESPACE_MODE_REQUESTER; + data[3] = 1; } -const int &db_settings::operator[](const int idx) const { - return data[idx]; -} - -int &db_settings::operator[](const char *key) { - return data[getKeyIdx(key)]; -} - -const int &db_settings::operator[](const char *key) const { - return data[getKeyIdx(key)]; -} - -int db_settings::getKeyIdx(const char *key) const { +int db_settings::getKeyIdx(string_view key) const { int idx = DB_SETTINGS_NUM; for (int i = 0; i < DB_SETTINGS_NUM; ++i) { - if (strcmp(key, DB_SETTING_KEYS[i]) == 0) + if (key == DB_SETTING_KEYS[i]) idx = i; } return idx; @@ -187,7 +154,7 @@ static char *open_and_init_db(sqlite3 *&db) { return nullptr; } -char *db_exec(const char *sql, int (*cb)(void *, int, char**, char**), void *v) { +char *db_exec(const char *sql) { char *err; if (mDB == nullptr) { err = open_and_init_db(mDB); @@ -199,139 +166,125 @@ char *db_exec(const char *sql, int (*cb)(void *, int, char**, char**), void *v) ); } if (mDB) { - sqlite3_exec(mDB, sql, cb, v, &err); + sqlite3_exec(mDB, sql, nullptr, nullptr, &err); return err; } return nullptr; } -static int settings_cb(void *v, int col_num, char **data, char **col_name) { - auto &cfg = *(db_settings *) v; - int value = -1; - const char *key = ""; - for (int i = 0; i < col_num; ++i) { - if (strcmp(col_name[i], "key") == 0) { - key = data[i]; - } else if (strcmp(col_name[i], "value") == 0) { - value = atoi(data[i]); - } +char *db_exec(const char *sql, const db_row_cb &fn) { + char *err; + if (mDB == nullptr) { + err = open_and_init_db(mDB); + db_err_cmd(err, + // Open fails, remove and reconstruct + unlink(MAGISKDB); + err = open_and_init_db(mDB); + err_ret(err); + ); } - if (key[0] && value >= 0) { - cfg[key] = value; - LOGD("magiskdb: query %s=[%d]\n", key, value); + if (mDB) { + sqlite3_exec(mDB, sql, [](void *cb, int col_num, char **data, char **col_name) -> int { + auto &func = *reinterpret_cast(cb); + db_row row; + for (int i = 0; i < col_num; ++i) + row[col_name[i]] = data[i]; + return func(row) ? 0 : 1; + }, (void *) &fn, &err); + return err; } - return 0; + return nullptr; } -int get_db_settings(db_settings *dbs, int key) { +int get_db_settings(db_settings &cfg, int key) { char *err; + auto settings_cb = [&](db_row &row) -> bool { + cfg[row["key"]] = atoi(row["value"].data()); + LOGD("magiskdb: query %s=[%s]\n", row["key"].data(), row["value"].data()); + return true; + }; if (key >= 0) { char query[128]; sprintf(query, "SELECT key, value FROM settings WHERE key='%s'", DB_SETTING_KEYS[key]); - err = db_exec(query, settings_cb, dbs); + err = db_exec(query, settings_cb); } else { - err = db_exec("SELECT key, value FROM settings", settings_cb, dbs); + err = db_exec("SELECT key, value FROM settings", settings_cb); } db_err_cmd(err, return 1); return 0; } -static int strings_cb(void *v, int col_num, char **data, char **col_name) { - auto &str = *(db_strings *) v; - const char *key = "", *value = ""; - for (int i = 0; i < col_num; ++i) { - if (strcmp(col_name[i], "key") == 0) { - key = data[i]; - } else if (strcmp(col_name[i], "value") == 0) { - value = data[i]; - } - } - if (key[0] && value[0]) { - strcpy(str[key], value); - LOGD("magiskdb: query %s=[%s]\n", key, value); - } - return 0; -} - -int get_db_strings(db_strings *str, int key) { +int get_db_strings(db_strings &str, int key) { char *err; + auto string_cb = [&](db_row &row) -> bool { + str[row["key"]] = row["value"]; + LOGD("magiskdb: query %s=[%s]\n", row["key"].data(), row["value"].data()); + return true; + }; if (key >= 0) { char query[128]; sprintf(query, "SELECT key, value FROM strings WHERE key='%s'", DB_STRING_KEYS[key]); - err = db_exec(query, strings_cb, str); + err = db_exec(query, string_cb); } else { - err = db_exec("SELECT key, value FROM strings", strings_cb, str); + err = db_exec("SELECT key, value FROM strings", string_cb); } - if (err) { - LOGE("sqlite3_exec: %s\n", err); - sqlite3_free(err); - return 1; - } - return 0; -} - -static int policy_cb(void *v, int col_num, char **data, char **col_name) { - auto su = (su_access *) 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(int uid, struct su_access *su) { - char query[256], *err; - sprintf(query, "SELECT policy, logging, notification FROM policies " - "WHERE uid=%d AND (until=0 OR until>%li)", uid, time(nullptr)); - err = db_exec(query, policy_cb, su); db_err_cmd(err, return 1); return 0; } -int validate_manager(char *alt_pkg, int userid, struct stat *st) { - if (st == nullptr) { - struct stat stat; - st = &stat; - } +int get_uid_policy(int uid, su_access &su) { + char query[256], *err; + sprintf(query, "SELECT policy, logging, notification FROM policies " + "WHERE uid=%d AND (until=0 OR until>%li)", uid, time(nullptr)); + err = db_exec(query, [&](db_row &row) -> bool { + su.policy = (policy_t) atoi(row["policy"].data()); + su.log = atoi(row["logging"].data()); + su.notify = atoi(row["notification"].data()); + LOGD("magiskdb: query policy=[%d] log=[%d] notify=[%d]\n", su.policy, su.log, su.notify); + return true; + }); + db_err_cmd(err, return 1); + return 0; +} + +int validate_manager(string &alt_pkg, int userid, struct stat *st) { + struct stat tmp_st; + if (st == nullptr) + st = &tmp_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, alt_pkg[0] ? alt_pkg : "xxx"); + sprintf(app_path, "%s/%d/%s", base, userid, alt_pkg.empty() ? "xxx" : alt_pkg.data()); 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)); - alt_pkg[0] = '\0'; + alt_pkg.clear(); return 1; } else { // Switch to official package if exists - strcpy(alt_pkg, JAVA_PACKAGE_NAME); + alt_pkg = JAVA_PACKAGE_NAME; } } return 0; } -static int print_cb(void *v, int col_num, char **data, char **col_name) { - FILE *out = (FILE *) v; - for (int i = 0; i < col_num; ++i) { - if (i) fprintf(out, "|"); - fprintf(out, "%s=%s", col_name[i], data[i]); - } - fprintf(out, "\n"); - return 0; -} - void exec_sql(int client) { char *sql = read_string(client); FILE *out = fdopen(recv_fd(client), "a"); - char *err = db_exec(sql, print_cb, out); + char *err = db_exec(sql, [&](db_row &row) -> bool { + bool first = false; + for (auto it : row) { + if (first) fprintf(out, "|"); + else first = true; + fprintf(out, "%s=%s", it.first.data(), it.second.data()); + } + fprintf(out, "\n"); + return true; + }); free(sql); fclose(out); db_err_cmd(err, diff --git a/native/jni/include/db.h b/native/jni/include/db.h index c57181474..50f8605ca 100644 --- a/native/jni/include/db.h +++ b/native/jni/include/db.h @@ -1,8 +1,11 @@ -#ifndef DB_H -#define DB_H +#pragma once #include #include +#include +#include +#include +#include #define db_err(e) db_err_cmd(e, ) #define db_err_cmd(e, cmd) if (e) { \ @@ -11,6 +14,30 @@ cmd;\ } +template +class db_data_base { +public: + T& operator [](std::string_view key) { + return data[getKeyIdx(key)]; + } + + const T& operator [](std::string_view key) const { + return data[getKeyIdx(key)]; + } + + T& operator [](int key) { + return data[key]; + } + + const T& operator [](int key) const { + return data[key]; + } + +protected: + T data[num + 1]; + virtual int getKeyIdx(std::string_view key) const = 0; +}; + /*************** * DB Settings * ***************/ @@ -55,17 +82,12 @@ enum { NAMESPACE_MODE_ISOLATE }; -class db_settings { +class db_settings : public db_data_base { public: db_settings(); - int& operator [](const char *); - const int& operator [](const char *) const; - int& operator [](const int); - const int& operator [](const int) const; -private: - int data[DB_SETTINGS_NUM + 1]; - int getKeyIdx(const char *) const; +protected: + int getKeyIdx(std::string_view key) const override; }; /************** @@ -84,17 +106,9 @@ enum { SU_MANAGER = 0 }; -class db_strings { -public: - db_strings(); - char * operator [](const char *); - const char * operator [](const char *) const; - char * operator [](const int); - const char * operator [](const int) const; - -private: - char data[DB_STRING_NUM + 1][128]; - int getKeyIdx(const char *) const; +class db_strings : public db_data_base { +protected: + int getKeyIdx(std::string_view key) const override; }; /************* @@ -135,12 +149,14 @@ struct su_access { * Public Functions * ********************/ -sqlite3 *get_magiskdb(sqlite3 *&db); -int get_db_settings(db_settings *dbs, int key = -1); -int get_db_strings(db_strings *str, int key = -1); -int get_uid_policy(int uid, struct su_access *su); -int validate_manager(char *alt_pkg, int userid, struct stat *st); -void exec_sql(int client); -char *db_exec(const char *sql, int (*cb)(void *, int, char**, char**) = nullptr, void *v = nullptr); +typedef std::map db_row; +typedef std::function db_row_cb; + +int get_db_settings(db_settings &cfg, int key = -1); +int get_db_strings(db_strings &str, int key = -1); +int get_uid_policy(int uid, su_access &su); +int validate_manager(std::string &alt_pkg, int userid, struct stat *st); +void exec_sql(int client); +char *db_exec(const char *sql); +char *db_exec(const char *sql, const db_row_cb &fn); -#endif //DB_H diff --git a/native/jni/magiskhide/hide_utils.cpp b/native/jni/magiskhide/hide_utils.cpp index 598f7a152..38b608643 100644 --- a/native/jni/magiskhide/hide_utils.cpp +++ b/native/jni/magiskhide/hide_utils.cpp @@ -204,24 +204,15 @@ static void init_list(const char *pkg, const char *proc) { kill_process(proc); } -static int db_init_list(void *, int col_num, char **data, char **cols) { - char *pkg, *proc; - for (int i = 0; i < col_num; ++i) { - if (strcmp(cols[i], "package_name") == 0) - pkg = data[i]; - else if (strcmp(cols[i], "process") == 0) - proc = data[i]; - } - init_list(pkg, proc); - return 0; -} - #define LEGACY_LIST MODULEROOT "/.core/hidelist" bool init_list() { LOGD("hide_list: initialize\n"); - char *err = db_exec("SELECT * FROM hidelist", db_init_list); + char *err = db_exec("SELECT * FROM hidelist", [](db_row &row) -> bool { + init_list(row["package_name"].data(), row["process"].data()); + return true; + }); db_err_cmd(err, return false); // Migrate old hide list into database @@ -328,7 +319,7 @@ int stop_magiskhide() { void auto_start_magiskhide() { db_settings dbs; - get_db_settings(&dbs, HIDE_CONFIG); + get_db_settings(dbs, HIDE_CONFIG); if (dbs[HIDE_CONFIG]) { new_daemon_thread([](auto) -> void* { launch_magiskhide(-1); diff --git a/native/jni/su/connect.cpp b/native/jni/su/connect.cpp index 99180872f..07d6c13c7 100644 --- a/native/jni/su/connect.cpp +++ b/native/jni/su/connect.cpp @@ -33,7 +33,7 @@ static inline const char *get_command(const struct su_request *to) { static void silent_run(const char **args, struct su_info *info) { char component[128]; - sprintf(component, "%s/a.h", info->str[SU_MANAGER]); + sprintf(component, "%s/a.h", info->str[SU_MANAGER].data()); args[5] = component; exec_t exec { .pre_exec = []() -> void { diff --git a/native/jni/su/su.h b/native/jni/su/su.h index d9bce9971..c4a38f72d 100644 --- a/native/jni/su/su.h +++ b/native/jni/su/su.h @@ -23,9 +23,9 @@ public: int count; /* Just a count for debugging purpose */ /* These values should be guarded with internal lock */ - struct db_settings cfg; - struct db_strings str; - struct su_access access; + db_settings cfg; + db_strings str; + su_access access; struct stat mgr_st; /* These should be guarded with global cache lock */ diff --git a/native/jni/su/su_daemon.cpp b/native/jni/su/su_daemon.cpp index 5bed94029..f2fa0dfe2 100644 --- a/native/jni/su/su_daemon.cpp +++ b/native/jni/su/su_daemon.cpp @@ -63,8 +63,8 @@ void su_info::deRef() { static void database_check(su_info *info) { int uid = info->uid; - get_db_settings(&info->cfg); - get_db_strings(&info->str); + get_db_settings(info->cfg); + get_db_strings(info->str); // Check multiuser settings switch (info->cfg[SU_MULTIUSER_MODE]) { @@ -83,7 +83,7 @@ static void database_check(su_info *info) { } if (uid > 0) - get_uid_policy(uid, &info->access); + get_uid_policy(uid, info->access); // We need to check our manager if (info->access.log || info->access.notify)