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.core.content.edit
import com.topjohnwu.magisk.BuildConfig
import com.topjohnwu.magisk.core.utils.BiometricHelper
import com.topjohnwu.magisk.core.utils.refreshLocale
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.di.ServiceLocator
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_BIOMETRIC = "su_biometric"
const val ZYGISK = "zygisk"
const val DENYLIST = "denylist"
const val SU_MANAGER = "requester"
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 suBiometric by dbSettings(Key.SU_BIOMETRIC, false)
var zygisk by dbSettings(Key.ZYGISK, false)
var denyList by DBBoolSettingsNoWrite(Key.DENYLIST, false)
var suManager by dbStrings(Key.SU_MANAGER, "", true)
var keyStoreRaw by dbStrings(Key.KEYSTORE, "", true)
@ -169,12 +171,6 @@ object Config : PreferenceModel, DBConfig {
else if (it.toInt() > Value.CANARY_CHANNEL)
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 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
) : ReadWriteProperty<DBConfig, Int> {
private var value: Int? = null
var value: Int? = null
@Synchronized
override fun getValue(thisRef: DBConfig, property: KProperty<*>): Int {
if (value == null)
value = runBlocking {
thisRef.settingsDB.fetch(name, default)
}
value = runBlocking { thisRef.settingsDB.fetch(name, default) }
return value as Int
}
@ -56,7 +54,7 @@ class DBSettingsValue(
}
}
class DBBoolSettings(
open class DBBoolSettings(
name: String,
default: Boolean
) : ReadWriteProperty<DBConfig, Boolean> {
@ -70,6 +68,17 @@ class DBBoolSettings(
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(
private val name: String,
private val default: String,

View File

@ -251,11 +251,11 @@ object DenyList : BaseSettingsItem.Toggle() {
if (isEnabled) R.string.settings_denylist_summary.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 }) {
val cmd = if (it) "enable" else "disable"
Shell.su("magisk --denylist $cmd").submit { result ->
if (result.isSuccess) Info.env.denyListEnforced = it
if (result.isSuccess) Config.denyList = it
else field = !it
}
DenyListConfig.isEnabled = it

View File

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

View File

@ -6,7 +6,15 @@
extern bool RECOVERY_MODE;
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 reboot();

View File

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

View File

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

View File

@ -4,26 +4,28 @@
#include <string_view>
#include <functional>
#include <map>
#include <atomic>
#include <daemon.hpp>
#define ISOLATED_MAGIC "isolated"
// CLI entries
int enable_hide();
int enable_deny();
int disable_deny();
int add_list(int client);
int rm_list(int client);
void ls_list(int client);
// Utility functions
bool deny_enforced();
bool is_deny_target(int uid, std::string_view process);
// Revert
void revert_daemon(int pid, int client);
void revert_unmount(int pid = -1);
extern std::atomic<bool> denylist_enabled;
enum : int {
ENFORCE_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
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() {
uid_proc_map->clear();
@ -147,7 +147,6 @@ static int add_list(const char *pkg, const char *proc) {
return DENYLIST_INVALID_PKG;
{
// Critical region
mutex_guard lock(data_lock);
for (const auto &hide : *deny_set)
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) {
bool remove = false;
{
// Critical region
bool remove = false;
mutex_guard lock(data_lock);
for (auto it = deny_set->begin(); it != deny_set->end();) {
if (it->first == pkg && (proc[0] == '\0' || it->second == proc)) {
@ -248,63 +246,68 @@ void ls_list(int client) {
close(client);
}
static void update_hide_config() {
static void update_deny_config() {
char sql[64];
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);
db_err(err);
}
int enable_hide() {
if (enforcement_status)
return DENY_IS_ENFORCED;
int enable_deny() {
if (denylist_enabled) {
return DAEMON_SUCCESS;
} else {
mutex_guard lock(data_lock);
if (access("/proc/self/ns/mnt", F_OK) != 0)
return DENY_NO_NS;
if (access("/proc/self/ns/mnt", F_OK) != 0) {
LOGW("The kernel does not support mount namespace\n");
return DENY_NO_NS;
}
if (procfp == nullptr && (procfp = opendir("/proc")) == nullptr)
return DAEMON_ERROR;
if (procfp == nullptr && (procfp = opendir("/proc")) == nullptr)
return DAEMON_ERROR;
LOGI("* Enforce DenyList\n");
LOGI("* Enable DenyList\n");
mutex_guard lock(data_lock);
default_new(deny_set);
default_new(uid_proc_map);
default_new(deny_set);
if (!init_list()) {
delete deny_set;
deny_set = nullptr;
return DAEMON_ERROR;
}
// Initialize the hide list
if (!init_list())
return DAEMON_ERROR;
denylist_enabled = true;
enforcement_status = true;
update_hide_config();
default_new(uid_proc_map);
rebuild_uid_map();
}
rebuild_uid_map();
update_deny_config();
return DAEMON_SUCCESS;
}
int disable_deny() {
mutex_guard lock(data_lock);
if (enforcement_status) {
if (denylist_enabled) {
denylist_enabled = false;
LOGI("* Disable DenyList\n");
mutex_guard lock(data_lock);
delete uid_proc_map;
delete deny_set;
uid_proc_map = nullptr;
deny_set = nullptr;
}
enforcement_status = false;
update_hide_config();
update_deny_config();
return DAEMON_SUCCESS;
}
void check_enforce_denylist() {
if (!enforcement_status) {
void initialize_denylist() {
if (!denylist_enabled) {
db_settings dbs;
get_db_settings(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;
}
bool deny_enforced() {
return enforcement_status;
}

View File

@ -39,14 +39,7 @@ enum : int {
DAEMON_LAST
};
// Daemon state
enum : int {
STATE_NONE,
STATE_POST_FS_DATA,
STATE_POST_FS_DATA_DONE,
STATE_LATE_START_DONE,
STATE_BOOT_COMPLETE
};
extern bool zygisk_enabled;
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);
// Denylist
void check_enforce_denylist();
void initialize_denylist();
int disable_deny();
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;
}
int mkdirs(string_view path, mode_t mode) {
int mkdirs(string path, mode_t mode) {
errno = 0;
for (char *p = path.data() + 1; *p; ++p) {
if (*p == '/') {

View File

@ -32,7 +32,7 @@ struct raw_file {
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 mkdirs(std::string_view path, mode_t mode);
int mkdirs(std::string path, mode_t mode);
void rm_rf(const char *path);
void mv_path(const char *src, const char *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) {
if (!deny_enforced()) {
if (!denylist_enabled) {
write_int(client, DENY_NOT_ENFORCED);
return;
}
@ -266,7 +266,7 @@ static void check_denylist(int client) {
}
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);
revert_daemon(cred->pid, client);
} else {