Update denylist config implementation

This commit is contained in:
topjohnwu 2021-09-16 05:27:34 -07:00
parent c0be5383de
commit 706a492218
14 changed files with 79 additions and 78 deletions

View File

@ -6,9 +6,9 @@ import android.util.Xml
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.edit import androidx.core.content.edit
import com.topjohnwu.magisk.BuildConfig import com.topjohnwu.magisk.BuildConfig
import com.topjohnwu.magisk.core.utils.BiometricHelper
import com.topjohnwu.magisk.core.utils.refreshLocale import com.topjohnwu.magisk.core.utils.refreshLocale
import com.topjohnwu.magisk.data.preference.PreferenceModel import com.topjohnwu.magisk.data.preference.PreferenceModel
import com.topjohnwu.magisk.data.repository.DBBoolSettingsNoWrite
import com.topjohnwu.magisk.data.repository.DBConfig import com.topjohnwu.magisk.data.repository.DBConfig
import com.topjohnwu.magisk.di.ServiceLocator import com.topjohnwu.magisk.di.ServiceLocator
import com.topjohnwu.magisk.ui.theme.Theme import com.topjohnwu.magisk.ui.theme.Theme
@ -38,6 +38,7 @@ object Config : PreferenceModel, DBConfig {
const val SU_MNT_NS = "mnt_ns" const val SU_MNT_NS = "mnt_ns"
const val SU_BIOMETRIC = "su_biometric" const val SU_BIOMETRIC = "su_biometric"
const val ZYGISK = "zygisk" const val ZYGISK = "zygisk"
const val DENYLIST = "denylist"
const val SU_MANAGER = "requester" const val SU_MANAGER = "requester"
const val KEYSTORE = "keystore" const val KEYSTORE = "keystore"
@ -145,6 +146,7 @@ object Config : PreferenceModel, DBConfig {
var suMultiuserMode by dbSettings(Key.SU_MULTIUSER_MODE, Value.MULTIUSER_MODE_OWNER_ONLY) var suMultiuserMode by dbSettings(Key.SU_MULTIUSER_MODE, Value.MULTIUSER_MODE_OWNER_ONLY)
var suBiometric by dbSettings(Key.SU_BIOMETRIC, false) var suBiometric by dbSettings(Key.SU_BIOMETRIC, false)
var zygisk by dbSettings(Key.ZYGISK, false) var zygisk by dbSettings(Key.ZYGISK, false)
var denyList by DBBoolSettingsNoWrite(Key.DENYLIST, false)
var suManager by dbStrings(Key.SU_MANAGER, "", true) var suManager by dbStrings(Key.SU_MANAGER, "", true)
var keyStoreRaw by dbStrings(Key.KEYSTORE, "", true) var keyStoreRaw by dbStrings(Key.KEYSTORE, "", true)
@ -169,12 +171,6 @@ object Config : PreferenceModel, DBConfig {
else if (it.toInt() > Value.CANARY_CHANNEL) else if (it.toInt() > Value.CANARY_CHANNEL)
putString(Key.UPDATE_CHANNEL, Value.CANARY_CHANNEL.toString()) putString(Key.UPDATE_CHANNEL, Value.CANARY_CHANNEL.toString())
} }
// Write database configs
putString(Key.ROOT_ACCESS, rootMode.toString())
putString(Key.SU_MNT_NS, suMntNamespaceMode.toString())
putString(Key.SU_MULTIUSER_MODE, suMultiuserMode.toString())
putBoolean(Key.SU_BIOMETRIC, BiometricHelper.isEnabled)
} }
} }

View File

@ -64,9 +64,5 @@ object Info {
} }
val isUnsupported = code > 0 && code < Const.Version.MIN_VERCODE val isUnsupported = code > 0 && code < Const.Version.MIN_VERCODE
val isActive = magiskVersionCode >= 0 val isActive = magiskVersionCode >= 0
var denyListEnforced = if (Const.Version.isCanary(code))
Shell.su("magisk --denylist status").exec().isSuccess
else
false
} }
} }

View File

@ -35,14 +35,12 @@ class DBSettingsValue(
private val default: Int private val default: Int
) : ReadWriteProperty<DBConfig, Int> { ) : ReadWriteProperty<DBConfig, Int> {
private var value: Int? = null var value: Int? = null
@Synchronized @Synchronized
override fun getValue(thisRef: DBConfig, property: KProperty<*>): Int { override fun getValue(thisRef: DBConfig, property: KProperty<*>): Int {
if (value == null) if (value == null)
value = runBlocking { value = runBlocking { thisRef.settingsDB.fetch(name, default) }
thisRef.settingsDB.fetch(name, default)
}
return value as Int return value as Int
} }
@ -56,7 +54,7 @@ class DBSettingsValue(
} }
} }
class DBBoolSettings( open class DBBoolSettings(
name: String, name: String,
default: Boolean default: Boolean
) : ReadWriteProperty<DBConfig, Boolean> { ) : ReadWriteProperty<DBConfig, Boolean> {
@ -70,6 +68,17 @@ class DBBoolSettings(
base.setValue(thisRef, property, if (value) 1 else 0) base.setValue(thisRef, property, if (value) 1 else 0)
} }
class DBBoolSettingsNoWrite(
name: String,
default: Boolean
) : DBBoolSettings(name, default) {
override fun setValue(thisRef: DBConfig, property: KProperty<*>, value: Boolean) {
synchronized(base) {
base.value = if (value) 1 else 0
}
}
}
class DBStringsValue( class DBStringsValue(
private val name: String, private val name: String,
private val default: String, private val default: String,

View File

@ -251,11 +251,11 @@ object DenyList : BaseSettingsItem.Toggle() {
if (isEnabled) R.string.settings_denylist_summary.asText() if (isEnabled) R.string.settings_denylist_summary.asText()
else R.string.settings_denylist_error.asText(R.string.zygisk.asText()) else R.string.settings_denylist_error.asText(R.string.zygisk.asText())
override var value = Info.env.denyListEnforced override var value = Config.denyList
set(value) = setV(value, field, { field = it }) { set(value) = setV(value, field, { field = it }) {
val cmd = if (it) "enable" else "disable" val cmd = if (it) "enable" else "disable"
Shell.su("magisk --denylist $cmd").submit { result -> Shell.su("magisk --denylist $cmd").submit { result ->
if (result.isSuccess) Info.env.denyListEnforced = it if (result.isSuccess) Config.denyList = it
else field = !it else field = !it
} }
DenyListConfig.isEnabled = it DenyListConfig.isEnabled = it

View File

@ -304,10 +304,8 @@ void post_fs_data(int client) {
exec_common_scripts("post-fs-data"); exec_common_scripts("post-fs-data");
db_settings dbs; db_settings dbs;
get_db_settings(dbs, ZYGISK_CONFIG); get_db_settings(dbs, ZYGISK_CONFIG);
if (dbs[ZYGISK_CONFIG]) { zygisk_enabled = dbs[ZYGISK_CONFIG];
zygisk_enabled = true; initialize_denylist();
check_enforce_denylist();
}
handle_modules(); handle_modules();
} }

View File

@ -6,7 +6,15 @@
extern bool RECOVERY_MODE; extern bool RECOVERY_MODE;
extern int DAEMON_STATE; extern int DAEMON_STATE;
extern bool zygisk_enabled;
// Daemon state
enum : int {
STATE_NONE,
STATE_POST_FS_DATA,
STATE_POST_FS_DATA_DONE,
STATE_LATE_START_DONE,
STATE_BOOT_COMPLETE
};
void unlock_blocks(); void unlock_blocks();
void reboot(); void reboot();

View File

@ -4,6 +4,7 @@
#include <utils.hpp> #include <utils.hpp>
#include <magisk.hpp> #include <magisk.hpp>
#include <daemon.hpp>
#include <selinux.hpp> #include <selinux.hpp>
#include <resetprop.hpp> #include <resetprop.hpp>

View File

@ -35,11 +35,10 @@ void denylist_handler(int client, ucred *cred) {
int res = DAEMON_ERROR; int res = DAEMON_ERROR;
switch (req) { switch (req) {
case DISABLE_DENY:
case ADD_LIST: case ADD_LIST:
case RM_LIST: case RM_LIST:
case LS_LIST: case LS_LIST:
if (!deny_enforced()) { if (!denylist_enabled) {
write_int(client, DENY_NOT_ENFORCED); write_int(client, DENY_NOT_ENFORCED);
close(client); close(client);
return; return;
@ -48,7 +47,7 @@ void denylist_handler(int client, ucred *cred) {
switch (req) { switch (req) {
case ENFORCE_DENY: case ENFORCE_DENY:
res = enable_hide(); res = enable_deny();
break; break;
case DISABLE_DENY: case DISABLE_DENY:
res = disable_deny(); res = disable_deny();
@ -63,7 +62,7 @@ void denylist_handler(int client, ucred *cred) {
ls_list(client); ls_list(client);
return; return;
case DENY_STATUS: case DENY_STATUS:
res = deny_enforced() ? DENY_IS_ENFORCED : DENY_NOT_ENFORCED; res = (zygisk_enabled && denylist_enabled) ? DENY_IS_ENFORCED : DENY_NOT_ENFORCED;
break; break;
} }

View File

@ -4,26 +4,28 @@
#include <string_view> #include <string_view>
#include <functional> #include <functional>
#include <map> #include <map>
#include <atomic>
#include <daemon.hpp> #include <daemon.hpp>
#define ISOLATED_MAGIC "isolated" #define ISOLATED_MAGIC "isolated"
// CLI entries // CLI entries
int enable_hide(); int enable_deny();
int disable_deny(); int disable_deny();
int add_list(int client); int add_list(int client);
int rm_list(int client); int rm_list(int client);
void ls_list(int client); void ls_list(int client);
// Utility functions // Utility functions
bool deny_enforced();
bool is_deny_target(int uid, std::string_view process); bool is_deny_target(int uid, std::string_view process);
// Revert // Revert
void revert_daemon(int pid, int client); void revert_daemon(int pid, int client);
void revert_unmount(int pid = -1); void revert_unmount(int pid = -1);
extern std::atomic<bool> denylist_enabled;
enum : int { enum : int {
ENFORCE_DENY, ENFORCE_DENY,
DISABLE_DENY, DISABLE_DENY,

View File

@ -19,7 +19,7 @@ static map<int, vector<string_view>> *uid_proc_map; /* uid -> list of process *
// Locks the variables above // Locks the variables above
static pthread_mutex_t data_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t data_lock = PTHREAD_MUTEX_INITIALIZER;
static atomic<bool> enforcement_status = false; atomic<bool> denylist_enabled = false;
static void rebuild_uid_map() { static void rebuild_uid_map() {
uid_proc_map->clear(); uid_proc_map->clear();
@ -147,7 +147,6 @@ static int add_list(const char *pkg, const char *proc) {
return DENYLIST_INVALID_PKG; return DENYLIST_INVALID_PKG;
{ {
// Critical region
mutex_guard lock(data_lock); mutex_guard lock(data_lock);
for (const auto &hide : *deny_set) for (const auto &hide : *deny_set)
if (hide.first == pkg && hide.second == proc) if (hide.first == pkg && hide.second == proc)
@ -172,9 +171,8 @@ int add_list(int client) {
} }
static int rm_list(const char *pkg, const char *proc) { static int rm_list(const char *pkg, const char *proc) {
bool remove = false;
{ {
// Critical region bool remove = false;
mutex_guard lock(data_lock); mutex_guard lock(data_lock);
for (auto it = deny_set->begin(); it != deny_set->end();) { for (auto it = deny_set->begin(); it != deny_set->end();) {
if (it->first == pkg && (proc[0] == '\0' || it->second == proc)) { if (it->first == pkg && (proc[0] == '\0' || it->second == proc)) {
@ -248,63 +246,68 @@ void ls_list(int client) {
close(client); close(client);
} }
static void update_hide_config() { static void update_deny_config() {
char sql[64]; char sql[64];
sprintf(sql, "REPLACE INTO settings (key,value) VALUES('%s',%d)", sprintf(sql, "REPLACE INTO settings (key,value) VALUES('%s',%d)",
DB_SETTING_KEYS[DENYLIST_CONFIG], enforcement_status.load()); DB_SETTING_KEYS[DENYLIST_CONFIG], denylist_enabled.load());
char *err = db_exec(sql); char *err = db_exec(sql);
db_err(err); db_err(err);
} }
int enable_hide() { int enable_deny() {
if (enforcement_status) if (denylist_enabled) {
return DENY_IS_ENFORCED; return DAEMON_SUCCESS;
} else {
mutex_guard lock(data_lock);
if (access("/proc/self/ns/mnt", F_OK) != 0) if (access("/proc/self/ns/mnt", F_OK) != 0) {
return DENY_NO_NS; LOGW("The kernel does not support mount namespace\n");
return DENY_NO_NS;
}
if (procfp == nullptr && (procfp = opendir("/proc")) == nullptr) if (procfp == nullptr && (procfp = opendir("/proc")) == nullptr)
return DAEMON_ERROR; return DAEMON_ERROR;
LOGI("* Enforce DenyList\n"); LOGI("* Enable DenyList\n");
mutex_guard lock(data_lock); default_new(deny_set);
default_new(deny_set); if (!init_list()) {
default_new(uid_proc_map); delete deny_set;
deny_set = nullptr;
return DAEMON_ERROR;
}
// Initialize the hide list denylist_enabled = true;
if (!init_list())
return DAEMON_ERROR;
enforcement_status = true; default_new(uid_proc_map);
update_hide_config(); rebuild_uid_map();
}
rebuild_uid_map(); update_deny_config();
return DAEMON_SUCCESS; return DAEMON_SUCCESS;
} }
int disable_deny() { int disable_deny() {
mutex_guard lock(data_lock); if (denylist_enabled) {
denylist_enabled = false;
if (enforcement_status) {
LOGI("* Disable DenyList\n"); LOGI("* Disable DenyList\n");
mutex_guard lock(data_lock);
delete uid_proc_map; delete uid_proc_map;
delete deny_set; delete deny_set;
uid_proc_map = nullptr; uid_proc_map = nullptr;
deny_set = nullptr; deny_set = nullptr;
} }
update_deny_config();
enforcement_status = false;
update_hide_config();
return DAEMON_SUCCESS; return DAEMON_SUCCESS;
} }
void check_enforce_denylist() { void initialize_denylist() {
if (!enforcement_status) { if (!denylist_enabled) {
db_settings dbs; db_settings dbs;
get_db_settings(dbs, DENYLIST_CONFIG); get_db_settings(dbs, DENYLIST_CONFIG);
if (dbs[DENYLIST_CONFIG]) if (dbs[DENYLIST_CONFIG])
enable_hide(); enable_deny();
} }
} }
@ -333,7 +336,3 @@ bool is_deny_target(int uid, string_view process) {
} }
return false; return false;
} }
bool deny_enforced() {
return enforcement_status;
}

View File

@ -39,14 +39,7 @@ enum : int {
DAEMON_LAST DAEMON_LAST
}; };
// Daemon state extern bool zygisk_enabled;
enum : int {
STATE_NONE,
STATE_POST_FS_DATA,
STATE_POST_FS_DATA_DONE,
STATE_LATE_START_DONE,
STATE_BOOT_COMPLETE
};
int connect_daemon(bool create = false); int connect_daemon(bool create = false);
@ -63,6 +56,6 @@ void su_daemon_handler(int client, ucred *credential);
void zygisk_handler(int client, ucred *cred); void zygisk_handler(int client, ucred *cred);
// Denylist // Denylist
void check_enforce_denylist(); void initialize_denylist();
int disable_deny(); int disable_deny();
int denylist_cli(int argc, char **argv); int denylist_cli(int argc, char **argv);

View File

@ -26,7 +26,7 @@ int fd_pathat(int dirfd, const char *name, char *path, size_t size) {
return 0; return 0;
} }
int mkdirs(string_view path, mode_t mode) { int mkdirs(string path, mode_t mode) {
errno = 0; errno = 0;
for (char *p = path.data() + 1; *p; ++p) { for (char *p = path.data() + 1; *p; ++p) {
if (*p == '/') { if (*p == '/') {

View File

@ -32,7 +32,7 @@ struct raw_file {
ssize_t fd_path(int fd, char *path, size_t size); ssize_t fd_path(int fd, char *path, size_t size);
int fd_pathat(int dirfd, const char *name, char *path, size_t size); int fd_pathat(int dirfd, const char *name, char *path, size_t size);
int mkdirs(std::string_view path, mode_t mode); int mkdirs(std::string path, mode_t mode);
void rm_rf(const char *path); void rm_rf(const char *path);
void mv_path(const char *src, const char *dest); void mv_path(const char *src, const char *dest);
void mv_dir(int src, int dest); void mv_dir(int src, int dest);

View File

@ -255,7 +255,7 @@ static void setup_files(int client, ucred *cred) {
} }
static void check_denylist(int client) { static void check_denylist(int client) {
if (!deny_enforced()) { if (!denylist_enabled) {
write_int(client, DENY_NOT_ENFORCED); write_int(client, DENY_NOT_ENFORCED);
return; return;
} }
@ -266,7 +266,7 @@ static void check_denylist(int client) {
} }
static void do_unmount(int client, ucred *cred) { static void do_unmount(int client, ucred *cred) {
if (deny_enforced()) { if (denylist_enabled) {
LOGD("zygisk: cleanup mount namespace for pid=[%d]\n", cred->pid); LOGD("zygisk: cleanup mount namespace for pid=[%d]\n", cred->pid);
revert_daemon(cred->pid, client); revert_daemon(cred->pid, client);
} else { } else {