mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-03-04 14:05:11 +00:00
Cleanup database code
This commit is contained in:
parent
10e47248de
commit
3ca6d06f69
@ -24,6 +24,7 @@ LOCAL_SRC_FILES := \
|
|||||||
core/package.cpp \
|
core/package.cpp \
|
||||||
core/scripting.cpp \
|
core/scripting.cpp \
|
||||||
core/selinux.cpp \
|
core/selinux.cpp \
|
||||||
|
core/sqlite.cpp \
|
||||||
core/module.cpp \
|
core/module.cpp \
|
||||||
core/thread.cpp \
|
core/thread.cpp \
|
||||||
core/core-rs.cpp \
|
core/core-rs.cpp \
|
||||||
|
@ -1,114 +1,21 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <dlfcn.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include <consts.hpp>
|
#include <consts.hpp>
|
||||||
#include <base.hpp>
|
#include <base.hpp>
|
||||||
#include <db.hpp>
|
#include <db.hpp>
|
||||||
|
#include <sqlite.hpp>
|
||||||
#include <core.hpp>
|
#include <core.hpp>
|
||||||
|
|
||||||
#define DB_VERSION 12
|
#define DB_VERSION 12
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
struct sqlite3;
|
|
||||||
struct sqlite3_stmt;
|
|
||||||
|
|
||||||
static sqlite3 *mDB = nullptr;
|
static sqlite3 *mDB = nullptr;
|
||||||
|
|
||||||
#define DBLOGV(...)
|
#define DBLOGV(...)
|
||||||
//#define DBLOGV(...) LOGD("magiskdb: " __VA_ARGS__)
|
//#define DBLOGV(...) LOGD("magiskdb: " __VA_ARGS__)
|
||||||
|
|
||||||
// SQLite APIs
|
|
||||||
|
|
||||||
#define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */
|
|
||||||
#define SQLITE_OPEN_CREATE 0x00000004 /* Ok for sqlite3_open_v2() */
|
|
||||||
#define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */
|
|
||||||
|
|
||||||
#define SQLITE_OK 0 /* Successful result */
|
|
||||||
#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */
|
|
||||||
#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */
|
|
||||||
|
|
||||||
static int (*sqlite3_open_v2)(const char *filename, sqlite3 **ppDb, int flags, const char *zVfs);
|
|
||||||
static int (*sqlite3_close)(sqlite3 *db);
|
|
||||||
static int (*sqlite3_prepare_v2)(sqlite3 *db, const char *zSql, int nByte, sqlite3_stmt **ppStmt, const char **pzTail);
|
|
||||||
static int (*sqlite3_bind_parameter_count)(sqlite3_stmt*);
|
|
||||||
static int (*sqlite3_bind_int)(sqlite3_stmt*, int, int);
|
|
||||||
static int (*sqlite3_bind_text)(sqlite3_stmt*,int,const char*,int,void(*)(void*));
|
|
||||||
static int (*sqlite3_column_count)(sqlite3_stmt *pStmt);
|
|
||||||
static const char *(*sqlite3_column_name)(sqlite3_stmt*, int N);
|
|
||||||
static const char *(*sqlite3_column_text)(sqlite3_stmt*, int iCol);
|
|
||||||
static int (*sqlite3_step)(sqlite3_stmt*);
|
|
||||||
static int (*sqlite3_finalize)(sqlite3_stmt *pStmt);
|
|
||||||
static const char *(*sqlite3_errstr)(int);
|
|
||||||
|
|
||||||
// Internal Android linker APIs
|
|
||||||
|
|
||||||
static void (*android_get_LD_LIBRARY_PATH)(char *buffer, size_t buffer_size);
|
|
||||||
static void (*android_update_LD_LIBRARY_PATH)(const char *ld_library_path);
|
|
||||||
|
|
||||||
#define DLERR(ptr) if (!(ptr)) { \
|
|
||||||
LOGE("db: %s\n", dlerror()); \
|
|
||||||
return false; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define DLOAD(handle, arg) {\
|
|
||||||
auto f = dlsym(handle, #arg); \
|
|
||||||
DLERR(f) \
|
|
||||||
*(void **) &(arg) = f; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __LP64__
|
|
||||||
constexpr char apex_path[] = "/apex/com.android.runtime/lib64:/apex/com.android.art/lib64:/apex/com.android.i18n/lib64:";
|
|
||||||
#else
|
|
||||||
constexpr char apex_path[] = "/apex/com.android.runtime/lib:/apex/com.android.art/lib:/apex/com.android.i18n/lib:";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static bool dload_sqlite() {
|
|
||||||
static int dl_init = 0;
|
|
||||||
if (dl_init)
|
|
||||||
return dl_init > 0;
|
|
||||||
dl_init = -1;
|
|
||||||
|
|
||||||
auto sqlite = dlopen("libsqlite.so", RTLD_LAZY);
|
|
||||||
if (!sqlite) {
|
|
||||||
// Should only happen on Android 10+
|
|
||||||
auto dl = dlopen("libdl_android.so", RTLD_LAZY);
|
|
||||||
DLERR(dl);
|
|
||||||
|
|
||||||
DLOAD(dl, android_get_LD_LIBRARY_PATH);
|
|
||||||
DLOAD(dl, android_update_LD_LIBRARY_PATH);
|
|
||||||
|
|
||||||
// Inject APEX into LD_LIBRARY_PATH
|
|
||||||
char ld_path[4096];
|
|
||||||
memcpy(ld_path, apex_path, sizeof(apex_path));
|
|
||||||
constexpr int len = sizeof(apex_path) - 1;
|
|
||||||
android_get_LD_LIBRARY_PATH(ld_path + len, sizeof(ld_path) - len);
|
|
||||||
android_update_LD_LIBRARY_PATH(ld_path);
|
|
||||||
sqlite = dlopen("libsqlite.so", RTLD_LAZY);
|
|
||||||
|
|
||||||
// Revert LD_LIBRARY_PATH just in case
|
|
||||||
android_update_LD_LIBRARY_PATH(ld_path + len);
|
|
||||||
}
|
|
||||||
DLERR(sqlite);
|
|
||||||
|
|
||||||
DLOAD(sqlite, sqlite3_open_v2);
|
|
||||||
DLOAD(sqlite, sqlite3_close);
|
|
||||||
DLOAD(sqlite, sqlite3_prepare_v2);
|
|
||||||
DLOAD(sqlite, sqlite3_bind_parameter_count);
|
|
||||||
DLOAD(sqlite, sqlite3_bind_int);
|
|
||||||
DLOAD(sqlite, sqlite3_bind_text);
|
|
||||||
DLOAD(sqlite, sqlite3_step);
|
|
||||||
DLOAD(sqlite, sqlite3_column_count);
|
|
||||||
DLOAD(sqlite, sqlite3_column_name);
|
|
||||||
DLOAD(sqlite, sqlite3_column_text);
|
|
||||||
DLOAD(sqlite, sqlite3_finalize);
|
|
||||||
DLOAD(sqlite, sqlite3_errstr);
|
|
||||||
|
|
||||||
dl_init = 1;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int db_strings::get_idx(string_view key) const {
|
int db_strings::get_idx(string_view key) const {
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
for (const char *k : DB_STRING_KEYS) {
|
for (const char *k : DB_STRING_KEYS) {
|
||||||
@ -139,80 +46,27 @@ int db_settings::get_idx(string_view key) const {
|
|||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ver_cb(void *ver, auto, rust::Slice<rust::String> data) {
|
struct db_result {
|
||||||
*((int *) ver) = parse_int(data[0].c_str());
|
db_result() = default;
|
||||||
}
|
db_result(const char *s) : err(s) {}
|
||||||
|
db_result(int code) : err(code == SQLITE_OK ? "" : (sqlite3_errstr(code) ?: "")) {}
|
||||||
db_result::db_result(int code) : err(code == SQLITE_OK ? "" : (sqlite3_errstr(code) ?: "")) {}
|
operator bool() {
|
||||||
|
if (!err.empty()) {
|
||||||
bool db_result::check_err() {
|
LOGE("sqlite3: %s\n", err.data());
|
||||||
if (!err.empty()) {
|
return false;
|
||||||
LOGE("sqlite3: %s\n", err.data());
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
private:
|
||||||
}
|
string err;
|
||||||
|
};
|
||||||
using StringVec = rust::Vec<rust::String>;
|
|
||||||
using StringSlice = rust::Slice<rust::String>;
|
|
||||||
using StrSlice = rust::Slice<rust::Str>;
|
|
||||||
using sqlite_row_callback = void(*)(void*, StringSlice, StringSlice);
|
|
||||||
|
|
||||||
#define fn_run_ret(fn, ...) if (int rc = fn(__VA_ARGS__); rc != SQLITE_OK) return rc
|
|
||||||
|
|
||||||
static int sql_exec(sqlite3 *db, rust::Str zSql, StrSlice args, sqlite_row_callback callback, void *v) {
|
|
||||||
const char *sql = zSql.begin();
|
|
||||||
auto arg_it = args.begin();
|
|
||||||
unique_ptr<sqlite3_stmt, decltype(sqlite3_finalize)> stmt(nullptr, sqlite3_finalize);
|
|
||||||
|
|
||||||
while (sql != zSql.end()) {
|
|
||||||
// Step 1: prepare statement
|
|
||||||
{
|
|
||||||
sqlite3_stmt *st = nullptr;
|
|
||||||
fn_run_ret(sqlite3_prepare_v2, db, sql, zSql.end() - sql, &st, &sql);
|
|
||||||
if (st == nullptr) continue;
|
|
||||||
stmt.reset(st);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 2: bind arguments
|
|
||||||
if (int count = sqlite3_bind_parameter_count(stmt.get())) {
|
|
||||||
for (int i = 1; i <= count && arg_it != args.end(); ++i, ++arg_it) {
|
|
||||||
fn_run_ret(sqlite3_bind_text, stmt.get(), i, arg_it->data(), arg_it->size(), nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 3: execute
|
|
||||||
bool first = true;
|
|
||||||
StringVec columns;
|
|
||||||
for (;;) {
|
|
||||||
int rc = sqlite3_step(stmt.get());
|
|
||||||
if (rc == SQLITE_DONE) break;
|
|
||||||
if (rc != SQLITE_ROW) return rc;
|
|
||||||
if (callback == nullptr) continue;
|
|
||||||
if (first) {
|
|
||||||
int count = sqlite3_column_count(stmt.get());
|
|
||||||
for (int i = 0; i < count; ++i) {
|
|
||||||
columns.emplace_back(sqlite3_column_name(stmt.get(), i));
|
|
||||||
}
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
StringVec data;
|
|
||||||
for (int i = 0; i < columns.size(); ++i) {
|
|
||||||
data.emplace_back(sqlite3_column_text(stmt.get(), i));
|
|
||||||
}
|
|
||||||
callback(v, StringSlice(columns), StringSlice(data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return SQLITE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sql_exec(sqlite3 *db, const char *sql, sqlite_row_callback callback = nullptr, void *v = nullptr) {
|
static int sql_exec(sqlite3 *db, const char *sql, sqlite_row_callback callback = nullptr, void *v = nullptr) {
|
||||||
return sql_exec(db, sql, {}, callback, v);
|
return sql_exec(db, sql, {}, callback, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
static db_result open_and_init_db() {
|
static db_result open_and_init_db() {
|
||||||
if (!dload_sqlite())
|
if (!load_sqlite())
|
||||||
return "Cannot load libsqlite.so";
|
return "Cannot load libsqlite.so";
|
||||||
|
|
||||||
unique_ptr<sqlite3, decltype(sqlite3_close)> db(nullptr, sqlite3_close);
|
unique_ptr<sqlite3, decltype(sqlite3_close)> db(nullptr, sqlite3_close);
|
||||||
@ -225,6 +79,9 @@ static db_result open_and_init_db() {
|
|||||||
|
|
||||||
int ver = 0;
|
int ver = 0;
|
||||||
bool upgrade = false;
|
bool upgrade = false;
|
||||||
|
auto ver_cb = [](void *ver, auto, StringSlice data) {
|
||||||
|
*((int *) ver) = parse_int(data[0].c_str());
|
||||||
|
};
|
||||||
fn_run_ret(sql_exec, db.get(), "PRAGMA user_version", ver_cb, &ver);
|
fn_run_ret(sql_exec, db.get(), "PRAGMA user_version", ver_cb, &ver);
|
||||||
if (ver > DB_VERSION) {
|
if (ver > DB_VERSION) {
|
||||||
// Don't support downgrading database
|
// Don't support downgrading database
|
||||||
@ -339,43 +196,41 @@ static db_result open_and_init_db() {
|
|||||||
|
|
||||||
static db_result ensure_db() {
|
static db_result ensure_db() {
|
||||||
if (mDB == nullptr) {
|
if (mDB == nullptr) {
|
||||||
auto res = open_and_init_db();
|
db_result res = open_and_init_db();
|
||||||
if (res.check_err()) {
|
if (!res) {
|
||||||
// Open fails, remove and reconstruct
|
// Open fails, remove and reconstruct
|
||||||
unlink(MAGISKDB);
|
unlink(MAGISKDB);
|
||||||
res = open_and_init_db();
|
return open_and_init_db();
|
||||||
if (!res) return res;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
db_result db_exec(const char *sql) {
|
bool db_exec(const char *sql) {
|
||||||
if (auto res = ensure_db(); !res) return res;
|
if (ensure_db() && mDB) {
|
||||||
if (mDB) {
|
db_result res = sql_exec(mDB, sql);
|
||||||
return sql_exec(mDB, sql);
|
return res;
|
||||||
}
|
}
|
||||||
return {};
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void row_to_db_row(void *cb, rust::Slice<rust::String> columns, rust::Slice<rust::String> data) {
|
bool db_exec(const char *sql, const db_row_cb &fn) {
|
||||||
auto &func = *static_cast<const db_row_cb*>(cb);
|
if (ensure_db() && mDB) {
|
||||||
db_row row;
|
auto convert = [](void *cb, StringSlice columns, StringSlice data) {
|
||||||
for (int i = 0; i < columns.size(); ++i)
|
auto &func = *static_cast<const db_row_cb*>(cb);
|
||||||
row[columns[i].c_str()] = data[i].c_str();
|
db_row row;
|
||||||
func(row);
|
for (int i = 0; i < columns.size(); ++i)
|
||||||
}
|
row[columns[i].c_str()] = data[i].c_str();
|
||||||
|
func(row);
|
||||||
db_result db_exec(const char *sql, const db_row_cb &fn) {
|
};
|
||||||
if (auto res = ensure_db(); !res) return res;
|
db_result res = sql_exec(mDB, sql, convert, (void *) &fn);
|
||||||
if (mDB) {
|
return res;
|
||||||
return sql_exec(mDB, sql, row_to_db_row, (void *) &fn);
|
|
||||||
}
|
}
|
||||||
return {};
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_db_settings(db_settings &cfg, int key) {
|
int get_db_settings(db_settings &cfg, int key) {
|
||||||
db_result res;
|
bool res;
|
||||||
auto settings_cb = [&](db_row &row) -> bool {
|
auto settings_cb = [&](db_row &row) -> bool {
|
||||||
cfg[row["key"]] = parse_int(row["value"]);
|
cfg[row["key"]] = parse_int(row["value"]);
|
||||||
DBLOGV("query %s=[%s]\n", row["key"].data(), row["value"].data());
|
DBLOGV("query %s=[%s]\n", row["key"].data(), row["value"].data());
|
||||||
@ -388,18 +243,18 @@ int get_db_settings(db_settings &cfg, int key) {
|
|||||||
} else {
|
} else {
|
||||||
res = db_exec("SELECT * FROM settings", settings_cb);
|
res = db_exec("SELECT * FROM settings", settings_cb);
|
||||||
}
|
}
|
||||||
return res.check_err() ? 1 : 0;
|
return res ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_db_settings(int key, int value) {
|
int set_db_settings(int key, int value) {
|
||||||
char sql[128];
|
char sql[128];
|
||||||
ssprintf(sql, sizeof(sql), "INSERT OR REPLACE INTO settings VALUES ('%s', %d)",
|
ssprintf(sql, sizeof(sql), "INSERT OR REPLACE INTO settings VALUES ('%s', %d)",
|
||||||
DB_SETTING_KEYS[key], value);
|
DB_SETTING_KEYS[key], value);
|
||||||
return db_exec(sql).check_err() ? 1 : 0;
|
return db_exec(sql) ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_db_strings(db_strings &str, int key) {
|
int get_db_strings(db_strings &str, int key) {
|
||||||
db_result res;
|
bool res;
|
||||||
auto string_cb = [&](db_row &row) -> bool {
|
auto string_cb = [&](db_row &row) -> bool {
|
||||||
str[row["key"]] = row["value"];
|
str[row["key"]] = row["value"];
|
||||||
DBLOGV("query %s=[%s]\n", row["key"].data(), row["value"].data());
|
DBLOGV("query %s=[%s]\n", row["key"].data(), row["value"].data());
|
||||||
@ -412,18 +267,18 @@ int get_db_strings(db_strings &str, int key) {
|
|||||||
} else {
|
} else {
|
||||||
res = db_exec("SELECT * FROM strings", string_cb);
|
res = db_exec("SELECT * FROM strings", string_cb);
|
||||||
}
|
}
|
||||||
return res.check_err() ? 1 : 0;
|
return res ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rm_db_strings(int key) {
|
void rm_db_strings(int key) {
|
||||||
char query[128];
|
char query[128];
|
||||||
ssprintf(query, sizeof(query), "DELETE FROM strings WHERE key == '%s'", DB_STRING_KEYS[key]);
|
ssprintf(query, sizeof(query), "DELETE FROM strings WHERE key == '%s'", DB_STRING_KEYS[key]);
|
||||||
db_exec(query).check_err();
|
db_exec(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
void exec_sql(owned_fd client) {
|
void exec_sql(owned_fd client) {
|
||||||
string sql = read_string(client);
|
string sql = read_string(client);
|
||||||
auto res = db_exec(sql.data(), [fd = (int) client](db_row &row) -> bool {
|
db_exec(sql.data(), [fd = (int) client](db_row &row) -> bool {
|
||||||
string out;
|
string out;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (auto it : row) {
|
for (auto it : row) {
|
||||||
@ -437,5 +292,4 @@ void exec_sql(owned_fd client) {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
write_int(client, 0);
|
write_int(client, 0);
|
||||||
res.check_err();
|
|
||||||
}
|
}
|
||||||
|
@ -201,7 +201,7 @@ void scan_deny_apps() {
|
|||||||
LOGI("denylist rm: [%s]\n", it->first.data());
|
LOGI("denylist rm: [%s]\n", it->first.data());
|
||||||
ssprintf(sql, sizeof(sql), "DELETE FROM denylist WHERE package_name='%s'",
|
ssprintf(sql, sizeof(sql), "DELETE FROM denylist WHERE package_name='%s'",
|
||||||
it->first.data());
|
it->first.data());
|
||||||
db_exec(sql).check_err();
|
db_exec(sql);
|
||||||
it = pkg_to_procs.erase(it);
|
it = pkg_to_procs.erase(it);
|
||||||
} else {
|
} else {
|
||||||
update_app_id(app_id, it->first, false);
|
update_app_id(app_id, it->first, false);
|
||||||
@ -222,11 +222,11 @@ static bool ensure_data() {
|
|||||||
LOGI("denylist: initializing internal data structures\n");
|
LOGI("denylist: initializing internal data structures\n");
|
||||||
|
|
||||||
default_new(pkg_to_procs_);
|
default_new(pkg_to_procs_);
|
||||||
auto res = db_exec("SELECT * FROM denylist", [](db_row &row) -> bool {
|
bool res = db_exec("SELECT * FROM denylist", [](db_row &row) -> bool {
|
||||||
add_hide_set(row["package_name"].data(), row["process"].data());
|
add_hide_set(row["package_name"].data(), row["process"].data());
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
if (res.check_err())
|
if (!res)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
default_new(app_id_to_pkgs_);
|
default_new(app_id_to_pkgs_);
|
||||||
@ -263,7 +263,7 @@ static int add_list(const char *pkg, const char *proc) {
|
|||||||
char sql[4096];
|
char sql[4096];
|
||||||
ssprintf(sql, sizeof(sql),
|
ssprintf(sql, sizeof(sql),
|
||||||
"INSERT INTO denylist (package_name, process) VALUES('%s', '%s')", pkg, proc);
|
"INSERT INTO denylist (package_name, process) VALUES('%s', '%s')", pkg, proc);
|
||||||
return db_exec(sql).check_err() ? DenyResponse::ERROR : DenyResponse::OK;
|
return db_exec(sql) ? DenyResponse::OK : DenyResponse::ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
int add_list(int client) {
|
int add_list(int client) {
|
||||||
@ -307,7 +307,7 @@ static int rm_list(const char *pkg, const char *proc) {
|
|||||||
else
|
else
|
||||||
ssprintf(sql, sizeof(sql),
|
ssprintf(sql, sizeof(sql),
|
||||||
"DELETE FROM denylist WHERE package_name='%s' AND process='%s'", pkg, proc);
|
"DELETE FROM denylist WHERE package_name='%s' AND process='%s'", pkg, proc);
|
||||||
return db_exec(sql).check_err() ? DenyResponse::ERROR : DenyResponse::OK;
|
return db_exec(sql) ? DenyResponse::OK : DenyResponse::ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rm_list(int client) {
|
int rm_list(int client) {
|
||||||
|
@ -126,20 +126,10 @@ using db_row = std::map<std::string_view, std::string_view>;
|
|||||||
using db_row_cb = std::function<bool(db_row&)>;
|
using db_row_cb = std::function<bool(db_row&)>;
|
||||||
struct owned_fd;
|
struct owned_fd;
|
||||||
|
|
||||||
struct db_result {
|
|
||||||
db_result() = default;
|
|
||||||
db_result(const char *s) : err(s) {}
|
|
||||||
db_result(int code);
|
|
||||||
bool check_err();
|
|
||||||
operator bool() { return err.empty(); }
|
|
||||||
private:
|
|
||||||
std::string err;
|
|
||||||
};
|
|
||||||
|
|
||||||
int get_db_settings(db_settings &cfg, int key = -1);
|
int get_db_settings(db_settings &cfg, int key = -1);
|
||||||
int set_db_settings(int key, int value);
|
int set_db_settings(int key, int value);
|
||||||
int get_db_strings(db_strings &str, int key = -1);
|
int get_db_strings(db_strings &str, int key = -1);
|
||||||
void rm_db_strings(int key);
|
void rm_db_strings(int key);
|
||||||
void exec_sql(owned_fd client);
|
void exec_sql(owned_fd client);
|
||||||
db_result db_exec(const char *sql);
|
bool db_exec(const char *sql);
|
||||||
db_result db_exec(const char *sql, const db_row_cb &fn);
|
bool db_exec(const char *sql, const db_row_cb &fn);
|
||||||
|
37
native/src/core/include/sqlite.hpp
Normal file
37
native/src/core/include/sqlite.hpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cxx.h>
|
||||||
|
|
||||||
|
#define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */
|
||||||
|
#define SQLITE_OPEN_CREATE 0x00000004 /* Ok for sqlite3_open_v2() */
|
||||||
|
#define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */
|
||||||
|
|
||||||
|
#define SQLITE_OK 0 /* Successful result */
|
||||||
|
#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */
|
||||||
|
#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */
|
||||||
|
|
||||||
|
struct sqlite3;
|
||||||
|
struct sqlite3_stmt;
|
||||||
|
|
||||||
|
extern int (*sqlite3_open_v2)(const char *filename, sqlite3 **ppDb, int flags, const char *zVfs);
|
||||||
|
extern int (*sqlite3_close)(sqlite3 *db);
|
||||||
|
extern int (*sqlite3_prepare_v2)(sqlite3 *db, const char *zSql, int nByte, sqlite3_stmt **ppStmt, const char **pzTail);
|
||||||
|
extern int (*sqlite3_bind_parameter_count)(sqlite3_stmt*);
|
||||||
|
extern int (*sqlite3_bind_int)(sqlite3_stmt*, int, int);
|
||||||
|
extern int (*sqlite3_bind_text)(sqlite3_stmt*,int,const char*,int,void(*)(void*));
|
||||||
|
extern int (*sqlite3_column_count)(sqlite3_stmt *pStmt);
|
||||||
|
extern const char *(*sqlite3_column_name)(sqlite3_stmt*, int N);
|
||||||
|
extern const char *(*sqlite3_column_text)(sqlite3_stmt*, int iCol);
|
||||||
|
extern int (*sqlite3_step)(sqlite3_stmt*);
|
||||||
|
extern int (*sqlite3_finalize)(sqlite3_stmt *pStmt);
|
||||||
|
extern const char *(*sqlite3_errstr)(int);
|
||||||
|
|
||||||
|
using StringVec = rust::Vec<rust::String>;
|
||||||
|
using StringSlice = rust::Slice<rust::String>;
|
||||||
|
using StrSlice = rust::Slice<rust::Str>;
|
||||||
|
using sqlite_row_callback = void(*)(void*, StringSlice, StringSlice);
|
||||||
|
|
||||||
|
#define fn_run_ret(fn, ...) if (int rc = fn(__VA_ARGS__); rc != SQLITE_OK) return rc
|
||||||
|
|
||||||
|
bool load_sqlite();
|
||||||
|
int sql_exec(sqlite3 *db, rust::Str zSql, StrSlice args, sqlite_row_callback callback, void *v);
|
135
native/src/core/sqlite.cpp
Normal file
135
native/src/core/sqlite.cpp
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
#include <base.hpp>
|
||||||
|
#include <sqlite.hpp>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
// SQLite APIs
|
||||||
|
|
||||||
|
int (*sqlite3_open_v2)(const char *filename, sqlite3 **ppDb, int flags, const char *zVfs);
|
||||||
|
int (*sqlite3_close)(sqlite3 *db);
|
||||||
|
int (*sqlite3_prepare_v2)(sqlite3 *db, const char *zSql, int nByte, sqlite3_stmt **ppStmt, const char **pzTail);
|
||||||
|
int (*sqlite3_bind_parameter_count)(sqlite3_stmt*);
|
||||||
|
int (*sqlite3_bind_int)(sqlite3_stmt*, int, int);
|
||||||
|
int (*sqlite3_bind_text)(sqlite3_stmt*,int,const char*,int,void(*)(void*));
|
||||||
|
int (*sqlite3_column_count)(sqlite3_stmt *pStmt);
|
||||||
|
const char *(*sqlite3_column_name)(sqlite3_stmt*, int N);
|
||||||
|
const char *(*sqlite3_column_text)(sqlite3_stmt*, int iCol);
|
||||||
|
int (*sqlite3_step)(sqlite3_stmt*);
|
||||||
|
int (*sqlite3_finalize)(sqlite3_stmt *pStmt);
|
||||||
|
const char *(*sqlite3_errstr)(int);
|
||||||
|
|
||||||
|
// Internal Android linker APIs
|
||||||
|
|
||||||
|
static void (*android_get_LD_LIBRARY_PATH)(char *buffer, size_t buffer_size);
|
||||||
|
static void (*android_update_LD_LIBRARY_PATH)(const char *ld_library_path);
|
||||||
|
|
||||||
|
#define DLERR(ptr) if (!(ptr)) { \
|
||||||
|
LOGE("db: %s\n", dlerror()); \
|
||||||
|
return false; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DLOAD(handle, arg) {\
|
||||||
|
auto f = dlsym(handle, #arg); \
|
||||||
|
DLERR(f) \
|
||||||
|
*(void **) &(arg) = f; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __LP64__
|
||||||
|
constexpr char apex_path[] = "/apex/com.android.runtime/lib64:/apex/com.android.art/lib64:/apex/com.android.i18n/lib64:";
|
||||||
|
#else
|
||||||
|
constexpr char apex_path[] = "/apex/com.android.runtime/lib:/apex/com.android.art/lib:/apex/com.android.i18n/lib:";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool load_sqlite() {
|
||||||
|
static int dl_init = 0;
|
||||||
|
if (dl_init)
|
||||||
|
return dl_init > 0;
|
||||||
|
dl_init = -1;
|
||||||
|
|
||||||
|
auto sqlite = dlopen("libsqlite.so", RTLD_LAZY);
|
||||||
|
if (!sqlite) {
|
||||||
|
// Should only happen on Android 10+
|
||||||
|
auto dl = dlopen("libdl_android.so", RTLD_LAZY);
|
||||||
|
DLERR(dl);
|
||||||
|
|
||||||
|
DLOAD(dl, android_get_LD_LIBRARY_PATH);
|
||||||
|
DLOAD(dl, android_update_LD_LIBRARY_PATH);
|
||||||
|
|
||||||
|
// Inject APEX into LD_LIBRARY_PATH
|
||||||
|
char ld_path[4096];
|
||||||
|
memcpy(ld_path, apex_path, sizeof(apex_path));
|
||||||
|
constexpr int len = sizeof(apex_path) - 1;
|
||||||
|
android_get_LD_LIBRARY_PATH(ld_path + len, sizeof(ld_path) - len);
|
||||||
|
android_update_LD_LIBRARY_PATH(ld_path);
|
||||||
|
sqlite = dlopen("libsqlite.so", RTLD_LAZY);
|
||||||
|
|
||||||
|
// Revert LD_LIBRARY_PATH just in case
|
||||||
|
android_update_LD_LIBRARY_PATH(ld_path + len);
|
||||||
|
}
|
||||||
|
DLERR(sqlite);
|
||||||
|
|
||||||
|
DLOAD(sqlite, sqlite3_open_v2);
|
||||||
|
DLOAD(sqlite, sqlite3_close);
|
||||||
|
DLOAD(sqlite, sqlite3_prepare_v2);
|
||||||
|
DLOAD(sqlite, sqlite3_bind_parameter_count);
|
||||||
|
DLOAD(sqlite, sqlite3_bind_int);
|
||||||
|
DLOAD(sqlite, sqlite3_bind_text);
|
||||||
|
DLOAD(sqlite, sqlite3_step);
|
||||||
|
DLOAD(sqlite, sqlite3_column_count);
|
||||||
|
DLOAD(sqlite, sqlite3_column_name);
|
||||||
|
DLOAD(sqlite, sqlite3_column_text);
|
||||||
|
DLOAD(sqlite, sqlite3_finalize);
|
||||||
|
DLOAD(sqlite, sqlite3_errstr);
|
||||||
|
|
||||||
|
dl_init = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sql_exec(sqlite3 *db, rust::Str zSql, StrSlice args, sqlite_row_callback callback, void *v) {
|
||||||
|
const char *sql = zSql.begin();
|
||||||
|
auto arg_it = args.begin();
|
||||||
|
unique_ptr<sqlite3_stmt, decltype(sqlite3_finalize)> stmt(nullptr, sqlite3_finalize);
|
||||||
|
|
||||||
|
while (sql != zSql.end()) {
|
||||||
|
// Step 1: prepare statement
|
||||||
|
{
|
||||||
|
sqlite3_stmt *st = nullptr;
|
||||||
|
fn_run_ret(sqlite3_prepare_v2, db, sql, zSql.end() - sql, &st, &sql);
|
||||||
|
if (st == nullptr) continue;
|
||||||
|
stmt.reset(st);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: bind arguments
|
||||||
|
if (int count = sqlite3_bind_parameter_count(stmt.get())) {
|
||||||
|
for (int i = 1; i <= count && arg_it != args.end(); ++i, ++arg_it) {
|
||||||
|
fn_run_ret(sqlite3_bind_text, stmt.get(), i, arg_it->data(), arg_it->size(), nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: execute
|
||||||
|
bool first = true;
|
||||||
|
StringVec columns;
|
||||||
|
for (;;) {
|
||||||
|
int rc = sqlite3_step(stmt.get());
|
||||||
|
if (rc == SQLITE_DONE) break;
|
||||||
|
if (rc != SQLITE_ROW) return rc;
|
||||||
|
if (callback == nullptr) continue;
|
||||||
|
if (first) {
|
||||||
|
int count = sqlite3_column_count(stmt.get());
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
columns.emplace_back(sqlite3_column_name(stmt.get(), i));
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
StringVec data;
|
||||||
|
for (int i = 0; i < columns.size(); ++i) {
|
||||||
|
data.emplace_back(sqlite3_column_text(stmt.get(), i));
|
||||||
|
}
|
||||||
|
callback(v, StringSlice(columns), StringSlice(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
@ -67,7 +67,7 @@ void su_info::check_db() {
|
|||||||
ssprintf(query, sizeof(query),
|
ssprintf(query, sizeof(query),
|
||||||
"SELECT policy, logging, notification FROM policies "
|
"SELECT policy, logging, notification FROM policies "
|
||||||
"WHERE uid=%d AND (until=0 OR until>%li)", eval_uid, time(nullptr));
|
"WHERE uid=%d AND (until=0 OR until>%li)", eval_uid, time(nullptr));
|
||||||
auto res = db_exec(query, [&](db_row &row) -> bool {
|
bool res = db_exec(query, [&](db_row &row) -> bool {
|
||||||
access.policy = (policy_t) parse_int(row["policy"]);
|
access.policy = (policy_t) parse_int(row["policy"]);
|
||||||
access.log = parse_int(row["logging"]);
|
access.log = parse_int(row["logging"]);
|
||||||
access.notify = parse_int(row["notification"]);
|
access.notify = parse_int(row["notification"]);
|
||||||
@ -75,7 +75,7 @@ void su_info::check_db() {
|
|||||||
access.policy, access.log, access.notify);
|
access.policy, access.log, access.notify);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
if (res.check_err())
|
if (!res)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,11 +128,11 @@ bool uid_granted_root(int uid) {
|
|||||||
ssprintf(query, sizeof(query),
|
ssprintf(query, sizeof(query),
|
||||||
"SELECT policy FROM policies WHERE uid=%d AND (until=0 OR until>%li)",
|
"SELECT policy FROM policies WHERE uid=%d AND (until=0 OR until>%li)",
|
||||||
uid, time(nullptr));
|
uid, time(nullptr));
|
||||||
auto res = db_exec(query, [&](db_row &row) -> bool {
|
bool res = db_exec(query, [&](db_row &row) -> bool {
|
||||||
granted = parse_int(row["policy"]) == ALLOW;
|
granted = parse_int(row["policy"]) == ALLOW;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
if (res.check_err())
|
if (!res)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return granted;
|
return granted;
|
||||||
@ -142,7 +142,7 @@ void prune_su_access() {
|
|||||||
cached.reset();
|
cached.reset();
|
||||||
vector<bool> app_no_list = get_app_no_list();
|
vector<bool> app_no_list = get_app_no_list();
|
||||||
vector<int> rm_uids;
|
vector<int> rm_uids;
|
||||||
auto res = db_exec("SELECT uid FROM policies", [&](db_row &row) -> bool {
|
bool res = db_exec("SELECT uid FROM policies", [&](db_row &row) -> bool {
|
||||||
int uid = parse_int(row["uid"]);
|
int uid = parse_int(row["uid"]);
|
||||||
int app_id = to_app_id(uid);
|
int app_id = to_app_id(uid);
|
||||||
if (app_id >= AID_APP_START && app_id <= AID_APP_END) {
|
if (app_id >= AID_APP_START && app_id <= AID_APP_END) {
|
||||||
@ -154,13 +154,13 @@ void prune_su_access() {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
if (res.check_err())
|
if (!res)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (int uid : rm_uids) {
|
for (int uid : rm_uids) {
|
||||||
char query[256];
|
char query[256];
|
||||||
ssprintf(query, sizeof(query), "DELETE FROM policies WHERE uid == %d", uid);
|
ssprintf(query, sizeof(query), "DELETE FROM policies WHERE uid == %d", uid);
|
||||||
db_exec(query).check_err();
|
db_exec(query);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user