mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-11-27 20:15:29 +00:00
Handle magisk.db completely natively
Prevent database corruption due to different Android application sqlite default settings
This commit is contained in:
parent
2a65c3dc8f
commit
dbb8b8a439
@ -52,6 +52,7 @@ public class Const {
|
|||||||
public static final int SEPOL_REFACTOR = 1640;
|
public static final int SEPOL_REFACTOR = 1640;
|
||||||
public static final int FIX_ENV = 1650;
|
public static final int FIX_ENV = 1650;
|
||||||
public static final int DBVER_SIX = 17000;
|
public static final int DBVER_SIX = 17000;
|
||||||
|
public static final int CMDLINE_DB = 17305;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ID {
|
public static class ID {
|
||||||
|
@ -252,7 +252,7 @@ public class SuRequestActivity extends BaseActivity {
|
|||||||
policy.policy = action;
|
policy.policy = action;
|
||||||
if (time >= 0) {
|
if (time >= 0) {
|
||||||
policy.until = (time == 0) ? 0 : (System.currentTimeMillis() / 1000 + time * 60);
|
policy.until = (time == 0) ? 0 : (System.currentTimeMillis() / 1000 + time * 60);
|
||||||
mm.mDB.addPolicy(policy);
|
mm.mDB.updatePolicy(policy);
|
||||||
}
|
}
|
||||||
handleAction();
|
handleAction();
|
||||||
}
|
}
|
||||||
|
@ -1,60 +1,66 @@
|
|||||||
package com.topjohnwu.magisk.database;
|
package com.topjohnwu.magisk.database;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.magisk.Const;
|
||||||
|
import com.topjohnwu.magisk.Data;
|
||||||
import com.topjohnwu.magisk.container.Policy;
|
import com.topjohnwu.magisk.container.Policy;
|
||||||
import com.topjohnwu.magisk.container.SuLogEntry;
|
import com.topjohnwu.magisk.container.SuLogEntry;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
import com.topjohnwu.superuser.Shell;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
public abstract class MagiskDB {
|
public class MagiskDB {
|
||||||
|
|
||||||
public static final int DATABASE_VER = 6;
|
static final String POLICY_TABLE = "policies";
|
||||||
public static final int OLD_DATABASE_VER = 5;
|
static final String LOG_TABLE = "logs";
|
||||||
public static final String POLICY_TABLE = "policies";
|
static final String SETTINGS_TABLE = "settings";
|
||||||
public static final String LOG_TABLE = "logs";
|
static final String STRINGS_TABLE = "strings";
|
||||||
public static final String SETTINGS_TABLE = "settings";
|
static final File LEGACY_MANAGER_DB =
|
||||||
public static final String STRINGS_TABLE = "strings";
|
|
||||||
public static final File LEGACY_MANAGER_DB =
|
|
||||||
new File(Utils.fmt("/sbin/.core/db-%d/magisk.db", Const.USER_ID));
|
new File(Utils.fmt("/sbin/.core/db-%d/magisk.db", Const.USER_ID));
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static MagiskDB getInstance() {
|
public static MagiskDB getInstance() {
|
||||||
|
if (LEGACY_MANAGER_DB.canWrite()) {
|
||||||
return MagiskDBLegacy.newInstance();
|
return MagiskDBLegacy.newInstance();
|
||||||
|
} else if (Shell.rootAccess()) {
|
||||||
|
return Data.magiskVersionCode >= Const.MAGISK_VER.CMDLINE_DB ?
|
||||||
|
new MagiskDBCmdline() : MagiskDBLegacy.newInstance();
|
||||||
|
} else {
|
||||||
|
return new MagiskDB();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void clearOutdated();
|
public void clearOutdated() {}
|
||||||
|
|
||||||
public void deletePolicy(Policy policy) {
|
public void deletePolicy(Policy policy) {
|
||||||
deletePolicy(policy.uid);
|
deletePolicy(policy.uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void deletePolicy(String pkg);
|
public void deletePolicy(String pkg) {}
|
||||||
|
|
||||||
public abstract void deletePolicy(int uid);
|
public void deletePolicy(int uid) {}
|
||||||
|
|
||||||
public abstract Policy getPolicy(int uid);
|
public Policy getPolicy(int uid) { return null; }
|
||||||
|
|
||||||
public abstract void addPolicy(Policy policy);
|
public void updatePolicy(Policy policy) {}
|
||||||
|
|
||||||
public abstract void updatePolicy(Policy policy);
|
public List<Policy> getPolicyList() { return Collections.emptyList(); }
|
||||||
|
|
||||||
public abstract List<Policy> getPolicyList();
|
public List<List<SuLogEntry>> getLogs() { return Collections.emptyList(); }
|
||||||
|
|
||||||
public abstract List<List<SuLogEntry>> getLogs();
|
public void addLog(SuLogEntry log) {}
|
||||||
|
|
||||||
public abstract void addLog(SuLogEntry log);
|
public void clearLogs() {}
|
||||||
|
|
||||||
public abstract void clearLogs();
|
public void setSettings(String key, int value) {}
|
||||||
|
|
||||||
public abstract void setSettings(String key, int value);
|
public int getSettings(String key, int defaultValue) { return defaultValue; }
|
||||||
|
|
||||||
public abstract int getSettings(String key, int defaultValue);
|
public void setStrings(String key, String value) {}
|
||||||
|
|
||||||
public abstract void setStrings(String key, String value);
|
public String getStrings(String key, String defaultValue) { return defaultValue; }
|
||||||
|
|
||||||
public abstract String getStrings(String key, String defaultValue);
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,185 @@
|
|||||||
|
package com.topjohnwu.magisk.database;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.Const;
|
||||||
|
import com.topjohnwu.magisk.Data;
|
||||||
|
import com.topjohnwu.magisk.container.Policy;
|
||||||
|
import com.topjohnwu.magisk.container.SuLogEntry;
|
||||||
|
import com.topjohnwu.magisk.utils.LocaleManager;
|
||||||
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
import com.topjohnwu.superuser.Shell;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class MagiskDBCmdline extends MagiskDB {
|
||||||
|
|
||||||
|
private PackageManager pm;
|
||||||
|
|
||||||
|
public MagiskDBCmdline() {
|
||||||
|
pm = Data.MM().getPackageManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> rawSQL(String fmt, Object... args) {
|
||||||
|
return Shell.su("magisk --sqlite '" + Utils.fmt(fmt, args) + "'").exec().getOut();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ContentValues> SQL(String fmt, Object... args) {
|
||||||
|
List<ContentValues> list = new ArrayList<>();
|
||||||
|
for (String raw : rawSQL(fmt, args)) {
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
String[] cols = raw.split("\\|");
|
||||||
|
for (String col : cols) {
|
||||||
|
String[] pair = col.split("=", 2);
|
||||||
|
values.put(pair[0], pair[1]);
|
||||||
|
}
|
||||||
|
list.add(values);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String toSQL(ContentValues values) {
|
||||||
|
StringBuilder keys = new StringBuilder(), vals = new StringBuilder();
|
||||||
|
keys.append('(');
|
||||||
|
vals.append("VALUES(");
|
||||||
|
boolean first = true;
|
||||||
|
for (Map.Entry<String, Object> entry : values.valueSet()) {
|
||||||
|
if (!first) {
|
||||||
|
keys.append(',');
|
||||||
|
vals.append(',');
|
||||||
|
} else {
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
keys.append(entry.getKey());
|
||||||
|
vals.append('"');
|
||||||
|
vals.append(entry.getValue());
|
||||||
|
vals.append('"');
|
||||||
|
}
|
||||||
|
keys.append(')');
|
||||||
|
vals.append(')');
|
||||||
|
keys.append(vals);
|
||||||
|
return keys.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearOutdated() {
|
||||||
|
rawSQL(
|
||||||
|
"DELETE FROM %s WHERE until > 0 AND until < %d;" +
|
||||||
|
"DELETE FROM %s WHERE time < %d",
|
||||||
|
POLICY_TABLE, System.currentTimeMillis() / 1000,
|
||||||
|
LOG_TABLE, System.currentTimeMillis() - Data.suLogTimeout * 86400000
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deletePolicy(String pkg) {
|
||||||
|
rawSQL("DELETE FROM %s WHERE package_name=\"%s\"", POLICY_TABLE, pkg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deletePolicy(int uid) {
|
||||||
|
rawSQL("DELETE FROM %s WHERE uid=%d", POLICY_TABLE, uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Policy getPolicy(int uid) {
|
||||||
|
List<ContentValues> res =
|
||||||
|
SQL("SELECT * FROM %s WHERE uid=%d", POLICY_TABLE, uid);
|
||||||
|
if (!res.isEmpty()) {
|
||||||
|
try {
|
||||||
|
return new Policy(res.get(0), pm);
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
deletePolicy(uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updatePolicy(Policy policy) {
|
||||||
|
rawSQL("REPLACE INTO %s %s", POLICY_TABLE, toSQL(policy.getContentValues()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Policy> getPolicyList() {
|
||||||
|
List<Policy> list = new ArrayList<>();
|
||||||
|
for (ContentValues values : SQL("SELECT * FROM %s WHERE uid/100000=%d", POLICY_TABLE, Const.USER_ID)) {
|
||||||
|
try {
|
||||||
|
list.add(new Policy(values, pm));
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
deletePolicy(values.getAsInteger("uid"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<List<SuLogEntry>> getLogs() {
|
||||||
|
List<List<SuLogEntry>> ret = new ArrayList<>();
|
||||||
|
List<SuLogEntry> list = null;
|
||||||
|
String dateString = null, newString;
|
||||||
|
for (ContentValues values : SQL("SELECT * FROM %s ORDER BY time DESC", LOG_TABLE)) {
|
||||||
|
Date date = new Date(values.getAsLong("time"));
|
||||||
|
newString = DateFormat.getDateInstance(DateFormat.MEDIUM, LocaleManager.locale).format(date);
|
||||||
|
if (!TextUtils.equals(dateString, newString)) {
|
||||||
|
dateString = newString;
|
||||||
|
list = new ArrayList<>();
|
||||||
|
ret.add(list);
|
||||||
|
}
|
||||||
|
list.add(new SuLogEntry(values));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addLog(SuLogEntry log) {
|
||||||
|
rawSQL("INSERT INTO %s %s", LOG_TABLE, toSQL(log.getContentValues()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearLogs() {
|
||||||
|
rawSQL("DELETE FROM %s", LOG_TABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSettings(String key, int value) {
|
||||||
|
ContentValues data = new ContentValues();
|
||||||
|
data.put("key", key);
|
||||||
|
data.put("value", value);
|
||||||
|
rawSQL("REPLACE INTO %s %s", SETTINGS_TABLE, toSQL(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSettings(String key, int defaultValue) {
|
||||||
|
List<ContentValues> res = SQL("SELECT value FROM %s WHERE key=\"%s\"", SETTINGS_TABLE, key);
|
||||||
|
if (res.isEmpty())
|
||||||
|
return defaultValue;
|
||||||
|
return res.get(0).getAsInteger("value");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setStrings(String key, String value) {
|
||||||
|
if (value == null) {
|
||||||
|
rawSQL("DELETE FROM %s WHERE key=\"%s\"", STRINGS_TABLE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ContentValues data = new ContentValues();
|
||||||
|
data.put("key", key);
|
||||||
|
data.put("value", value);
|
||||||
|
rawSQL("REPLACE INTO %s %s", STRINGS_TABLE, toSQL(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getStrings(String key, String defaultValue) {
|
||||||
|
List<ContentValues> res = SQL("SELECT value FROM %s WHERE key=\"%s\"", STRINGS_TABLE, key);
|
||||||
|
if (res.isEmpty())
|
||||||
|
return defaultValue;
|
||||||
|
return res.get(0).getAsString("value");
|
||||||
|
}
|
||||||
|
}
|
@ -30,6 +30,9 @@ import java.util.List;
|
|||||||
|
|
||||||
public class MagiskDBLegacy extends MagiskDB {
|
public class MagiskDBLegacy extends MagiskDB {
|
||||||
|
|
||||||
|
private static final int DATABASE_VER = 6;
|
||||||
|
private static final int OLD_DATABASE_VER = 5;
|
||||||
|
|
||||||
private PackageManager pm;
|
private PackageManager pm;
|
||||||
private SQLiteDatabase db;
|
private SQLiteDatabase db;
|
||||||
|
|
||||||
@ -193,14 +196,9 @@ public class MagiskDBLegacy extends MagiskDB {
|
|||||||
return policy;
|
return policy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addPolicy(Policy policy) {
|
|
||||||
db.replace(POLICY_TABLE, null, policy.getContentValues());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updatePolicy(Policy policy) {
|
public void updatePolicy(Policy policy) {
|
||||||
db.update(POLICY_TABLE, policy.getContentValues(), Utils.fmt("uid=%d", policy.uid), null);
|
db.replace(POLICY_TABLE, null, policy.getContentValues());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -942,6 +942,7 @@ core_only:
|
|||||||
} else {
|
} else {
|
||||||
// Check whether we have a valid manager installed
|
// Check whether we have a valid manager installed
|
||||||
sqlite3 *db = get_magiskdb();
|
sqlite3 *db = get_magiskdb();
|
||||||
|
if (db) {
|
||||||
struct db_strings str;
|
struct db_strings str;
|
||||||
memset(&str, 0, sizeof(str));
|
memset(&str, 0, sizeof(str));
|
||||||
get_db_strings(db, SU_MANAGER, &str);
|
get_db_strings(db, SU_MANAGER, &str);
|
||||||
@ -950,6 +951,8 @@ core_only:
|
|||||||
exec_command_sync("/sbin/magiskinit", "-x", "manager", "/data/magisk.apk", NULL);
|
exec_command_sync("/sbin/magiskinit", "-x", "manager", "/data/magisk.apk", NULL);
|
||||||
install_apk("/data/magisk.apk");
|
install_apk("/data/magisk.apk");
|
||||||
}
|
}
|
||||||
|
sqlite3_close_v2(db);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// All boot stage done, cleanup
|
// All boot stage done, cleanup
|
||||||
|
@ -8,20 +8,67 @@
|
|||||||
#include "magisk.h"
|
#include "magisk.h"
|
||||||
#include "db.h"
|
#include "db.h"
|
||||||
|
|
||||||
static int policy_cb(void *v, int col_num, char **data, char **col_name) {
|
static int ver_cb(void *v, int col_num, char **data, char **col_name) {
|
||||||
struct su_access *su = v;
|
*((int *) v) = atoi(data[0]);
|
||||||
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;
|
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) {
|
static int settings_cb(void *v, int col_num, char **data, char **col_name) {
|
||||||
struct db_settings *dbs = v;
|
struct db_settings *dbs = v;
|
||||||
int key = -1, value;
|
int key = -1, value;
|
||||||
@ -42,6 +89,24 @@ static int settings_cb(void *v, int col_num, char **data, char **col_name) {
|
|||||||
return 0;
|
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) {
|
static int strings_cb(void *v, int col_num, char **data, char **col_name) {
|
||||||
struct db_strings *dbs = v;
|
struct db_strings *dbs = v;
|
||||||
int key = -1;
|
int key = -1;
|
||||||
@ -63,38 +128,6 @@ static int strings_cb(void *v, int col_num, char **data, char **col_name) {
|
|||||||
return 0;
|
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) {
|
int get_db_strings(sqlite3 *db, int key, struct db_strings *str) {
|
||||||
if (db == NULL)
|
if (db == NULL)
|
||||||
return 1;
|
return 1;
|
||||||
@ -113,6 +146,20 @@ int get_db_strings(sqlite3 *db, int key, struct db_strings *str) {
|
|||||||
return 0;
|
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) {
|
int get_uid_policy(sqlite3 *db, int uid, struct su_access *su) {
|
||||||
if (db == NULL)
|
if (db == NULL)
|
||||||
return 1;
|
return 1;
|
||||||
@ -127,7 +174,7 @@ int get_uid_policy(sqlite3 *db, int uid, struct su_access *su) {
|
|||||||
return 0;
|
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) {
|
if (st == NULL) {
|
||||||
struct stat stat;
|
struct stat stat;
|
||||||
st = &stat;
|
st = &stat;
|
||||||
@ -135,19 +182,44 @@ int validate_manager(char *pkg, int userid, struct stat *st) {
|
|||||||
// Prefer DE storage
|
// Prefer DE storage
|
||||||
const char *base = access("/data/user_de", F_OK) == 0 ? "/data/user_de" : "/data/user";
|
const char *base = access("/data/user_de", F_OK) == 0 ? "/data/user_de" : "/data/user";
|
||||||
char app_path[128];
|
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)) {
|
if (stat(app_path, st)) {
|
||||||
// Check the official package name
|
// Check the official package name
|
||||||
sprintf(app_path, "%s/%d/"JAVA_PACKAGE_NAME, base, userid);
|
sprintf(app_path, "%s/%d/"JAVA_PACKAGE_NAME, base, userid);
|
||||||
if (stat(app_path, st)) {
|
if (stat(app_path, st)) {
|
||||||
LOGE("su: cannot find manager");
|
LOGE("su: cannot find manager");
|
||||||
memset(st, 0, sizeof(*st));
|
memset(st, 0, sizeof(*st));
|
||||||
pkg[0] = '\0';
|
alt_pkg[0] = '\0';
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
// Switch to official package if exists
|
// Switch to official package if exists
|
||||||
strcpy(pkg, JAVA_PACKAGE_NAME);
|
strcpy(alt_pkg, JAVA_PACKAGE_NAME);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
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 "magisk.h"
|
||||||
#include "daemon.h"
|
#include "daemon.h"
|
||||||
#include "selinux.h"
|
#include "selinux.h"
|
||||||
|
#include "db.h"
|
||||||
#include "flags.h"
|
#include "flags.h"
|
||||||
|
|
||||||
static int create_links(const char *bin, const char *path) {
|
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"
|
" --unlock-blocks set BLKROSET flag to OFF for all block devices\n"
|
||||||
" --restorecon fix selinux context on Magisk files and folders\n"
|
" --restorecon fix selinux context on Magisk files and folders\n"
|
||||||
" --clone-attr SRC DEST clone permission, owner, and selinux context\n"
|
" --clone-attr SRC DEST clone permission, owner, and selinux context\n"
|
||||||
|
" --sqlite SQL exec SQL to Magisk database\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Supported init triggers:\n"
|
"Supported init triggers:\n"
|
||||||
" startup, post-fs-data, service, boot-complete\n"
|
" startup, post-fs-data, service, boot-complete\n"
|
||||||
@ -110,6 +112,8 @@ int magisk_main(int argc, char *argv[]) {
|
|||||||
int fd = connect_daemon();
|
int fd = connect_daemon();
|
||||||
write_int(fd, BOOT_COMPLETE);
|
write_int(fd, BOOT_COMPLETE);
|
||||||
return read_int(fd);
|
return read_int(fd);
|
||||||
|
} else if (strcmp(argv[1], "--sqlite") == 0) {
|
||||||
|
return exec_sql(argv[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
usage();
|
usage();
|
||||||
|
@ -119,6 +119,7 @@ sqlite3 *get_magiskdb();
|
|||||||
int get_db_settings(sqlite3 *db, int key, struct db_settings *dbs);
|
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_db_strings(sqlite3 *db, int key, struct db_strings *str);
|
||||||
int get_uid_policy(sqlite3 *db, int uid, struct su_access *su);
|
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
|
#endif //DB_H
|
||||||
|
@ -75,7 +75,7 @@ static void database_check(struct su_info *info) {
|
|||||||
|
|
||||||
if (uid > 0)
|
if (uid > 0)
|
||||||
get_uid_policy(db, uid, &info->access);
|
get_uid_policy(db, uid, &info->access);
|
||||||
sqlite3_close(db);
|
sqlite3_close_v2(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to check our manager
|
// We need to check our manager
|
||||||
|
Loading…
Reference in New Issue
Block a user