diff --git a/kernel/Kconfig b/kernel/Kconfig index 59713417..88211ae8 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -22,7 +22,6 @@ config KSU_MULTI_MANAGER_SUPPORT help Enable multi KernelSU manager support - config KSU_ALLOWLIST_WORKAROUND bool "KernelSU Session Keyring Init workaround" depends on KSU diff --git a/kernel/Makefile b/kernel/Makefile index e5ce49ea..39a7b404 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -1,25 +1,25 @@ kernelsu-objs := ksu.o kernelsu-objs += allowlist.o -kernelsu-objs += app_profile.o kernelsu-objs += dynamic_manager.o +kernelsu-objs += app_profile.o kernelsu-objs += apk_sign.o kernelsu-objs += sucompat.o kernelsu-objs += syscall_hook_manager.o kernelsu-objs += throne_tracker.o kernelsu-objs += pkg_observer.o kernelsu-objs += setuid_hook.o +kernelsu-objs += lsm_hooks.o kernelsu-objs += kernel_compat.o kernelsu-objs += kernel_umount.o kernelsu-objs += supercalls.o kernelsu-objs += feature.o +kernelsu-objs += throne_tracker.o kernelsu-objs += ksud.o kernelsu-objs += embed_ksud.o kernelsu-objs += seccomp_cache.o kernelsu-objs += file_wrapper.o kernelsu-objs += throne_comm.o kernelsu-objs += sulog.o -kernelsu-objs += lsm_hook.o - ifeq ($(CONFIG_KSU_MANUAL_SU), y) ccflags-y += -DCONFIG_KSU_MANUAL_SU kernelsu-objs += manual_su.o @@ -93,6 +93,8 @@ endif ccflags-y += -DKSU_VERSION=$(KSU_VERSION) ccflags-y += -DKSU_VERSION_FULL=\"$(KSU_VERSION_FULL)\" +$(info -- Supported Unofficial Manager: 5ec1cff (GKI) rsuntk (Non-GKI) ShirkNeko udochina (GKI and non-GKI and KPM)) + ifeq ($(CONFIG_KSU_MANUAL_HOOK), y) ccflags-y += -DKSU_MANUAL_HOOK $(info -- SukiSU: KSU_MANUAL_HOOK) @@ -126,6 +128,14 @@ else $(info -- KPM is disabled) endif +# SELinux drivers check +ifeq ($(shell grep -q "current_sid(void)" $(srctree)/security/selinux/include/objsec.h; echo $$?),0) +ccflags-y += -DKSU_COMPAT_HAS_CURRENT_SID +endif +ifeq ($(shell grep -q "struct selinux_state " $(srctree)/security/selinux/include/security.h; echo $$?),0) +ccflags-y += -DKSU_COMPAT_HAS_SELINUX_STATE +endif + # Handle optional backports ifeq ($(shell grep -q "strncpy_from_user_nofault" $(srctree)/include/linux/uaccess.h; echo $$?),0) ccflags-y += -DKSU_OPTIONAL_STRNCPY @@ -136,36 +146,42 @@ endif ifeq ($(shell grep "ssize_t kernel_write" $(srctree)/fs/read_write.c | grep -q "const void" ; echo $$?),0) ccflags-y += -DKSU_OPTIONAL_KERNEL_WRITE endif +ifeq ($(shell grep -q "int\s\+path_umount" $(srctree)/fs/namespace.c; echo $$?),0) +ccflags-y += -DKSU_HAS_PATH_UMOUNT +endif ifeq ($(shell grep -q "inode_security_struct\s\+\*selinux_inode" $(srctree)/security/selinux/include/objsec.h; echo $$?),0) ccflags-y += -DKSU_OPTIONAL_SELINUX_INODE endif -ifeq ($(shell grep -q "int\s\+path_umount" $(srctree)/fs/namespace.c; echo $$?),0) -ccflags-y += -DKSU_HAS_PATH_UMOUNT -ifneq ($(shell grep -Eq "^int path_umount" $(srctree)/fs/internal.h; echo $$?),0) -$(shell sed -i '/^extern void __init mnt_init/a int path_umount(struct path *path, int flags);' $(srctree)/fs/internal.h;) -$(info -- KernelSU: SusFS: Adding 'int path_umount(struct path *path, int flags);' to $(srctree)/fs/internal.h) +ifeq ($(shell grep -q "task_security_struct\s\+\*selinux_cred" $(srctree)/security/selinux/include/objsec.h; echo $$?),0) +ccflags-y += -DKSU_OPTIONAL_SELINUX_CRED endif +# seccomp_types.h were added on 6.7 +ifeq ($(shell grep -q "atomic_t\s\+filter_count" $(srctree)/include/linux/seccomp.h $(srctree)/include/linux/seccomp_types.h; echo $$?),0) +ccflags-y += -DKSU_OPTIONAL_SECCOMP_FILTER_CNT endif -# Checks Samsung UH drivers +# some old kernel backport this, let's check if put_seccomp_filter still exist +ifneq ($(shell grep -wq "put_seccomp_filter" $(srctree)/kernel/seccomp.c $(srctree)/include/linux/seccomp.h; echo $$?),0) +ccflags-y += -DKSU_OPTIONAL_SECCOMP_FILTER_RELEASE +endif +ifeq ($(shell grep -q "anon_inode_getfd_secure" $(srctree)/fs/anon_inodes.c; echo $$?),0) +ccflags-y += -DKSU_HAS_GETFD_SECURE +endif +ifeq ($(shell grep -A1 "^int vfs_getattr" $(srctree)/fs/stat.c | grep -q "query_flags"; echo $$?),0) +ccflags-y += -DKSU_HAS_NEW_VFS_GETATTR +endif + +# Checks Samsung ifeq ($(shell grep -q "CONFIG_KDP_CRED" $(srctree)/kernel/cred.c; echo $$?),0) ccflags-y += -DSAMSUNG_UH_DRIVER_EXIST endif - -# Samsung SELinux Porting ifeq ($(shell grep -q "SEC_SELINUX_PORTING_COMMON" $(srctree)/security/selinux/avc.c; echo $$?),0) ccflags-y += -DSAMSUNG_SELINUX_PORTING endif - # Function proc_ops check ifeq ($(shell grep -q "struct proc_ops " $(srctree)/include/linux/proc_fs.h; echo $$?),0) ccflags-y += -DKSU_COMPAT_HAS_PROC_OPS endif -# Struct selinux_state check -ifeq ($(shell grep -q "struct selinux_state " $(srctree)/security/selinux/include/security.h; echo $$?),0) -ccflags-y += -DKSU_COMPAT_HAS_SELINUX_STATE -endif - # Custom Signs ifdef KSU_EXPECTED_SIZE ccflags-y += -DEXPECTED_SIZE=$(KSU_EXPECTED_SIZE) @@ -182,7 +198,6 @@ ccflags-y += -DKSU_MANAGER_PACKAGE=\"$(KSU_MANAGER_PACKAGE)\" $(info -- SukiSU Manager package name: $(KSU_MANAGER_PACKAGE)) endif -$(info -- Supported Unofficial Manager: 5ec1cff (GKI) rsuntk (Non-GKI) ShirkNeko udochina (GKI and non-GKI and KPM)) ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat ccflags-y += -Wno-declaration-after-statement -Wno-unused-function -Wno-unused-variable diff --git a/kernel/allowlist.c b/kernel/allowlist.c index 650f249a..061fb533 100644 --- a/kernel/allowlist.c +++ b/kernel/allowlist.c @@ -21,10 +21,10 @@ #include "klog.h" // IWYU pragma: keep #include "ksud.h" -#include "kernel_compat.h" #include "selinux/selinux.h" #include "allowlist.h" #include "manager.h" +#include "kernel_compat.h" #ifndef CONFIG_KSU_SUSFS #include "syscall_hook_manager.h" #endif // #ifndef CONFIG_KSU_SUSFS @@ -41,61 +41,59 @@ static DEFINE_MUTEX(allowlist_mutex); static struct root_profile default_root_profile; static struct non_root_profile default_non_root_profile; -void persistent_allow_list(void); - static int allow_list_arr[PAGE_SIZE / sizeof(int)] __read_mostly - __aligned(PAGE_SIZE); + __aligned(PAGE_SIZE); static int allow_list_pointer __read_mostly = 0; static void remove_uid_from_arr(uid_t uid) { - int *temp_arr; - int i, j; + int *temp_arr; + int i, j; - if (allow_list_pointer == 0) - return; + if (allow_list_pointer == 0) + return; - temp_arr = kzalloc(sizeof(allow_list_arr), GFP_KERNEL); - if (temp_arr == NULL) { - pr_err("%s: unable to allocate memory\n", __func__); - return; - } + temp_arr = kzalloc(sizeof(allow_list_arr), GFP_KERNEL); + if (temp_arr == NULL) { + pr_err("%s: unable to allocate memory\n", __func__); + return; + } - for (i = j = 0; i < allow_list_pointer; i++) { - if (allow_list_arr[i] == uid) - continue; - temp_arr[j++] = allow_list_arr[i]; - } + for (i = j = 0; i < allow_list_pointer; i++) { + if (allow_list_arr[i] == uid) + continue; + temp_arr[j++] = allow_list_arr[i]; + } - allow_list_pointer = j; + allow_list_pointer = j; - for (; j < ARRAY_SIZE(allow_list_arr); j++) - temp_arr[j] = -1; + for (; j < ARRAY_SIZE(allow_list_arr); j++) + temp_arr[j] = -1; - memcpy(&allow_list_arr, temp_arr, PAGE_SIZE); - kfree(temp_arr); + memcpy(&allow_list_arr, temp_arr, PAGE_SIZE); + kfree(temp_arr); } static void init_default_profiles(void) { - kernel_cap_t full_cap = CAP_FULL_SET; + kernel_cap_t full_cap = CAP_FULL_SET; - default_root_profile.uid = 0; - default_root_profile.gid = 0; - default_root_profile.groups_count = 1; - default_root_profile.groups[0] = 0; - memcpy(&default_root_profile.capabilities.effective, &full_cap, - sizeof(default_root_profile.capabilities.effective)); - default_root_profile.namespaces = 0; - strcpy(default_root_profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN); + default_root_profile.uid = 0; + default_root_profile.gid = 0; + default_root_profile.groups_count = 1; + default_root_profile.groups[0] = 0; + memcpy(&default_root_profile.capabilities.effective, &full_cap, + sizeof(default_root_profile.capabilities.effective)); + default_root_profile.namespaces = 0; + strcpy(default_root_profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN); - // This means that we will umount modules by default! - default_non_root_profile.umount_modules = true; + // This means that we will umount modules by default! + default_non_root_profile.umount_modules = true; } struct perm_data { - struct list_head list; - struct app_profile profile; + struct list_head list; + struct app_profile profile; }; static struct list_head allow_list; @@ -105,463 +103,470 @@ static uint8_t allow_list_bitmap[PAGE_SIZE] __read_mostly __aligned(PAGE_SIZE); #define KERNEL_SU_ALLOWLIST "/data/adb/ksu/.allowlist" +void persistent_allow_list(void); + void ksu_show_allow_list(void) { - struct perm_data *p = NULL; - struct list_head *pos = NULL; - pr_info("ksu_show_allow_list\n"); - list_for_each (pos, &allow_list) { - p = list_entry(pos, struct perm_data, list); - pr_info("uid :%d, allow: %d\n", p->profile.current_uid, - p->profile.allow_su); - } + struct perm_data *p = NULL; + struct list_head *pos = NULL; + pr_info("ksu_show_allow_list\n"); + list_for_each (pos, &allow_list) { + p = list_entry(pos, struct perm_data, list); + pr_info("uid :%d, allow: %d\n", p->profile.current_uid, + p->profile.allow_su); + } } #ifdef CONFIG_KSU_DEBUG static void ksu_grant_root_to_shell(void) { - struct app_profile profile = { - .version = KSU_APP_PROFILE_VER, - .allow_su = true, - .current_uid = 2000, - }; - strcpy(profile.key, "com.android.shell"); - strcpy(profile.rp_config.profile.selinux_domain, - KSU_DEFAULT_SELINUX_DOMAIN); - ksu_set_app_profile(&profile, false); + struct app_profile profile = { + .version = KSU_APP_PROFILE_VER, + .allow_su = true, + .current_uid = 2000, + }; + strcpy(profile.key, "com.android.shell"); + strcpy(profile.rp_config.profile.selinux_domain, + KSU_DEFAULT_SELINUX_DOMAIN); + ksu_set_app_profile(&profile, false); } #endif bool ksu_get_app_profile(struct app_profile *profile) { - struct perm_data *p = NULL; - struct list_head *pos = NULL; - bool found = false; + struct perm_data *p = NULL; + struct list_head *pos = NULL; + bool found = false; - list_for_each (pos, &allow_list) { - p = list_entry(pos, struct perm_data, list); - bool uid_match = profile->current_uid == p->profile.current_uid; - if (uid_match) { - // found it, override it with ours - memcpy(profile, &p->profile, sizeof(*profile)); - found = true; - goto exit; - } - } + list_for_each (pos, &allow_list) { + p = list_entry(pos, struct perm_data, list); + bool uid_match = profile->current_uid == p->profile.current_uid; + if (uid_match) { + // found it, override it with ours + memcpy(profile, &p->profile, sizeof(*profile)); + found = true; + goto exit; + } + } exit: - return found; + return found; } static inline bool forbid_system_uid(uid_t uid) { #define SHELL_UID 2000 #define SYSTEM_UID 1000 - return uid < SHELL_UID && uid != SYSTEM_UID; + return uid < SHELL_UID && uid != SYSTEM_UID; } static bool profile_valid(struct app_profile *profile) { - if (!profile) { - return false; - } + if (!profile) { + return false; + } - if (profile->version < KSU_APP_PROFILE_VER) { - pr_info("Unsupported profile version: %d\n", profile->version); - return false; - } + if (profile->version < KSU_APP_PROFILE_VER) { + pr_info("Unsupported profile version: %d\n", profile->version); + return false; + } - if (profile->allow_su) { - if (profile->rp_config.profile.groups_count > KSU_MAX_GROUPS) { - return false; - } + if (profile->allow_su) { + if (profile->rp_config.profile.groups_count > KSU_MAX_GROUPS) { + return false; + } - if (strlen(profile->rp_config.profile.selinux_domain) == 0) { - return false; - } - } + if (strlen(profile->rp_config.profile.selinux_domain) == 0) { + return false; + } + } - return true; + return true; } bool ksu_set_app_profile(struct app_profile *profile, bool persist) { - struct perm_data *p = NULL; - struct list_head *pos = NULL; - bool result = false; + struct perm_data *p = NULL; + struct list_head *pos = NULL; + bool result = false; - if (!profile_valid(profile)) { - pr_err("Failed to set app profile: invalid profile!\n"); - return false; - } + if (!profile_valid(profile)) { + pr_err("Failed to set app profile: invalid profile!\n"); + return false; + } - list_for_each (pos, &allow_list) { - p = list_entry(pos, struct perm_data, list); - // both uid and package must match, otherwise it will break multiple package with different user id - if (profile->current_uid == p->profile.current_uid && - !strcmp(profile->key, p->profile.key)) { - // found it, just override it all! - memcpy(&p->profile, profile, sizeof(*profile)); - result = true; - goto out; - } - } + list_for_each (pos, &allow_list) { + p = list_entry(pos, struct perm_data, list); + // both uid and package must match, otherwise it will break multiple package with different user id + if (profile->current_uid == p->profile.current_uid && + !strcmp(profile->key, p->profile.key)) { + // found it, just override it all! + memcpy(&p->profile, profile, sizeof(*profile)); + result = true; + goto out; + } + } - // not found, alloc a new node! - p = (struct perm_data *)kzalloc(sizeof(struct perm_data), GFP_KERNEL); - if (!p) { - pr_err("ksu_set_app_profile alloc failed\n"); - return false; - } + // not found, alloc a new node! + p = (struct perm_data *)kzalloc(sizeof(struct perm_data), GFP_KERNEL); + if (!p) { + pr_err("ksu_set_app_profile alloc failed\n"); + return false; + } - memcpy(&p->profile, profile, sizeof(*profile)); - if (profile->allow_su) { - pr_info("set root profile, key: %s, uid: %d, gid: %d, context: %s\n", - profile->key, profile->current_uid, - profile->rp_config.profile.gid, - profile->rp_config.profile.selinux_domain); - } else { - pr_info("set app profile, key: %s, uid: %d, umount modules: %d\n", - profile->key, profile->current_uid, - profile->nrp_config.profile.umount_modules); - } - list_add_tail(&p->list, &allow_list); + memcpy(&p->profile, profile, sizeof(*profile)); + if (profile->allow_su) { + pr_info("set root profile, key: %s, uid: %d, gid: %d, context: %s\n", + profile->key, profile->current_uid, + profile->rp_config.profile.gid, + profile->rp_config.profile.selinux_domain); + } else { + pr_info("set app profile, key: %s, uid: %d, umount modules: %d\n", + profile->key, profile->current_uid, + profile->nrp_config.profile.umount_modules); + } + list_add_tail(&p->list, &allow_list); out: - if (profile->current_uid <= BITMAP_UID_MAX) { - if (profile->allow_su) - allow_list_bitmap[profile->current_uid / BITS_PER_BYTE] |= - 1 << (profile->current_uid % BITS_PER_BYTE); - else - allow_list_bitmap[profile->current_uid / BITS_PER_BYTE] &= - ~(1 << (profile->current_uid % BITS_PER_BYTE)); - } else { - if (profile->allow_su) { - /* + if (profile->current_uid <= BITMAP_UID_MAX) { + if (profile->allow_su) + allow_list_bitmap[profile->current_uid / BITS_PER_BYTE] |= + 1 << (profile->current_uid % BITS_PER_BYTE); + else + allow_list_bitmap[profile->current_uid / BITS_PER_BYTE] &= + ~(1 << (profile->current_uid % BITS_PER_BYTE)); + } else { + if (profile->allow_su) { + /* * 1024 apps with uid higher than BITMAP_UID_MAX * registered to request superuser? */ - if (allow_list_pointer >= ARRAY_SIZE(allow_list_arr)) { - pr_err("too many apps registered\n"); - WARN_ON(1); - return false; - } - allow_list_arr[allow_list_pointer++] = profile->current_uid; - } else { - remove_uid_from_arr(profile->current_uid); - } - } - result = true; + if (allow_list_pointer >= ARRAY_SIZE(allow_list_arr)) { + pr_err("too many apps registered\n"); + WARN_ON(1); + return false; + } + allow_list_arr[allow_list_pointer++] = + profile->current_uid; + } else { + remove_uid_from_arr(profile->current_uid); + } + } + result = true; - // check if the default profiles is changed, cache it to a single struct to accelerate access. - if (unlikely(!strcmp(profile->key, "$"))) { - // set default non root profile - memcpy(&default_non_root_profile, &profile->nrp_config.profile, - sizeof(default_non_root_profile)); - } + // check if the default profiles is changed, cache it to a single struct to accelerate access. + if (unlikely(!strcmp(profile->key, "$"))) { + // set default non root profile + memcpy(&default_non_root_profile, &profile->nrp_config.profile, + sizeof(default_non_root_profile)); + } - if (unlikely(!strcmp(profile->key, "#"))) { - // set default root profile - memcpy(&default_root_profile, &profile->rp_config.profile, - sizeof(default_root_profile)); - } + if (unlikely(!strcmp(profile->key, "#"))) { + // set default root profile + memcpy(&default_root_profile, &profile->rp_config.profile, + sizeof(default_root_profile)); + } - if (persist) { - persistent_allow_list(); -#ifndef CONFIG_KSU_SUSFS - // FIXME: use a new flag - ksu_mark_running_process(); -#endif // #ifndef CONFIG_KSU_SUSFS - } + if (persist) { + persistent_allow_list(); + // FIXME: use a new flag + ksu_mark_running_process(); + } - return result; + return result; } bool __ksu_is_allow_uid(uid_t uid) { - int i; + int i; - if (forbid_system_uid(uid)) { - // do not bother going through the list if it's system - return false; - } + if (forbid_system_uid(uid)) { + // do not bother going through the list if it's system + return false; + } - if (likely(ksu_is_manager_uid_valid()) && - unlikely(ksu_get_manager_uid() == uid)) { - // manager is always allowed! - return true; - } + if (likely(ksu_is_manager_uid_valid()) && + unlikely(ksu_get_manager_uid() == uid)) { + // manager is always allowed! + return true; + } - if (likely(uid <= BITMAP_UID_MAX)) { - return !!(allow_list_bitmap[uid / BITS_PER_BYTE] & - (1 << (uid % BITS_PER_BYTE))); - } else { - for (i = 0; i < allow_list_pointer; i++) { - if (allow_list_arr[i] == uid) - return true; - } - } + if (likely(uid <= BITMAP_UID_MAX)) { + return !!(allow_list_bitmap[uid / BITS_PER_BYTE] & + (1 << (uid % BITS_PER_BYTE))); + } else { + for (i = 0; i < allow_list_pointer; i++) { + if (allow_list_arr[i] == uid) + return true; + } + } - return false; + return false; } bool __ksu_is_allow_uid_for_current(uid_t uid) { - if (unlikely(uid == 0)) { - // already root, but only allow our domain. - return is_ksu_domain(); - } - return __ksu_is_allow_uid(uid); + if (unlikely(uid == 0)) { + // already root, but only allow our domain. + return is_ksu_domain(); + } + return __ksu_is_allow_uid(uid); } bool ksu_uid_should_umount(uid_t uid) { - struct app_profile profile = { .current_uid = uid }; - if (likely(ksu_is_manager_uid_valid()) && - unlikely(ksu_get_manager_uid() == uid)) { - // we should not umount on manager! - return false; - } - bool found = ksu_get_app_profile(&profile); - if (!found) { - // no app profile found, it must be non root app - return default_non_root_profile.umount_modules; - } - if (profile.allow_su) { - // if found and it is granted to su, we shouldn't umount for it - return false; - } else { - // found an app profile - if (profile.nrp_config.use_default) { - return default_non_root_profile.umount_modules; - } else { - return profile.nrp_config.profile.umount_modules; - } - } + struct app_profile profile = { .current_uid = uid }; + if (likely(ksu_is_manager_uid_valid()) && + unlikely(ksu_get_manager_uid() == uid)) { + // we should not umount on manager! + return false; + } + bool found = ksu_get_app_profile(&profile); + if (!found) { + // no app profile found, it must be non root app + return default_non_root_profile.umount_modules; + } + if (profile.allow_su) { + // if found and it is granted to su, we shouldn't umount for it + return false; + } else { + // found an app profile + if (profile.nrp_config.use_default) { + return default_non_root_profile.umount_modules; + } else { + return profile.nrp_config.profile.umount_modules; + } + } } struct root_profile *ksu_get_root_profile(uid_t uid) { - struct perm_data *p = NULL; - struct list_head *pos = NULL; + struct perm_data *p = NULL; + struct list_head *pos = NULL; - list_for_each (pos, &allow_list) { - p = list_entry(pos, struct perm_data, list); - if (uid == p->profile.current_uid && p->profile.allow_su) { - if (!p->profile.rp_config.use_default) { - return &p->profile.rp_config.profile; - } - } - } + list_for_each (pos, &allow_list) { + p = list_entry(pos, struct perm_data, list); + if (uid == p->profile.current_uid && p->profile.allow_su) { + if (!p->profile.rp_config.use_default) { + return &p->profile.rp_config.profile; + } + } + } - // use default profile - return &default_root_profile; + // use default profile + return &default_root_profile; } bool ksu_get_allow_list(int *array, int *length, bool allow) { - struct perm_data *p = NULL; - struct list_head *pos = NULL; - int i = 0; - list_for_each (pos, &allow_list) { - p = list_entry(pos, struct perm_data, list); - // pr_info("get_allow_list uid: %d allow: %d\n", p->uid, p->allow); - if (p->profile.allow_su == allow) { - array[i++] = p->profile.current_uid; - } - } - *length = i; + struct perm_data *p = NULL; + struct list_head *pos = NULL; + int i = 0; + list_for_each (pos, &allow_list) { + p = list_entry(pos, struct perm_data, list); + // pr_info("get_allow_list uid: %d allow: %d\n", p->uid, p->allow); + if (p->profile.allow_su == allow) { + array[i++] = p->profile.current_uid; + } + } + *length = i; - return true; + return true; } static void do_persistent_allow_list(struct callback_head *_cb) { - u32 magic = FILE_MAGIC; - u32 version = FILE_FORMAT_VERSION; - struct perm_data *p = NULL; - struct list_head *pos = NULL; - loff_t off = 0; + u32 magic = FILE_MAGIC; + u32 version = FILE_FORMAT_VERSION; + struct perm_data *p = NULL; + struct list_head *pos = NULL; + loff_t off = 0; - mutex_lock(&allowlist_mutex); - struct file *fp = - filp_open(KERNEL_SU_ALLOWLIST, O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (IS_ERR(fp)) { - pr_err("save_allow_list create file failed: %ld\n", PTR_ERR(fp)); - goto unlock; - } + mutex_lock(&allowlist_mutex); + struct file *fp = ksu_filp_open_compat( + KERNEL_SU_ALLOWLIST, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (IS_ERR(fp)) { + pr_err("save_allow_list create file failed: %ld\n", + PTR_ERR(fp)); + goto unlock; + } - // store magic and version - if (kernel_write(fp, &magic, sizeof(magic), &off) != sizeof(magic)) { - pr_err("save_allow_list write magic failed.\n"); - goto close_file; - } + // store magic and version + if (ksu_kernel_write_compat(fp, &magic, sizeof(magic), &off) != + sizeof(magic)) { + pr_err("save_allow_list write magic failed.\n"); + goto close_file; + } - if (kernel_write(fp, &version, sizeof(version), &off) != sizeof(version)) { - pr_err("save_allow_list write version failed.\n"); - goto close_file; - } + if (ksu_kernel_write_compat(fp, &version, sizeof(version), &off) != + sizeof(version)) { + pr_err("save_allow_list write version failed.\n"); + goto close_file; + } - list_for_each (pos, &allow_list) { - p = list_entry(pos, struct perm_data, list); - pr_info("save allow list, name: %s uid :%d, allow: %d\n", - p->profile.key, p->profile.current_uid, p->profile.allow_su); + list_for_each (pos, &allow_list) { + p = list_entry(pos, struct perm_data, list); + pr_info("save allow list, name: %s uid :%d, allow: %d\n", + p->profile.key, p->profile.current_uid, + p->profile.allow_su); - kernel_write(fp, &p->profile, sizeof(p->profile), &off); - } + ksu_kernel_write_compat(fp, &p->profile, sizeof(p->profile), + &off); + } close_file: - filp_close(fp, 0); + filp_close(fp, 0); unlock: - mutex_unlock(&allowlist_mutex); - kfree(_cb); + mutex_unlock(&allowlist_mutex); + kfree(_cb); } -void persistent_allow_list() +void persistent_allow_list(void) { - struct task_struct *tsk; + struct task_struct *tsk; - tsk = get_pid_task(find_vpid(1), PIDTYPE_PID); - if (!tsk) { - pr_err("save_allow_list find init task err\n"); - return; - } + tsk = get_pid_task(find_vpid(1), PIDTYPE_PID); + if (!tsk) { + pr_err("save_allow_list find init task err\n"); + return; + } - struct callback_head *cb = - kzalloc(sizeof(struct callback_head), GFP_KERNEL); - if (!cb) { - pr_err("save_allow_list alloc cb err\b"); - goto put_task; - } - cb->func = do_persistent_allow_list; - task_work_add(tsk, cb, TWA_RESUME); + struct callback_head *cb = + kzalloc(sizeof(struct callback_head), GFP_KERNEL); + if (!cb) { + pr_err("save_allow_list alloc cb err\b"); + goto put_task; + } + cb->func = do_persistent_allow_list; + task_work_add(tsk, cb, TWA_RESUME); put_task: - put_task_struct(tsk); + put_task_struct(tsk); } -void ksu_load_allow_list() +void ksu_load_allow_list(void) { - loff_t off = 0; - ssize_t ret = 0; - struct file *fp = NULL; - u32 magic; - u32 version; + loff_t off = 0; + ssize_t ret = 0; + struct file *fp = NULL; + u32 magic; + u32 version; #ifdef CONFIG_KSU_DEBUG - // always allow adb shell by default - ksu_grant_root_to_shell(); + // always allow adb shell by default + ksu_grant_root_to_shell(); #endif - // load allowlist now! - fp = filp_open(KERNEL_SU_ALLOWLIST, O_RDONLY, 0); - if (IS_ERR(fp)) { - pr_err("load_allow_list open file failed: %ld\n", PTR_ERR(fp)); - return; - } + // load allowlist now! + fp = ksu_filp_open_compat(KERNEL_SU_ALLOWLIST, O_RDONLY, 0); + if (IS_ERR(fp)) { + pr_err("load_allow_list open file failed: %ld\n", PTR_ERR(fp)); + return; + } - // verify magic - if (kernel_read(fp, &magic, sizeof(magic), &off) != sizeof(magic) || - magic != FILE_MAGIC) { - pr_err("allowlist file invalid: %d!\n", magic); - goto exit; - } + // verify magic + if (ksu_kernel_read_compat(fp, &magic, sizeof(magic), &off) != + sizeof(magic) || + magic != FILE_MAGIC) { + pr_err("allowlist file invalid: %d!\n", magic); + goto exit; + } - if (kernel_read(fp, &version, sizeof(version), &off) != sizeof(version)) { - pr_err("allowlist read version: %d failed\n", version); - goto exit; - } + if (ksu_kernel_read_compat(fp, &version, sizeof(version), &off) != + sizeof(version)) { + pr_err("allowlist read version: %d failed\n", version); + goto exit; + } - pr_info("allowlist version: %d\n", version); + pr_info("allowlist version: %d\n", version); - while (true) { - struct app_profile profile; + while (true) { + struct app_profile profile; - ret = kernel_read(fp, &profile, sizeof(profile), &off); + ret = ksu_kernel_read_compat(fp, &profile, sizeof(profile), + &off); - if (ret <= 0) { - pr_info("load_allow_list read err: %zd\n", ret); - break; - } + if (ret <= 0) { + pr_info("load_allow_list read err: %zd\n", ret); + break; + } - pr_info("load_allow_uid, name: %s, uid: %d, allow: %d\n", profile.key, - profile.current_uid, profile.allow_su); - ksu_set_app_profile(&profile, false); - } + pr_info("load_allow_uid, name: %s, uid: %d, allow: %d\n", + profile.key, profile.current_uid, profile.allow_su); + ksu_set_app_profile(&profile, false); + } exit: - ksu_show_allow_list(); - filp_close(fp, 0); + ksu_show_allow_list(); + filp_close(fp, 0); } void ksu_prune_allowlist(bool (*is_uid_valid)(uid_t, char *, void *), - void *data) + void *data) { - struct perm_data *np = NULL; - struct perm_data *n = NULL; + struct perm_data *np = NULL; + struct perm_data *n = NULL; - if (!ksu_boot_completed) { - pr_info("boot not completed, skip prune\n"); - return; - } + if (!ksu_boot_completed) { + pr_info("boot not completed, skip prune\n"); + return; + } - bool modified = false; - // TODO: use RCU! - mutex_lock(&allowlist_mutex); - list_for_each_entry_safe (np, n, &allow_list, list) { - uid_t uid = np->profile.current_uid; - char *package = np->profile.key; - // we use this uid for special cases, don't prune it! - bool is_preserved_uid = uid == KSU_APP_PROFILE_PRESERVE_UID; - if (!is_preserved_uid && !is_uid_valid(uid, package, data)) { - modified = true; - pr_info("prune uid: %d, package: %s\n", uid, package); - list_del(&np->list); - if (likely(uid <= BITMAP_UID_MAX)) { - allow_list_bitmap[uid / BITS_PER_BYTE] &= - ~(1 << (uid % BITS_PER_BYTE)); - } - remove_uid_from_arr(uid); - smp_mb(); - kfree(np); - } - } - mutex_unlock(&allowlist_mutex); + bool modified = false; + // TODO: use RCU! + mutex_lock(&allowlist_mutex); + list_for_each_entry_safe (np, n, &allow_list, list) { + uid_t uid = np->profile.current_uid; + char *package = np->profile.key; + // we use this uid for special cases, don't prune it! + bool is_preserved_uid = uid == KSU_APP_PROFILE_PRESERVE_UID; + if (!is_preserved_uid && !is_uid_valid(uid, package, data)) { + modified = true; + pr_info("prune uid: %d, package: %s\n", uid, package); + list_del(&np->list); + if (likely(uid <= BITMAP_UID_MAX)) { + allow_list_bitmap[uid / BITS_PER_BYTE] &= + ~(1 << (uid % BITS_PER_BYTE)); + } + remove_uid_from_arr(uid); + smp_mb(); + kfree(np); + } + } + mutex_unlock(&allowlist_mutex); - if (modified) { - persistent_allow_list(); - } + if (modified) { + persistent_allow_list(); + } } void ksu_allowlist_init(void) { - int i; + int i; - BUILD_BUG_ON(sizeof(allow_list_bitmap) != PAGE_SIZE); - BUILD_BUG_ON(sizeof(allow_list_arr) != PAGE_SIZE); + BUILD_BUG_ON(sizeof(allow_list_bitmap) != PAGE_SIZE); + BUILD_BUG_ON(sizeof(allow_list_arr) != PAGE_SIZE); - for (i = 0; i < ARRAY_SIZE(allow_list_arr); i++) - allow_list_arr[i] = -1; + for (i = 0; i < ARRAY_SIZE(allow_list_arr); i++) + allow_list_arr[i] = -1; - INIT_LIST_HEAD(&allow_list); + INIT_LIST_HEAD(&allow_list); - init_default_profiles(); + init_default_profiles(); } void ksu_allowlist_exit(void) { - struct perm_data *np = NULL; - struct perm_data *n = NULL; + struct perm_data *np = NULL; + struct perm_data *n = NULL; - persistent_allow_list(); - - // free allowlist - mutex_lock(&allowlist_mutex); - list_for_each_entry_safe (np, n, &allow_list, list) { - list_del(&np->list); - kfree(np); - } - mutex_unlock(&allowlist_mutex); + // free allowlist + mutex_lock(&allowlist_mutex); + list_for_each_entry_safe (np, n, &allow_list, list) { + list_del(&np->list); + kfree(np); + } + mutex_unlock(&allowlist_mutex); } #ifdef CONFIG_KSU_MANUAL_SU diff --git a/kernel/allowlist.h b/kernel/allowlist.h index 4bac8c32..68e04bab 100644 --- a/kernel/allowlist.h +++ b/kernel/allowlist.h @@ -23,11 +23,13 @@ bool __ksu_is_allow_uid(uid_t uid); // Check if the uid is in allow list, or current is ksu domain root bool __ksu_is_allow_uid_for_current(uid_t uid); -#define ksu_is_allow_uid_for_current(uid) unlikely(__ksu_is_allow_uid_for_current(uid)) +#define ksu_is_allow_uid_for_current(uid) \ + unlikely(__ksu_is_allow_uid_for_current(uid)) bool ksu_get_allow_list(int *array, int *length, bool allow); -void ksu_prune_allowlist(bool (*is_uid_exist)(uid_t, char *, void *), void *data); +void ksu_prune_allowlist(bool (*is_uid_exist)(uid_t, char *, void *), + void *data); bool ksu_get_app_profile(struct app_profile *); bool ksu_set_app_profile(struct app_profile *, bool persist); @@ -37,8 +39,8 @@ struct root_profile *ksu_get_root_profile(uid_t uid); static inline bool is_appuid(uid_t uid) { - uid_t appid = uid % PER_USER_RANGE; - return appid >= FIRST_APPLICATION_UID && appid <= LAST_APPLICATION_UID; + uid_t appid = uid % PER_USER_RANGE; + return appid >= FIRST_APPLICATION_UID && appid <= LAST_APPLICATION_UID; } #ifdef CONFIG_KSU_MANUAL_SU @@ -46,4 +48,4 @@ bool ksu_temp_grant_root_once(uid_t uid); void ksu_temp_revoke_root_once(uid_t uid); #endif -#endif +#endif \ No newline at end of file diff --git a/kernel/apk_sign.c b/kernel/apk_sign.c index bc371263..04d8ae97 100644 --- a/kernel/apk_sign.c +++ b/kernel/apk_sign.c @@ -18,6 +18,7 @@ #include "dynamic_manager.h" #include "klog.h" // IWYU pragma: keep #include "manager_sign.h" +#include "kernel_compat.h" struct sdesc { struct shash_desc shash; @@ -107,7 +108,7 @@ static bool check_dynamic_sign(struct file *fp, u32 size4, loff_t *pos, int *mat return false; } - kernel_read(fp, cert, size4, pos); + ksu_kernel_read_compat(fp, cert, size4, pos); unsigned char digest[SHA256_DIGEST_SIZE]; if (ksu_sha256(cert, size4, digest) < 0) { @@ -137,19 +138,19 @@ static bool check_block(struct file *fp, u32 *size4, loff_t *pos, u32 *offset, i apk_sign_key_t sign_key; bool signature_valid = false; - kernel_read(fp, size4, 0x4, pos); // signer-sequence length - kernel_read(fp, size4, 0x4, pos); // signer length - kernel_read(fp, size4, 0x4, pos); // signed data length + ksu_kernel_read_compat(fp, size4, 0x4, pos); // signer-sequence length + ksu_kernel_read_compat(fp, size4, 0x4, pos); // signer length + ksu_kernel_read_compat(fp, size4, 0x4, pos); // signed data length *offset += 0x4 * 3; - kernel_read(fp, size4, 0x4, pos); // digests-sequence length + ksu_kernel_read_compat(fp, size4, 0x4, pos); // digests-sequence length *pos += *size4; *offset += 0x4 + *size4; - kernel_read(fp, size4, 0x4, pos); // certificates length - kernel_read(fp, size4, 0x4, pos); // certificate length + ksu_kernel_read_compat(fp, size4, 0x4, pos); // certificates length + ksu_kernel_read_compat(fp, size4, 0x4, pos); // certificate length *offset += 0x4 * 2; if (ksu_is_dynamic_manager_enabled()) { @@ -174,7 +175,7 @@ static bool check_block(struct file *fp, u32 *size4, loff_t *pos, u32 *offset, i pr_info("cert length overlimit\n"); return false; } - kernel_read(fp, cert, *size4, pos); + ksu_kernel_read_compat(fp, cert, *size4, pos); unsigned char digest[SHA256_DIGEST_SIZE]; if (ksu_sha256(cert, *size4, digest) < 0 ) { pr_info("sha256 error\n"); @@ -220,7 +221,7 @@ static bool has_v1_signature_file(struct file *fp) loff_t pos = 0; - while (kernel_read(fp, &header, + while (ksu_kernel_read_compat(fp, &header, sizeof(struct zip_entry_header), &pos) == sizeof(struct zip_entry_header)) { if (header.signature != 0x04034b50) { @@ -230,7 +231,7 @@ static bool has_v1_signature_file(struct file *fp) // Read the entry file name if (header.file_name_length == sizeof(MANIFEST) - 1) { char fileName[sizeof(MANIFEST)]; - kernel_read(fp, fileName, + ksu_kernel_read_compat(fp, fileName, header.file_name_length, &pos); fileName[header.file_name_length] = '\0'; @@ -265,7 +266,7 @@ static __always_inline bool check_v2_signature(char *path, bool check_multi_mana bool v3_1_signing_exist = false; int matched_index = -1; int i; - struct file *fp = filp_open(path, O_RDONLY, 0); + struct file *fp = ksu_filp_open_compat(path, O_RDONLY, 0); if (IS_ERR(fp)) { pr_err("open %s error.\n", path); return false; @@ -284,10 +285,10 @@ static __always_inline bool check_v2_signature(char *path, bool check_multi_mana for (i = 0;; ++i) { unsigned short n; pos = generic_file_llseek(fp, -i - 2, SEEK_END); - kernel_read(fp, &n, 2, &pos); + ksu_kernel_read_compat(fp, &n, 2, &pos); if (n == i) { pos -= 22; - kernel_read(fp, &size4, 4, &pos); + ksu_kernel_read_compat(fp, &size4, 4, &pos); if ((size4 ^ 0xcafebabeu) == 0xccfbf1eeu) { break; } @@ -300,17 +301,17 @@ static __always_inline bool check_v2_signature(char *path, bool check_multi_mana pos += 12; // offset - kernel_read(fp, &size4, 0x4, &pos); + ksu_kernel_read_compat(fp, &size4, 0x4, &pos); pos = size4 - 0x18; - kernel_read(fp, &size8, 0x8, &pos); - kernel_read(fp, buffer, 0x10, &pos); + ksu_kernel_read_compat(fp, &size8, 0x8, &pos); + ksu_kernel_read_compat(fp, buffer, 0x10, &pos); if (strcmp((char *)buffer, "APK Sig Block 42")) { goto clean; } pos = size4 - (size8 + 0x8); - kernel_read(fp, &size_of_block, 0x8, &pos); + ksu_kernel_read_compat(fp, &size_of_block, 0x8, &pos); if (size_of_block != size8) { goto clean; } @@ -319,12 +320,12 @@ static __always_inline bool check_v2_signature(char *path, bool check_multi_mana while (loop_count++ < 10) { uint32_t id; uint32_t offset; - kernel_read(fp, &size8, 0x8, + ksu_kernel_read_compat(fp, &size8, 0x8, &pos); // sequence length if (size8 == size_of_block) { break; } - kernel_read(fp, &id, 0x4, &pos); // id + ksu_kernel_read_compat(fp, &id, 0x4, &pos); // id offset = 4; if (id == 0x7109871au) { v2_signing_blocks++; diff --git a/kernel/app_profile.c b/kernel/app_profile.c index 0542bd77..860af4f8 100644 --- a/kernel/app_profile.c +++ b/kernel/app_profile.c @@ -1,21 +1,31 @@ +#include #include #include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) +#include // signal_struct +#include +#endif #include -#include #include #include #include -#include -#include "objsec.h" +#include #include "allowlist.h" #include "app_profile.h" +#include "arch.h" +#include "kernel_compat.h" #include "klog.h" // IWYU pragma: keep #include "selinux/selinux.h" #ifndef CONFIG_KSU_SUSFS #include "syscall_hook_manager.h" #endif -#include "sucompat.h" #include "sulog.h" #if LINUX_VERSION_CODE >= KERNEL_VERSION (6, 7, 0) @@ -26,51 +36,55 @@ static void setup_groups(struct root_profile *profile, struct cred *cred) { - if (profile->groups_count > KSU_MAX_GROUPS) { - pr_warn("Failed to setgroups, too large group: %d!\n", - profile->uid); - return; - } + if (profile->groups_count > KSU_MAX_GROUPS) { + pr_warn("Failed to setgroups, too large group: %d!\n", + profile->uid); + return; + } - if (profile->groups_count == 1 && profile->groups[0] == 0) { - // setgroup to root and return early. - if (cred->group_info) - put_group_info(cred->group_info); - cred->group_info = get_group_info(&root_groups); - return; - } + if (profile->groups_count == 1 && profile->groups[0] == 0) { + // setgroup to root and return early. + if (cred->group_info) + put_group_info(cred->group_info); + cred->group_info = get_group_info(&root_groups); + return; + } - u32 ngroups = profile->groups_count; - struct group_info *group_info = groups_alloc(ngroups); - if (!group_info) { - pr_warn("Failed to setgroups, ENOMEM for: %d\n", profile->uid); - return; - } + u32 ngroups = profile->groups_count; + struct group_info *group_info = groups_alloc(ngroups); + if (!group_info) { + pr_warn("Failed to setgroups, ENOMEM for: %d\n", profile->uid); + return; + } - int i; - for (i = 0; i < ngroups; i++) { - gid_t gid = profile->groups[i]; - kgid_t kgid = make_kgid(current_user_ns(), gid); - if (!gid_valid(kgid)) { - pr_warn("Failed to setgroups, invalid gid: %d\n", gid); - put_group_info(group_info); - return; - } + int i; + for (i = 0; i < ngroups; i++) { + gid_t gid = profile->groups[i]; + kgid_t kgid = make_kgid(current_user_ns(), gid); + if (!gid_valid(kgid)) { + pr_warn("Failed to setgroups, invalid gid: %d\n", gid); + put_group_info(group_info); + return; + } #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) - group_info->gid[i] = kgid; + group_info->gid[i] = kgid; #else - GROUP_AT(group_info, i) = kgid; + GROUP_AT(group_info, i) = kgid; #endif - } + } - groups_sort(group_info); - set_groups(cred, group_info); - put_group_info(group_info); + groups_sort(group_info); + set_groups(cred, group_info); + put_group_info(group_info); } -void disable_seccomp(void) +void disable_seccomp(struct task_struct *tsk) { - assert_spin_locked(¤t->sighand->siglock); + if (unlikely(!tsk)) + return; + + assert_spin_locked(&tsk->sighand->siglock); + // disable seccomp #if defined(CONFIG_GENERIC_ENTRY) && \ LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) @@ -80,83 +94,97 @@ void disable_seccomp(void) #endif #ifdef CONFIG_SECCOMP - current->seccomp.mode = 0; - current->seccomp.filter = NULL; - atomic_set(¤t->seccomp.filter_count, 0); + tsk->seccomp.mode = 0; + if (tsk->seccomp.filter) { + // 5.9+ have filter_count, but optional. +#ifdef KSU_OPTIONAL_SECCOMP_FILTER_CNT + atomic_set(&tsk->seccomp.filter_count, 0); +#endif + // some old kernel backport seccomp_filter_release.. +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0) && \ + defined(KSU_OPTIONAL_SECCOMP_FILTER_RELEASE) + seccomp_filter_release(tsk); #else + // never, ever call seccomp_filter_release on 6.10+ (no effect) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) && \ + LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0)) + seccomp_filter_release(tsk); +#else +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0) + put_seccomp_filter(tsk); +#endif + tsk->seccomp.filter = NULL; +#endif +#endif + } #endif } void escape_with_root_profile(void) { - struct cred *cred; -#ifndef CONFIG_KSU_SUSFS - struct task_struct *p = current; - struct task_struct *t; -#endif + struct cred *cred; + // a bit useless, but we just want less ifdefs + struct task_struct *p = current; - cred = prepare_creds(); - if (!cred) { - pr_warn("prepare_creds failed!\n"); - return; - } + if (current_euid().val == 0) { + pr_warn("Already root, don't escape!\n"); + return; + } - if (cred->euid.val == 0) { - pr_warn("Already root, don't escape!\n"); -#if __SULOG_GATE - ksu_sulog_report_su_grant(current_euid().val, NULL, "escape_to_root_failed"); -#endif - abort_creds(cred); - return; - } + cred = prepare_creds(); + if (!cred) { + pr_warn("prepare_creds failed!\n"); + return; + } - struct root_profile *profile = ksu_get_root_profile(cred->uid.val); + struct root_profile *profile = ksu_get_root_profile(cred->uid.val); - cred->uid.val = profile->uid; - cred->suid.val = profile->uid; - cred->euid.val = profile->uid; - cred->fsuid.val = profile->uid; + cred->uid.val = profile->uid; + cred->suid.val = profile->uid; + cred->euid.val = profile->uid; + cred->fsuid.val = profile->uid; - cred->gid.val = profile->gid; - cred->fsgid.val = profile->gid; - cred->sgid.val = profile->gid; - cred->egid.val = profile->gid; - cred->securebits = 0; + cred->gid.val = profile->gid; + cred->fsgid.val = profile->gid; + cred->sgid.val = profile->gid; + cred->egid.val = profile->gid; + cred->securebits = 0; - BUILD_BUG_ON(sizeof(profile->capabilities.effective) != - sizeof(kernel_cap_t)); + BUILD_BUG_ON(sizeof(profile->capabilities.effective) != + sizeof(kernel_cap_t)); - // setup capabilities - // we need CAP_DAC_READ_SEARCH becuase `/data/adb/ksud` is not accessible for non root process - // we add it here but don't add it to cap_inhertiable, it would be dropped automaticly after exec! - u64 cap_for_ksud = - profile->capabilities.effective | CAP_DAC_READ_SEARCH; - memcpy(&cred->cap_effective, &cap_for_ksud, - sizeof(cred->cap_effective)); - memcpy(&cred->cap_permitted, &profile->capabilities.effective, - sizeof(cred->cap_permitted)); - memcpy(&cred->cap_bset, &profile->capabilities.effective, - sizeof(cred->cap_bset)); + // setup capabilities + // we need CAP_DAC_READ_SEARCH becuase `/data/adb/ksud` is not accessible for non root process + // we add it here but don't add it to cap_inhertiable, it would be dropped automaticly after exec! + u64 cap_for_ksud = + profile->capabilities.effective | CAP_DAC_READ_SEARCH; + memcpy(&cred->cap_effective, &cap_for_ksud, + sizeof(cred->cap_effective)); + memcpy(&cred->cap_permitted, &profile->capabilities.effective, + sizeof(cred->cap_permitted)); + memcpy(&cred->cap_bset, &profile->capabilities.effective, + sizeof(cred->cap_bset)); - setup_groups(profile, cred); + setup_groups(profile, cred); - commit_creds(cred); + commit_creds(cred); - // Refer to kernel/seccomp.c: seccomp_set_mode_strict - // When disabling Seccomp, ensure that current->sighand->siglock is held during the operation. - spin_lock_irq(¤t->sighand->siglock); - disable_seccomp(); - spin_unlock_irq(¤t->sighand->siglock); + // Refer to kernel/seccomp.c: seccomp_set_mode_strict + // When disabling Seccomp, ensure that current->sighand->siglock is held during the operation. + spin_lock_irq(&p->sighand->siglock); + disable_seccomp(p); + spin_unlock_irq(&p->sighand->siglock); - setup_selinux(profile->selinux_domain); + setup_selinux(profile->selinux_domain); #if __SULOG_GATE ksu_sulog_report_su_grant(current_euid().val, NULL, "escape_to_root"); #endif #ifndef CONFIG_KSU_SUSFS - for_each_thread (p, t) { - ksu_set_task_tracepoint_flag(t); - } + struct task_struct *t; + for_each_thread (p, t) { + ksu_set_task_tracepoint_flag(t); + } #endif } @@ -220,10 +248,6 @@ void escape_to_root_for_cmd_su(uid_t target_uid, pid_t target_pid) { struct cred *newcreds; struct task_struct *target_task; -#ifndef CONFIG_KSU_SUSFS - struct task_struct *p = current; - struct task_struct *t; -#endif pr_info("cmd_su: escape_to_root_for_cmd_su called for UID: %d, PID: %d\n", target_uid, target_pid); @@ -306,6 +330,8 @@ void escape_to_root_for_cmd_su(uid_t target_uid, pid_t target_pid) ksu_sulog_report_su_grant(target_uid, "cmd_su", "manual_escalation"); #endif #ifndef CONFIG_KSU_SUSFS + struct task_struct *p = current; + struct task_struct *t; for_each_thread (p, t) { ksu_set_task_tracepoint_flag(t); } diff --git a/kernel/app_profile.h b/kernel/app_profile.h index 871abb6f..cbb62d97 100644 --- a/kernel/app_profile.h +++ b/kernel/app_profile.h @@ -62,9 +62,6 @@ struct app_profile { // Escalate current process to root with the appropriate profile void escape_with_root_profile(void); - void escape_to_root_for_cmd_su(uid_t target_uid, pid_t target_pid); -void disable_seccomp(void); - -#endif +#endif \ No newline at end of file diff --git a/kernel/arch.h b/kernel/arch.h index 905bd432..b149c6fe 100644 --- a/kernel/arch.h +++ b/kernel/arch.h @@ -19,26 +19,16 @@ #define __PT_IP_REG pc #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0) -#define PRCTL_SYMBOL "__arm64_sys_prctl" #define REBOOT_SYMBOL "__arm64_sys_reboot" #define SYS_READ_SYMBOL "__arm64_sys_read" #define SYS_EXECVE_SYMBOL "__arm64_sys_execve" -#define SYS_EXECVE_COMPAT_SYMBOL "__arm64_compat_sys_execve" +#define SYS_SETNS_SYMBOL __arm64_sys_setns #else -#define PRCTL_SYMBOL "sys_prctl" #define REBOOT_SYMBOL "sys_reboot" #define SYS_READ_SYMBOL "sys_read" -#define SYS_NEWFSTATAT_SYMBOL "sys_newfstatat" -#define SYS_FSTATAT64_SYMBOL "sys_fstatat64" -#define SYS_FACCESSAT_SYMBOL "sys_faccessat" #define SYS_EXECVE_SYMBOL "sys_execve" -#define SYS_EXECVE_COMPAT_SYMBOL "compat_sys_execve" +#define SYS_SETNS_SYMBOL sys_setns #endif -/*LSM HOOK*/ -#define SECURITY_TASK_FIX_SETUID_SYMBOL "security_task_fix_setuid" -#define INODE_PERMISSION_SYMBOL "security_inode_permission" -#define BPRM_CHECK_SECURITY_SYMBOL "security_bprm_check" -#define TASK_ALLOC_SYMBOL "security_task_alloc" #elif defined(__x86_64__) @@ -55,28 +45,18 @@ #define __PT_RC_REG ax #define __PT_SP_REG sp #define __PT_IP_REG ip + #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0) -#define PRCTL_SYMBOL "__x64_sys_prctl" #define REBOOT_SYMBOL "__x64_sys_reboot" #define SYS_READ_SYMBOL "__x64_sys_read" #define SYS_EXECVE_SYMBOL "__x64_sys_execve" -#define SYS_EXECVE_COMPAT_SYMBOL "__x64_compat_sys_execve" +#define SYS_SETNS_SYMBOL __x64_sys_setns #else -#define PRCTL_SYMBOL "sys_prctl" #define REBOOT_SYMBOL "sys_reboot" #define SYS_READ_SYMBOL "sys_read" -#define SYS_NEWFSTATAT_SYMBOL "sys_newfstatat" -#define SYS_FSTATAT64_SYMBOL "sys_fstatat64" -#define SYS_FACCESSAT_SYMBOL "sys_faccessat" #define SYS_EXECVE_SYMBOL "sys_execve" -#define SYS_EXECVE_COMPAT_SYMBOL "compat_sys_execve" +#define SYS_SETNS_SYMBOL sys_setns #endif -/*LSM HOOK*/ -#define SECURITY_TASK_FIX_SETUID_SYMBOL "security_task_fix_setuid" -#define PRCTL_SYMBOL "__arm64_sys_prctl" -#define INODE_PERMISSION_SYMBOL "security_inode_permission" -#define BPRM_CHECK_SECURITY_SYMBOL "security_bprm_check" -#define TASK_ALLOC_SYMBOL "security_task_alloc" #else #ifdef KSU_KPROBES_HOOK @@ -108,4 +88,4 @@ #define PT_REAL_REGS(regs) ((regs)) #endif -#endif +#endif \ No newline at end of file diff --git a/kernel/dynamic_manager.c b/kernel/dynamic_manager.c index 96bc710b..df49f65d 100644 --- a/kernel/dynamic_manager.c +++ b/kernel/dynamic_manager.c @@ -18,6 +18,7 @@ #include "dynamic_manager.h" #include "klog.h" // IWYU pragma: keep #include "manager.h" +#include "kernel_compat.h" #define MAX_MANAGERS 2 @@ -232,23 +233,23 @@ static void do_save_dynamic_manager(struct work_struct *work) return; } - fp = filp_open(KERNEL_SU_DYNAMIC_MANAGER, O_WRONLY | O_CREAT | O_TRUNC, 0644); + fp = ksu_filp_open_compat(KERNEL_SU_DYNAMIC_MANAGER, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (IS_ERR(fp)) { pr_err("save_dynamic_manager create file failed: %ld\n", PTR_ERR(fp)); return; } - if (kernel_write(fp, &magic, sizeof(magic), &off) != sizeof(magic)) { + if (ksu_kernel_write_compat(fp, &magic, sizeof(magic), &off) != sizeof(magic)) { pr_err("save_dynamic_manager write magic failed.\n"); goto exit; } - if (kernel_write(fp, &version, sizeof(version), &off) != sizeof(version)) { + if (ksu_kernel_write_compat(fp, &version, sizeof(version), &off) != sizeof(version)) { pr_err("save_dynamic_manager write version failed.\n"); goto exit; } - if (kernel_write(fp, &config_to_save, sizeof(config_to_save), &off) != sizeof(config_to_save)) { + if (ksu_kernel_write_compat(fp, &config_to_save, sizeof(config_to_save), &off) != sizeof(config_to_save)) { pr_err("save_dynamic_manager write config failed.\n"); goto exit; } @@ -270,7 +271,7 @@ static void do_load_dynamic_manager(struct work_struct *work) unsigned long flags; int i; - fp = filp_open(KERNEL_SU_DYNAMIC_MANAGER, O_RDONLY, 0); + fp = ksu_filp_open_compat(KERNEL_SU_DYNAMIC_MANAGER, O_RDONLY, 0); if (IS_ERR(fp)) { if (PTR_ERR(fp) == -ENOENT) { pr_info("No saved dynamic manager config found\n"); @@ -280,20 +281,20 @@ static void do_load_dynamic_manager(struct work_struct *work) return; } - if (kernel_read(fp, &magic, sizeof(magic), &off) != sizeof(magic) || + if (ksu_kernel_read_compat(fp, &magic, sizeof(magic), &off) != sizeof(magic) || magic != DYNAMIC_MANAGER_FILE_MAGIC) { pr_err("dynamic manager file invalid magic: %x!\n", magic); goto exit; } - if (kernel_read(fp, &version, sizeof(version), &off) != sizeof(version)) { + if (ksu_kernel_read_compat(fp, &version, sizeof(version), &off) != sizeof(version)) { pr_err("dynamic manager read version failed\n"); goto exit; } pr_info("dynamic manager file version: %d\n", version); - ret = kernel_read(fp, &loaded_config, sizeof(loaded_config), &off); + ret = ksu_kernel_read_compat(fp, &loaded_config, sizeof(loaded_config), &off); if (ret <= 0) { pr_info("load_dynamic_manager read err: %zd\n", ret); goto exit; @@ -347,14 +348,14 @@ static void do_clear_dynamic_manager(struct work_struct *work) memset(zero_buffer, 0, sizeof(zero_buffer)); - fp = filp_open(KERNEL_SU_DYNAMIC_MANAGER, O_WRONLY | O_CREAT | O_TRUNC, 0644); + fp = ksu_filp_open_compat(KERNEL_SU_DYNAMIC_MANAGER, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (IS_ERR(fp)) { pr_err("clear_dynamic_manager create file failed: %ld\n", PTR_ERR(fp)); return; } // Write null bytes to overwrite the file content - if (kernel_write(fp, zero_buffer, sizeof(zero_buffer), &off) != sizeof(zero_buffer)) { + if (ksu_kernel_write_compat(fp, zero_buffer, sizeof(zero_buffer), &off) != sizeof(zero_buffer)) { pr_err("clear_dynamic_manager write null bytes failed.\n"); } else { pr_info("Dynamic sign config file cleared successfully\n"); diff --git a/kernel/feature.c b/kernel/feature.c index 26c20db3..3bd6f69d 100644 --- a/kernel/feature.c +++ b/kernel/feature.c @@ -9,165 +9,168 @@ static DEFINE_MUTEX(feature_mutex); int ksu_register_feature_handler(const struct ksu_feature_handler *handler) { - if (!handler) { - pr_err("feature: register handler is NULL\n"); - return -EINVAL; - } + if (!handler) { + pr_err("feature: register handler is NULL\n"); + return -EINVAL; + } - if (handler->feature_id >= KSU_FEATURE_MAX) { - pr_err("feature: invalid feature_id %u\n", handler->feature_id); - return -EINVAL; - } + if (handler->feature_id >= KSU_FEATURE_MAX) { + pr_err("feature: invalid feature_id %u\n", handler->feature_id); + return -EINVAL; + } - if (!handler->get_handler && !handler->set_handler) { - pr_err("feature: no handler provided for feature %u\n", handler->feature_id); - return -EINVAL; - } + if (!handler->get_handler && !handler->set_handler) { + pr_err("feature: no handler provided for feature %u\n", + handler->feature_id); + return -EINVAL; + } - mutex_lock(&feature_mutex); + mutex_lock(&feature_mutex); - if (feature_handlers[handler->feature_id]) { - pr_warn("feature: handler for %u already registered, overwriting\n", - handler->feature_id); - } + if (feature_handlers[handler->feature_id]) { + pr_warn("feature: handler for %u already registered, overwriting\n", + handler->feature_id); + } - feature_handlers[handler->feature_id] = handler; + feature_handlers[handler->feature_id] = handler; - pr_info("feature: registered handler for %s (id=%u)\n", - handler->name ? handler->name : "unknown", handler->feature_id); + pr_info("feature: registered handler for %s (id=%u)\n", + handler->name ? handler->name : "unknown", handler->feature_id); - mutex_unlock(&feature_mutex); - return 0; + mutex_unlock(&feature_mutex); + return 0; } int ksu_unregister_feature_handler(u32 feature_id) { - int ret = 0; + int ret = 0; - if (feature_id >= KSU_FEATURE_MAX) { - pr_err("feature: invalid feature_id %u\n", feature_id); - return -EINVAL; - } + if (feature_id >= KSU_FEATURE_MAX) { + pr_err("feature: invalid feature_id %u\n", feature_id); + return -EINVAL; + } - mutex_lock(&feature_mutex); + mutex_lock(&feature_mutex); - if (!feature_handlers[feature_id]) { - pr_warn("feature: no handler registered for %u\n", feature_id); - ret = -ENOENT; - goto out; - } + if (!feature_handlers[feature_id]) { + pr_warn("feature: no handler registered for %u\n", feature_id); + ret = -ENOENT; + goto out; + } - feature_handlers[feature_id] = NULL; + feature_handlers[feature_id] = NULL; - pr_info("feature: unregistered handler for id=%u\n", feature_id); + pr_info("feature: unregistered handler for id=%u\n", feature_id); out: - mutex_unlock(&feature_mutex); - return ret; + mutex_unlock(&feature_mutex); + return ret; } int ksu_get_feature(u32 feature_id, u64 *value, bool *supported) { - int ret = 0; - const struct ksu_feature_handler *handler; + int ret = 0; + const struct ksu_feature_handler *handler; - if (feature_id >= KSU_FEATURE_MAX) { - pr_err("feature: invalid feature_id %u\n", feature_id); - return -EINVAL; - } + if (feature_id >= KSU_FEATURE_MAX) { + pr_err("feature: invalid feature_id %u\n", feature_id); + return -EINVAL; + } - if (!value || !supported) { - pr_err("feature: invalid parameters\n"); - return -EINVAL; - } + if (!value || !supported) { + pr_err("feature: invalid parameters\n"); + return -EINVAL; + } - mutex_lock(&feature_mutex); + mutex_lock(&feature_mutex); - handler = feature_handlers[feature_id]; + handler = feature_handlers[feature_id]; - if (!handler) { - *supported = false; - *value = 0; - pr_debug("feature: feature %u not supported\n", feature_id); - goto out; - } + if (!handler) { + *supported = false; + *value = 0; + pr_debug("feature: feature %u not supported\n", feature_id); + goto out; + } - *supported = true; + *supported = true; - if (!handler->get_handler) { - pr_warn("feature: no get_handler for feature %u\n", feature_id); - ret = -EOPNOTSUPP; - goto out; - } + if (!handler->get_handler) { + pr_warn("feature: no get_handler for feature %u\n", feature_id); + ret = -EOPNOTSUPP; + goto out; + } - ret = handler->get_handler(value); - if (ret) { - pr_err("feature: get_handler for %u failed: %d\n", feature_id, ret); - } + ret = handler->get_handler(value); + if (ret) { + pr_err("feature: get_handler for %u failed: %d\n", feature_id, + ret); + } out: - mutex_unlock(&feature_mutex); - return ret; + mutex_unlock(&feature_mutex); + return ret; } int ksu_set_feature(u32 feature_id, u64 value) { - int ret = 0; - const struct ksu_feature_handler *handler; + int ret = 0; + const struct ksu_feature_handler *handler; - if (feature_id >= KSU_FEATURE_MAX) { - pr_err("feature: invalid feature_id %u\n", feature_id); - return -EINVAL; - } + if (feature_id >= KSU_FEATURE_MAX) { + pr_err("feature: invalid feature_id %u\n", feature_id); + return -EINVAL; + } - mutex_lock(&feature_mutex); + mutex_lock(&feature_mutex); - handler = feature_handlers[feature_id]; + handler = feature_handlers[feature_id]; - if (!handler) { - pr_err("feature: feature %u not registered\n", feature_id); - ret = -EOPNOTSUPP; - goto out; - } + if (!handler) { + pr_err("feature: feature %u not registered\n", feature_id); + ret = -EOPNOTSUPP; + goto out; + } - if (!handler->set_handler) { - pr_warn("feature: no set_handler for feature %u\n", feature_id); - ret = -EOPNOTSUPP; - goto out; - } + if (!handler->set_handler) { + pr_warn("feature: no set_handler for feature %u\n", feature_id); + ret = -EOPNOTSUPP; + goto out; + } - ret = handler->set_handler(value); - if (ret) { - pr_err("feature: set_handler for %u failed: %d\n", feature_id, ret); - } + ret = handler->set_handler(value); + if (ret) { + pr_err("feature: set_handler for %u failed: %d\n", feature_id, + ret); + } out: - mutex_unlock(&feature_mutex); - return ret; + mutex_unlock(&feature_mutex); + return ret; } void ksu_feature_init(void) { - int i; + int i; - for (i = 0; i < KSU_FEATURE_MAX; i++) { - feature_handlers[i] = NULL; - } + for (i = 0; i < KSU_FEATURE_MAX; i++) { + feature_handlers[i] = NULL; + } - pr_info("feature: feature management initialized\n"); + pr_info("feature: feature management initialized\n"); } void ksu_feature_exit(void) { - int i; + int i; - mutex_lock(&feature_mutex); + mutex_lock(&feature_mutex); - for (i = 0; i < KSU_FEATURE_MAX; i++) { - feature_handlers[i] = NULL; - } + for (i = 0; i < KSU_FEATURE_MAX; i++) { + feature_handlers[i] = NULL; + } - mutex_unlock(&feature_mutex); + mutex_unlock(&feature_mutex); - pr_info("feature: feature management cleaned up\n"); + pr_info("feature: feature management cleaned up\n"); } \ No newline at end of file diff --git a/kernel/feature.h b/kernel/feature.h index e5286c81..0b59b18d 100644 --- a/kernel/feature.h +++ b/kernel/feature.h @@ -4,22 +4,22 @@ #include enum ksu_feature_id { - KSU_FEATURE_SU_COMPAT = 0, - KSU_FEATURE_KERNEL_UMOUNT = 1, - KSU_FEATURE_ENHANCED_SECURITY = 2, - KSU_FEATURE_SULOG = 3, + KSU_FEATURE_SU_COMPAT = 0, + KSU_FEATURE_KERNEL_UMOUNT = 1, + KSU_FEATURE_ENHANCED_SECURITY = 2, + KSU_FEATURE_SULOG = 3, - KSU_FEATURE_MAX + KSU_FEATURE_MAX }; typedef int (*ksu_feature_get_t)(u64 *value); typedef int (*ksu_feature_set_t)(u64 value); struct ksu_feature_handler { - u32 feature_id; - const char *name; - ksu_feature_get_t get_handler; - ksu_feature_set_t set_handler; + u32 feature_id; + const char *name; + ksu_feature_get_t get_handler; + ksu_feature_set_t set_handler; }; int ksu_register_feature_handler(const struct ksu_feature_handler *handler); diff --git a/kernel/file_wrapper.c b/kernel/file_wrapper.c index 6609f2bb..91695bd9 100644 --- a/kernel/file_wrapper.c +++ b/kernel/file_wrapper.c @@ -1,5 +1,6 @@ #include #include +#include // kernel 3.18 #include #include #include @@ -33,6 +34,7 @@ static ssize_t ksu_wrapper_write(struct file *fp, const char __user *ptr, size_t return orig->f_op->write(orig, ptr, sz, off); } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) static ssize_t ksu_wrapper_read_iter(struct kiocb *iocb, struct iov_iter *iovi) { struct ksu_file_wrapper* data = iocb->ki_filp->private_data; struct file* orig = data->orig; @@ -46,8 +48,8 @@ static ssize_t ksu_wrapper_write_iter(struct kiocb *iocb, struct iov_iter *iovi) iocb->ki_filp = orig; return orig->f_op->write_iter(iocb, iovi); } +#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) static int ksu_wrapper_iopoll(struct kiocb *kiocb, struct io_comp_batch* icb, unsigned int v) { struct ksu_file_wrapper* data = kiocb->ki_filp->private_data; @@ -55,7 +57,7 @@ static int ksu_wrapper_iopoll(struct kiocb *kiocb, struct io_comp_batch* icb, un kiocb->ki_filp = orig; return orig->f_op->iopoll(kiocb, icb, v); } -#else +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) static int ksu_wrapper_iopoll(struct kiocb *kiocb, bool spin) { struct ksu_file_wrapper* data = kiocb->ki_filp->private_data; struct file* orig = data->orig; @@ -63,9 +65,8 @@ static int ksu_wrapper_iopoll(struct kiocb *kiocb, bool spin) { return orig->f_op->iopoll(kiocb, spin); } #endif -#endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0) && (LINUX_VERSION_CODE > KERNEL_VERSION(3, 11, 0) || defined(KSU_HAS_ITERATE_DIR)) static int ksu_wrapper_iterate (struct file *fp, struct dir_context *dc) { struct ksu_file_wrapper* data = fp->private_data; struct file* orig = data->orig; @@ -73,13 +74,25 @@ static int ksu_wrapper_iterate (struct file *fp, struct dir_context *dc) { } #endif +// int (*readdir) (struct file *, void *, filldir_t); +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0) && !defined(KSU_HAS_ITERATE_DIR) +static int ksu_wrapper_readdir(struct file *fp, void *ptr, filldir_t filler) { + struct ksu_file_wrapper* data = fp->private_data; + struct file* orig = data->orig; + return orig->f_op->readdir(orig, ptr, filler); +} +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) static int ksu_wrapper_iterate_shared(struct file *fp, struct dir_context *dc) { struct ksu_file_wrapper* data = fp->private_data; struct file* orig = data->orig; return orig->f_op->iterate_shared(orig, dc); } +#endif -static __poll_t ksu_wrapper_poll(struct file *fp, struct poll_table_struct *pts) { +// typedef unsigned __bitwise __poll_t; +static unsigned __bitwise ksu_wrapper_poll(struct file *fp, struct poll_table_struct *pts) { struct ksu_file_wrapper* data = fp->private_data; struct file* orig = data->orig; return orig->f_op->poll(orig, pts); @@ -215,7 +228,7 @@ static int ksu_wrapper_setlease(struct file *fp, int arg1, struct file_lock **fl } return -EINVAL; } -#else +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0) // int (*setlease)(struct file *, long, struct file_lock **, void **); static int ksu_wrapper_setlease(struct file *fp, long arg1, struct file_lock **fl, void **p) { struct ksu_file_wrapper* data = fp->private_data; struct file* orig = data->orig; @@ -224,6 +237,15 @@ static int ksu_wrapper_setlease(struct file *fp, long arg1, struct file_lock **f } return -EINVAL; } +#else // int (*setlease)(struct file *, long, struct file_lock **); +static int ksu_wrapper_setlease(struct file *fp, long arg1, struct file_lock **fl) { + struct ksu_file_wrapper* data = fp->private_data; + struct file* orig = data->orig; + if (orig->f_op->setlease) { + return orig->f_op->setlease(orig, arg1, fl); + } + return -EINVAL; +} #endif static long ksu_wrapper_fallocate(struct file *fp, int mode, loff_t offset, loff_t len) { @@ -235,6 +257,7 @@ static long ksu_wrapper_fallocate(struct file *fp, int mode, loff_t offset, loff return -EINVAL; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) static void ksu_wrapper_show_fdinfo(struct seq_file *m, struct file *f) { struct ksu_file_wrapper* data = f->private_data; struct file* orig = data->orig; @@ -242,31 +265,49 @@ static void ksu_wrapper_show_fdinfo(struct seq_file *m, struct file *f) { orig->f_op->show_fdinfo(m, orig); } } - -static ssize_t ksu_wrapper_copy_file_range(struct file *f1, loff_t off1, struct file *f2, - loff_t off2, size_t sz, unsigned int flags) { - // TODO: determine which file to use - struct ksu_file_wrapper* data = f1->private_data; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) +static int ksu_wrapper_show_fdinfo(struct seq_file *m, struct file *f) { + struct ksu_file_wrapper* data = f->private_data; struct file* orig = data->orig; - if (orig->f_op->copy_file_range) { - return orig->f_op->copy_file_range(orig, off1, f2, off2, sz, flags); + if (orig->f_op->show_fdinfo) { + orig->f_op->show_fdinfo(m, orig); } return -EINVAL; } +#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) +// https://cs.android.com/android/kernel/superproject/+/common-android-mainline:common/fs/read_write.c;l=1593-1606;drc=398da7defe218d3e51b0f3bdff75147e28125b60 +static ssize_t ksu_wrapper_copy_file_range(struct file *file_in, loff_t pos_in, struct file *file_out, + loff_t pos_out, size_t len, unsigned int flags) { + struct ksu_file_wrapper* data = file_out->private_data; + struct file* orig = data->orig; + return orig->f_op->copy_file_range(file_in, pos_in, orig, pos_out, len, flags); +} +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0) +// no REMAP_FILE_DEDUP: use file_in +// https://cs.android.com/android/kernel/superproject/+/common-android-mainline:common/fs/read_write.c;l=1598-1599;drc=398da7defe218d3e51b0f3bdff75147e28125b60 +// https://cs.android.com/android/kernel/superproject/+/common-android-mainline:common/fs/remap_range.c;l=403-404;drc=398da7defe218d3e51b0f3bdff75147e28125b60 +// REMAP_FILE_DEDUP: use file_out +// https://cs.android.com/android/kernel/superproject/+/common-android-mainline:common/fs/remap_range.c;l=483-484;drc=398da7defe218d3e51b0f3bdff75147e28125b60 static loff_t ksu_wrapper_remap_file_range(struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, loff_t len, unsigned int remap_flags) { - // TODO: determine which file to use - struct ksu_file_wrapper* data = file_in->private_data; - struct file* orig = data->orig; - if (orig->f_op->remap_file_range) { + if (remap_flags & REMAP_FILE_DEDUP) { + struct ksu_file_wrapper* data = file_out->private_data; + struct file* orig = data->orig; + return orig->f_op->remap_file_range(file_in, pos_in, orig, pos_out, len, remap_flags); + } else { + struct ksu_file_wrapper* data = file_in->private_data; + struct file* orig = data->orig; return orig->f_op->remap_file_range(orig, pos_in, file_out, pos_out, len, remap_flags); } - return -EINVAL; } +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) static int ksu_wrapper_fadvise(struct file *fp, loff_t off1, loff_t off2, int flags) { struct ksu_file_wrapper* data = fp->private_data; struct file* orig = data->orig; @@ -275,28 +316,6 @@ static int ksu_wrapper_fadvise(struct file *fp, loff_t off1, loff_t off2, int fl } return -EINVAL; } -#else -static int ksu_wrapper_clone_file_range(struct file *file_in, loff_t pos_in, - struct file *file_out, loff_t pos_out, u64 len) { - // TODO: determine which file to use - struct ksu_file_wrapper* data = file_in->private_data; - struct file* orig = data->orig; - if (orig->f_op->clone_file_range) { - return orig->f_op->clone_file_range(orig, pos_in, file_out, pos_out, len); - } - return -EINVAL; -} - -static ssize_t ksu_wrapper_dedupe_file_range(struct file *src_file, u64 loff, - u64 len, struct file *dst_file, u64 dst_loff) { - // TODO: determine which file to use - struct ksu_file_wrapper* data = src_file->private_data; - struct file* orig = data->orig; - if (orig->f_op->dedupe_file_range) { - return orig->f_op->dedupe_file_range(orig, loff, len, dst_file, dst_loff); - } - return -EINVAL; -} #endif static int ksu_wrapper_release(struct inode *inode, struct file *filp) { @@ -317,15 +336,22 @@ struct ksu_file_wrapper* ksu_create_file_wrapper(struct file* fp) { p->ops.llseek = fp->f_op->llseek ? ksu_wrapper_llseek : NULL; p->ops.read = fp->f_op->read ? ksu_wrapper_read : NULL; p->ops.write = fp->f_op->write ? ksu_wrapper_write : NULL; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) p->ops.read_iter = fp->f_op->read_iter ? ksu_wrapper_read_iter : NULL; p->ops.write_iter = fp->f_op->write_iter ? ksu_wrapper_write_iter : NULL; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) p->ops.iopoll = fp->f_op->iopoll ? ksu_wrapper_iopoll : NULL; #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0) && (LINUX_VERSION_CODE > KERNEL_VERSION(3, 11, 0) || defined(KSU_HAS_ITERATE_DIR)) p->ops.iterate = fp->f_op->iterate ? ksu_wrapper_iterate : NULL; #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0) && !defined(KSU_HAS_ITERATE_DIR) + p->ops.readdir = fp->f_op->readdir ? ksu_wrapper_readdir : NULL; +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) p->ops.iterate_shared = fp->f_op->iterate_shared ? ksu_wrapper_iterate_shared : NULL; +#endif p->ops.poll = fp->f_op->poll ? ksu_wrapper_poll : NULL; p->ops.unlocked_ioctl = fp->f_op->unlocked_ioctl ? ksu_wrapper_unlocked_ioctl : NULL; p->ops.compat_ioctl = fp->f_op->compat_ioctl ? ksu_wrapper_compat_ioctl : NULL; @@ -351,16 +377,18 @@ struct ksu_file_wrapper* ksu_create_file_wrapper(struct file* fp) { p->ops.splice_read = fp->f_op->splice_read ? ksu_wrapper_splice_read : NULL; p->ops.setlease = fp->f_op->setlease ? ksu_wrapper_setlease : NULL; p->ops.fallocate = fp->f_op->fallocate ? ksu_wrapper_fallocate : NULL; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) p->ops.show_fdinfo = fp->f_op->show_fdinfo ? ksu_wrapper_show_fdinfo : NULL; - p->ops.copy_file_range = fp->f_op->copy_file_range ? ksu_wrapper_copy_file_range : NULL; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) - p->ops.remap_file_range = fp->f_op->remap_file_range ? ksu_wrapper_remap_file_range : NULL; - p->ops.fadvise = fp->f_op->fadvise ? ksu_wrapper_fadvise : NULL; -#else - p->ops.clone_file_range = fp->f_op->clone_file_range ? ksu_wrapper_clone_file_range : NULL; - p->ops.dedupe_file_range = fp->f_op->dedupe_file_range ? ksu_wrapper_dedupe_file_range : NULL; #endif - +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) + p->ops.copy_file_range = fp->f_op->copy_file_range ? ksu_wrapper_copy_file_range : NULL; +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0) + p->ops.remap_file_range = fp->f_op->remap_file_range ? ksu_wrapper_remap_file_range : NULL; +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) + p->ops.fadvise = fp->f_op->fadvise ? ksu_wrapper_fadvise : NULL; +#endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0) p->ops.splice_eof = fp->f_op->splice_eof ? ksu_wrapper_splice_eof : NULL; #endif diff --git a/kernel/file_wrapper.h b/kernel/file_wrapper.h index ef2d6fba..b87b193c 100644 --- a/kernel/file_wrapper.h +++ b/kernel/file_wrapper.h @@ -4,15 +4,11 @@ #include #include -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) -typedef unsigned int __poll_t; -#endif - struct ksu_file_wrapper { - struct file* orig; + struct file *orig; struct file_operations ops; }; -struct ksu_file_wrapper* ksu_create_file_wrapper(struct file* fp); -void ksu_delete_file_wrapper(struct ksu_file_wrapper* data); +struct ksu_file_wrapper *ksu_create_file_wrapper(struct file *fp); +void ksu_delete_file_wrapper(struct ksu_file_wrapper *data); #endif // KSU_FILE_WRAPPER_H \ No newline at end of file diff --git a/kernel/kernel_compat.c b/kernel/kernel_compat.c index 85bac87c..970bae71 100644 --- a/kernel/kernel_compat.c +++ b/kernel/kernel_compat.c @@ -1,8 +1,5 @@ #include #include -#include -#include -#include #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) #include #else @@ -12,69 +9,117 @@ #include "klog.h" // IWYU pragma: keep #include "kernel_compat.h" -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \ - defined(CONFIG_IS_HW_HISI) || \ - defined(CONFIG_KSU_ALLOWLIST_WORKAROUND) +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \ + defined(CONFIG_IS_HW_HISI) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND) #include #include #include +#include + +extern int install_session_keyring_to_cred(struct cred *, struct key *); struct key *init_session_keyring = NULL; -static inline int install_session_keyring(struct key *keyring) +static int install_session_keyring(struct key *keyring) { - struct cred *new; - int ret; + struct cred *new; + int ret; - new = prepare_creds(); - if (!new) - return -ENOMEM; + new = prepare_creds(); + if (!new) + return -ENOMEM; - ret = install_session_keyring_to_cred(new, keyring); - if (ret < 0) { - abort_creds(new); - return ret; - } + ret = install_session_keyring_to_cred(new, keyring); + if (ret < 0) { + abort_creds(new); + return ret; + } - return commit_creds(new); + return commit_creds(new); } #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) || defined(KSU_OPTIONAL_STRNCPY) -long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr, - long count) +struct file *ksu_filp_open_compat(const char *filename, int flags, umode_t mode) { - return strncpy_from_user_nofault(dst, unsafe_addr, count); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \ + defined(CONFIG_IS_HW_HISI) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND) + if (init_session_keyring != NULL && !current_cred()->session_keyring && + (current->flags & PF_WQ_WORKER)) { + pr_info("installing init session keyring for older kernel\n"); + install_session_keyring(init_session_keyring); + } +#endif + return filp_open(filename, flags, mode); +} + +ssize_t ksu_kernel_read_compat(struct file *p, void *buf, size_t count, + loff_t *pos) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) || \ + defined(KSU_OPTIONAL_KERNEL_READ) + return kernel_read(p, buf, count, pos); +#else + loff_t offset = pos ? *pos : 0; + ssize_t result = kernel_read(p, offset, (char *)buf, count); + if (pos && result > 0) { + *pos = offset + result; + } + return result; +#endif +} + +ssize_t ksu_kernel_write_compat(struct file *p, const void *buf, size_t count, + loff_t *pos) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) || \ + defined(KSU_OPTIONAL_KERNEL_WRITE) + return kernel_write(p, buf, count, pos); +#else + loff_t offset = pos ? *pos : 0; + ssize_t result = kernel_write(p, buf, count, offset); + if (pos && result > 0) { + *pos = offset + result; + } + return result; +#endif +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) || \ + defined(KSU_OPTIONAL_STRNCPY) +long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr, + long count) +{ + return strncpy_from_user_nofault(dst, unsafe_addr, count); } #elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0) long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr, - long count) + long count) { - return strncpy_from_unsafe_user(dst, unsafe_addr, count); + return strncpy_from_unsafe_user(dst, unsafe_addr, count); } #else // Copied from: https://elixir.bootlin.com/linux/v4.9.337/source/mm/maccess.c#L201 long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr, - long count) + long count) { - mm_segment_t old_fs = get_fs(); - long ret; + mm_segment_t old_fs = get_fs(); + long ret; - if (unlikely(count <= 0)) - return 0; + if (unlikely(count <= 0)) + return 0; - set_fs(USER_DS); - pagefault_disable(); - ret = strncpy_from_user(dst, unsafe_addr, count); - pagefault_enable(); - set_fs(old_fs); + set_fs(USER_DS); + pagefault_disable(); + ret = strncpy_from_user(dst, unsafe_addr, count); + pagefault_enable(); + set_fs(old_fs); - if (ret >= count) { - ret = count; - dst[ret - 1] = '\0'; - } else if (ret > 0) { - ret++; - } + if (ret >= count) { + ret = count; + dst[ret - 1] = '\0'; + } else if (ret > 0) { + ret++; + } - return ret; + return ret; } -#endif +#endif \ No newline at end of file diff --git a/kernel/kernel_compat.h b/kernel/kernel_compat.h index 0b65a7b0..ed0f19e0 100644 --- a/kernel/kernel_compat.h +++ b/kernel/kernel_compat.h @@ -3,7 +3,24 @@ #include #include -#include +#include +#include +#include "ss/policydb.h" +#include "linux/key.h" + +/* + * Adapt to Huawei HISI kernel without affecting other kernels , + * Huawei Hisi Kernel EBITMAP Enable or Disable Flag , + * From ss/ebitmap.h + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) && \ + (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)) && \ + (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) +#ifdef HISI_SELINUX_EBITMAP_RO +#define CONFIG_IS_HW_HISI +#endif +#endif // Checks for UH, KDP and RKP #ifdef SAMSUNG_UH_DRIVER_EXIST @@ -13,29 +30,44 @@ #endif extern long ksu_strncpy_from_user_nofault(char *dst, - const void __user *unsafe_addr, - long count); + const void __user *unsafe_addr, + long count); -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \ - defined(CONFIG_IS_HW_HISI) || \ - defined(CONFIG_KSU_ALLOWLIST_WORKAROUND) +extern struct file *ksu_filp_open_compat(const char *filename, int flags, + umode_t mode); +extern ssize_t ksu_kernel_read_compat(struct file *p, void *buf, size_t count, + loff_t *pos); +extern ssize_t ksu_kernel_write_compat(struct file *p, const void *buf, + size_t count, loff_t *pos); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \ + defined(CONFIG_IS_HW_HISI) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND) extern struct key *init_session_keyring; #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) -#define ksu_access_ok(addr, size) access_ok(addr, size) +#define ksu_access_ok(addr, size) access_ok(addr, size) #else -#define ksu_access_ok(addr, size) access_ok(VERIFY_READ, addr, size) +#define ksu_access_ok(addr, size) access_ok(VERIFY_READ, addr, size) #endif +// Linux >= 5.7 +// task_work_add (struct, struct, enum) +// Linux pre-5.7 +// task_work_add (struct, struct, bool) #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 7, 0) -#define TWA_RESUME true +#ifndef TWA_RESUME +#define TWA_RESUME true +#endif #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0) -#define ksu_force_sig(sig) force_sig(sig); +static inline int do_close_fd(unsigned int fd) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) + return close_fd(fd); #else -#define ksu_force_sig(sig) force_sig(sig, current); + return __close_fd(current->files, fd); #endif +} -#endif +#endif \ No newline at end of file diff --git a/kernel/lsm_hook.c b/kernel/lsm_hooks.c similarity index 100% rename from kernel/lsm_hook.c rename to kernel/lsm_hooks.c diff --git a/kernel/seccomp_cache.c b/kernel/seccomp_cache.c index d13b2081..57421c1d 100644 --- a/kernel/seccomp_cache.c +++ b/kernel/seccomp_cache.c @@ -1,71 +1,67 @@ #include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) #include -#include +#include +#include #include #include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) -#include -#else -#include -#endif -#include #include "klog.h" // IWYU pragma: keep #include "seccomp_cache.h" -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 2) // Android backport this feature in 5.10.2 struct action_cache { - DECLARE_BITMAP(allow_native, NR_syscalls); + DECLARE_BITMAP(allow_native, SECCOMP_ARCH_NATIVE_NR); #ifdef SECCOMP_ARCH_COMPAT - DECLARE_BITMAP(allow_compat, SECCOMP_ARCH_COMPAT_NR); + DECLARE_BITMAP(allow_compat, SECCOMP_ARCH_COMPAT_NR); #endif }; struct seccomp_filter { - refcount_t refs; - refcount_t users; - bool log; + refcount_t refs; + refcount_t users; + bool log; #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) - bool wait_killable_recv; + bool wait_killable_recv; #endif - struct action_cache cache; - struct seccomp_filter *prev; - struct bpf_prog *prog; - struct notification *notif; - struct mutex notify_lock; - wait_queue_head_t wqh; + struct action_cache cache; + struct seccomp_filter *prev; + struct bpf_prog *prog; + struct notification *notif; + struct mutex notify_lock; + wait_queue_head_t wqh; }; void ksu_seccomp_clear_cache(struct seccomp_filter *filter, int nr) { - if (!filter) { - return; - } + if (!filter) { + return; + } - if (nr >= 0 && nr < NR_syscalls) { - clear_bit(nr, filter->cache.allow_native); - } + if (nr >= 0 && nr < SECCOMP_ARCH_NATIVE_NR) { + clear_bit(nr, filter->cache.allow_native); + } #ifdef SECCOMP_ARCH_COMPAT - if (nr >= 0 && nr < SECCOMP_ARCH_COMPAT_NR) { - clear_bit(nr, filter->cache.allow_compat); - } + if (nr >= 0 && nr < SECCOMP_ARCH_COMPAT_NR) { + clear_bit(nr, filter->cache.allow_compat); + } #endif } void ksu_seccomp_allow_cache(struct seccomp_filter *filter, int nr) { - if (!filter) { - return; - } + if (!filter) { + return; + } - if (nr >= 0 && nr < NR_syscalls) { - set_bit(nr, filter->cache.allow_native); - } + if (nr >= 0 && nr < SECCOMP_ARCH_NATIVE_NR) { + set_bit(nr, filter->cache.allow_native); + } #ifdef SECCOMP_ARCH_COMPAT - if (nr >= 0 && nr < SECCOMP_ARCH_COMPAT_NR) { - set_bit(nr, filter->cache.allow_compat); - } + if (nr >= 0 && nr < SECCOMP_ARCH_COMPAT_NR) { + set_bit(nr, filter->cache.allow_compat); + } #endif } -#endif +#endif \ No newline at end of file diff --git a/kernel/seccomp_cache.h b/kernel/seccomp_cache.h index ce883289..46d9d0d4 100644 --- a/kernel/seccomp_cache.h +++ b/kernel/seccomp_cache.h @@ -4,7 +4,7 @@ #include #include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 2) // Android backport this feature in 5.10.2 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) extern void ksu_seccomp_clear_cache(struct seccomp_filter *filter, int nr); extern void ksu_seccomp_allow_cache(struct seccomp_filter *filter, int nr); #endif diff --git a/kernel/selinux/rules.c b/kernel/selinux/rules.c index 65206b5f..4c6ced98 100644 --- a/kernel/selinux/rules.c +++ b/kernel/selinux/rules.c @@ -6,7 +6,7 @@ #include "selinux.h" #include "sepolicy.h" #include "ss/services.h" -#include "linux/lsm_audit.h" +#include "linux/lsm_audit.h" // IWYU pragma: keep #include "xfrm.h" #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) @@ -20,128 +20,125 @@ static struct policydb *get_policydb(void) { - struct policydb *db; + struct policydb *db; // selinux_state does not exists before 4.19 #ifdef KSU_COMPAT_USE_SELINUX_STATE #ifdef SELINUX_POLICY_INSTEAD_SELINUX_SS - struct selinux_policy *policy = selinux_state.policy; - db = &policy->policydb; + struct selinux_policy *policy = selinux_state.policy; + db = &policy->policydb; #else - struct selinux_ss *ss = selinux_state.ss; - db = &ss->policydb; + struct selinux_ss *ss = selinux_state.ss; + db = &ss->policydb; #endif #else - db = &policydb; + db = &policydb; #endif - return db; + return db; } static DEFINE_MUTEX(ksu_rules); + void apply_kernelsu_rules(void) { - struct policydb *db; + struct policydb *db; - if (!getenforce()) { - pr_info("SELinux permissive or disabled, apply rules!\n"); - } + if (!getenforce()) { + pr_info("SELinux permissive or disabled, apply rules!\n"); + } - mutex_lock(&ksu_rules); + mutex_lock(&ksu_rules); - db = get_policydb(); + db = get_policydb(); - ksu_permissive(db, KERNEL_SU_DOMAIN); - ksu_typeattribute(db, KERNEL_SU_DOMAIN, "mlstrustedsubject"); - ksu_typeattribute(db, KERNEL_SU_DOMAIN, "netdomain"); - ksu_typeattribute(db, KERNEL_SU_DOMAIN, "bluetoothdomain"); + ksu_permissive(db, KERNEL_SU_DOMAIN); + ksu_typeattribute(db, KERNEL_SU_DOMAIN, "mlstrustedsubject"); + ksu_typeattribute(db, KERNEL_SU_DOMAIN, "netdomain"); + ksu_typeattribute(db, KERNEL_SU_DOMAIN, "bluetoothdomain"); - // Create unconstrained file type - ksu_type(db, KERNEL_SU_FILE, "file_type"); - ksu_typeattribute(db, KERNEL_SU_FILE, "mlstrustedobject"); - ksu_allow(db, ALL, KERNEL_SU_FILE, ALL, ALL); + // Create unconstrained file type + ksu_type(db, KERNEL_SU_FILE, "file_type"); + ksu_typeattribute(db, KERNEL_SU_FILE, "mlstrustedobject"); + ksu_allow(db, ALL, KERNEL_SU_FILE, ALL, ALL); - // allow all! - ksu_allow(db, KERNEL_SU_DOMAIN, ALL, ALL, ALL); + // allow all! + ksu_allow(db, KERNEL_SU_DOMAIN, ALL, ALL, ALL); - // allow us do any ioctl - if (db->policyvers >= POLICYDB_VERSION_XPERMS_IOCTL) { - ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "blk_file", ALL); - ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "fifo_file", ALL); - ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "chr_file", ALL); - ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "file", ALL); - } + // allow us do any ioctl + if (db->policyvers >= POLICYDB_VERSION_XPERMS_IOCTL) { + ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "blk_file", ALL); + ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "fifo_file", ALL); + ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "chr_file", ALL); + ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "file", ALL); + } - // we need to save allowlist in /data/adb/ksu - ksu_allow(db, "kernel", "adb_data_file", "dir", ALL); - ksu_allow(db, "kernel", "adb_data_file", "file", ALL); - // we need to search /data/app - ksu_allow(db, "kernel", "apk_data_file", "file", "open"); - ksu_allow(db, "kernel", "apk_data_file", "dir", "open"); - ksu_allow(db, "kernel", "apk_data_file", "dir", "read"); - ksu_allow(db, "kernel", "apk_data_file", "dir", "search"); - // we may need to do mount on shell - ksu_allow(db, "kernel", "shell_data_file", "file", ALL); - // we need to read /data/system/packages.list - ksu_allow(db, "kernel", "kernel", "capability", "dac_override"); - // Android 10+: - // http://aospxref.com/android-12.0.0_r3/xref/system/sepolicy/private/file_contexts#512 - ksu_allow(db, "kernel", "packages_list_file", "file", ALL); - // Kernel 4.4 - ksu_allow(db, "kernel", "packages_list_file", "dir", ALL); - // Android 9-: - // http://aospxref.com/android-9.0.0_r61/xref/system/sepolicy/private/file_contexts#360 - ksu_allow(db, "kernel", "system_data_file", "file", ALL); - ksu_allow(db, "kernel", "system_data_file", "dir", ALL); - // our ksud triggered by init - ksu_allow(db, "init", "adb_data_file", "file", ALL); - ksu_allow(db, "init", "adb_data_file", "dir", ALL); // #1289 - ksu_allow(db, "init", KERNEL_SU_DOMAIN, ALL, ALL); + // we need to save allowlist in /data/adb/ksu + ksu_allow(db, "kernel", "adb_data_file", "dir", ALL); + ksu_allow(db, "kernel", "adb_data_file", "file", ALL); + // we need to search /data/app + ksu_allow(db, "kernel", "apk_data_file", "file", "open"); + ksu_allow(db, "kernel", "apk_data_file", "dir", "open"); + ksu_allow(db, "kernel", "apk_data_file", "dir", "read"); + ksu_allow(db, "kernel", "apk_data_file", "dir", "search"); + // we may need to do mount on shell + ksu_allow(db, "kernel", "shell_data_file", "file", ALL); + // we need to read /data/system/packages.list + ksu_allow(db, "kernel", "kernel", "capability", "dac_override"); + // Android 10+: + // http://aospxref.com/android-12.0.0_r3/xref/system/sepolicy/private/file_contexts#512 + ksu_allow(db, "kernel", "packages_list_file", "file", ALL); + // Kernel 4.4 + ksu_allow(db, "kernel", "packages_list_file", "dir", ALL); + // Android 9-: + // http://aospxref.com/android-9.0.0_r61/xref/system/sepolicy/private/file_contexts#360 + ksu_allow(db, "kernel", "system_data_file", "file", ALL); + ksu_allow(db, "kernel", "system_data_file", "dir", ALL); + // our ksud triggered by init + ksu_allow(db, "init", "adb_data_file", "file", ALL); + ksu_allow(db, "init", "adb_data_file", "dir", ALL); // #1289 + ksu_allow(db, "init", KERNEL_SU_DOMAIN, ALL, ALL); + // we need to umount modules in zygote + ksu_allow(db, "zygote", "adb_data_file", "dir", "search"); - // we need to umount modules in zygote - ksu_allow(db, "zygote", "adb_data_file", "dir", "search"); + // copied from Magisk rules + // suRights + ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "dir", "search"); + ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "dir", "read"); + ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "file", "open"); + ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "file", "read"); + ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "process", "getattr"); + ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "process", "sigchld"); - // copied from Magisk rules - // suRights - ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "dir", "search"); - ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "dir", "read"); - ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "file", "open"); - ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "file", "read"); - ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "process", "getattr"); - ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "process", "sigchld"); + // allowLog + ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "dir", "search"); + ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "read"); + ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "open"); + ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "getattr"); - // allowLog - ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "dir", "search"); - ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "read"); - ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "open"); - ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "getattr"); + // dumpsys + ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fd", "use"); + ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "write"); + ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "read"); + ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "open"); + ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "getattr"); - // dumpsys - ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fd", "use"); - ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "write"); - ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "read"); - ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "open"); - ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "getattr"); + // bootctl + ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "dir", "search"); + ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "file", "read"); + ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "file", "open"); + ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "process", + "getattr"); - // bootctl - ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "dir", "search"); - ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "file", "read"); - ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "file", "open"); - ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "process", - "getattr"); + // For mounting loop devices, mirrors, tmpfs + ksu_allow(db, "kernel", ALL, "file", "read"); + ksu_allow(db, "kernel", ALL, "file", "write"); - // For mounting loop devices, mirrors, tmpfs - ksu_allow(db, "kernel", ALL, "file", "read"); - ksu_allow(db, "kernel", ALL, "file", "write"); - - // Allow all binder transactions - ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "binder", ALL); - - // Allow system server kill su process - ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "getpgid"); - ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "sigkill"); - - // https://android-review.googlesource.com/c/platform/system/logging/+/3725346 - ksu_dontaudit(db, "untrusted_app", KERNEL_SU_DOMAIN, "dir", "getattr"); + // Allow all binder transactions + ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "binder", ALL); + // Allow system server kill su process + ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "getpgid"); + ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "sigkill"); + #ifdef CONFIG_KSU_SUSFS // Allow umount in zygote process without installing zygisk ksu_allow(db, "zygote", "labeledfs", "filesystem", "unmount"); @@ -150,8 +147,7 @@ void apply_kernelsu_rules(void) susfs_set_ksu_sid(); susfs_set_zygote_sid(); #endif - - mutex_unlock(&ksu_rules); + mutex_unlock(&ksu_rules); } #define MAX_SEPOL_LEN 128 @@ -167,372 +163,369 @@ void apply_kernelsu_rules(void) #define CMD_GENFSCON 9 struct sepol_data { - uint32_t cmd; - uint32_t subcmd; - uint64_t sepol1; - uint64_t sepol2; - uint64_t sepol3; - uint64_t sepol4; - uint64_t sepol5; - uint64_t sepol6; - uint64_t sepol7; + u32 cmd; + u32 subcmd; + u64 sepol1; + u64 sepol2; + u64 sepol3; + u64 sepol4; + u64 sepol5; + u64 sepol6; + u64 sepol7; }; static int get_object(char *buf, char __user *user_object, size_t buf_sz, - char **object) + char **object) { - if (!user_object) { - *object = ALL; - return 0; - } + if (!user_object) { + *object = ALL; + return 0; + } - if (strncpy_from_user(buf, user_object, buf_sz) < 0) { - return -EINVAL; - } + if (strncpy_from_user(buf, user_object, buf_sz) < 0) { + return -EINVAL; + } - *object = buf; + *object = buf; - return 0; + return 0; } - #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) || \ - !defined(KSU_COMPAT_USE_SELINUX_STATE) + !defined(KSU_COMPAT_USE_SELINUX_STATE) extern int avc_ss_reset(u32 seqno); #else extern int avc_ss_reset(struct selinux_avc *avc, u32 seqno); #endif - // reset avc cache table, otherwise the new rules will not take effect if already denied static void reset_avc_cache(void) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) || \ - !defined(KSU_COMPAT_USE_SELINUX_STATE) - avc_ss_reset(0); - selnl_notify_policyload(0); - selinux_status_update_policyload(0); + !defined(KSU_COMPAT_USE_SELINUX_STATE) + avc_ss_reset(0); + selnl_notify_policyload(0); + selinux_status_update_policyload(0); #else - struct selinux_avc *avc = selinux_state.avc; - avc_ss_reset(avc, 0); - selnl_notify_policyload(0); - selinux_status_update_policyload(&selinux_state, 0); + struct selinux_avc *avc = selinux_state.avc; + avc_ss_reset(avc, 0); + selnl_notify_policyload(0); + selinux_status_update_policyload(&selinux_state, 0); #endif - selinux_xfrm_notify_policyload(); + selinux_xfrm_notify_policyload(); } int handle_sepolicy(unsigned long arg3, void __user *arg4) { - struct policydb *db; + struct policydb *db; - if (!arg4) { - return -EINVAL; - } + if (!arg4) { + return -EINVAL; + } - if (!getenforce()) { - pr_info("SELinux permissive or disabled when handle policy!\n"); - } + if (!getenforce()) { + pr_info("SELinux permissive or disabled when handle policy!\n"); + } - struct sepol_data data = { 0 }; - if (copy_from_user(&data, arg4, sizeof(struct sepol_data))) { - pr_err("sepol: copy sepol_data failed.\n"); - return -EINVAL; - } + struct sepol_data data; + if (copy_from_user(&data, arg4, sizeof(struct sepol_data))) { + pr_err("sepol: copy sepol_data failed.\n"); + return -EINVAL; + } - u32 cmd = data.cmd; - u32 subcmd = data.subcmd; + u32 cmd = data.cmd; + u32 subcmd = data.subcmd; - mutex_lock(&ksu_rules); + mutex_lock(&ksu_rules); - db = get_policydb(); + db = get_policydb(); - int ret = -EINVAL; + int ret = -EINVAL; + switch (cmd) { + case CMD_NORMAL_PERM: { + char src_buf[MAX_SEPOL_LEN]; + char tgt_buf[MAX_SEPOL_LEN]; + char cls_buf[MAX_SEPOL_LEN]; + char perm_buf[MAX_SEPOL_LEN]; - switch (cmd) { - case CMD_NORMAL_PERM: { - char src_buf[MAX_SEPOL_LEN]; - char tgt_buf[MAX_SEPOL_LEN]; - char cls_buf[MAX_SEPOL_LEN]; - char perm_buf[MAX_SEPOL_LEN]; + char *s, *t, *c, *p; + if (get_object(src_buf, (void __user *)data.sepol1, + sizeof(src_buf), &s) < 0) { + pr_err("sepol: copy src failed.\n"); + goto exit; + } - char *s, *t, *c, *p; - if (get_object(src_buf, (void __user *)data.sepol1, - sizeof(src_buf), &s) < 0) { - pr_err("sepol: copy src failed.\n"); - goto exit; - } + if (get_object(tgt_buf, (void __user *)data.sepol2, + sizeof(tgt_buf), &t) < 0) { + pr_err("sepol: copy tgt failed.\n"); + goto exit; + } - if (get_object(tgt_buf, (void __user *)data.sepol2, - sizeof(tgt_buf), &t) < 0) { - pr_err("sepol: copy tgt failed.\n"); - goto exit; - } + if (get_object(cls_buf, (void __user *)data.sepol3, + sizeof(cls_buf), &c) < 0) { + pr_err("sepol: copy cls failed.\n"); + goto exit; + } - if (get_object(cls_buf, (void __user *)data.sepol3, - sizeof(cls_buf), &c) < 0) { - pr_err("sepol: copy cls failed.\n"); - goto exit; - } + if (get_object(perm_buf, (void __user *)data.sepol4, + sizeof(perm_buf), &p) < 0) { + pr_err("sepol: copy perm failed.\n"); + goto exit; + } - if (get_object(perm_buf, (void __user *)data.sepol4, - sizeof(perm_buf), &p) < 0) { - pr_err("sepol: copy perm failed.\n"); - goto exit; - } + bool success = false; - bool success = false; + if (subcmd == 1) { + success = ksu_allow(db, s, t, c, p); + } else if (subcmd == 2) { + success = ksu_deny(db, s, t, c, p); + } else if (subcmd == 3) { + success = ksu_auditallow(db, s, t, c, p); + } else if (subcmd == 4) { + success = ksu_dontaudit(db, s, t, c, p); + } else { + pr_err("sepol: unknown subcmd: %d\n", subcmd); + } + ret = success ? 0 : -EINVAL; + break; + } + case CMD_XPERM: { + char src_buf[MAX_SEPOL_LEN]; + char tgt_buf[MAX_SEPOL_LEN]; + char cls_buf[MAX_SEPOL_LEN]; - if (subcmd == 1) { - success = ksu_allow(db, s, t, c, p); - } else if (subcmd == 2) { - success = ksu_deny(db, s, t, c, p); - } else if (subcmd == 3) { - success = ksu_auditallow(db, s, t, c, p); - } else if (subcmd == 4) { - success = ksu_dontaudit(db, s, t, c, p); - } else { - pr_err("sepol: unknown subcmd: %d\n", subcmd); - } - ret = success ? 0 : -EINVAL; - break; - } - case CMD_XPERM: { - char src_buf[MAX_SEPOL_LEN]; - char tgt_buf[MAX_SEPOL_LEN]; - char cls_buf[MAX_SEPOL_LEN]; + char __maybe_unused + operation[MAX_SEPOL_LEN]; // it is always ioctl now! + char perm_set[MAX_SEPOL_LEN]; - char __maybe_unused - operation[MAX_SEPOL_LEN]; // it is always ioctl now! - char perm_set[MAX_SEPOL_LEN]; + char *s, *t, *c; + if (get_object(src_buf, (void __user *)data.sepol1, + sizeof(src_buf), &s) < 0) { + pr_err("sepol: copy src failed.\n"); + goto exit; + } + if (get_object(tgt_buf, (void __user *)data.sepol2, + sizeof(tgt_buf), &t) < 0) { + pr_err("sepol: copy tgt failed.\n"); + goto exit; + } + if (get_object(cls_buf, (void __user *)data.sepol3, + sizeof(cls_buf), &c) < 0) { + pr_err("sepol: copy cls failed.\n"); + goto exit; + } + if (strncpy_from_user(operation, (void __user *)data.sepol4, + sizeof(operation)) < 0) { + pr_err("sepol: copy operation failed.\n"); + goto exit; + } + if (strncpy_from_user(perm_set, (void __user *)data.sepol5, + sizeof(perm_set)) < 0) { + pr_err("sepol: copy perm_set failed.\n"); + goto exit; + } - char *s, *t, *c; - if (get_object(src_buf, (void __user *)data.sepol1, - sizeof(src_buf), &s) < 0) { - pr_err("sepol: copy src failed.\n"); - goto exit; - } - if (get_object(tgt_buf, (void __user *)data.sepol2, - sizeof(tgt_buf), &t) < 0) { - pr_err("sepol: copy tgt failed.\n"); - goto exit; - } - if (get_object(cls_buf, (void __user *)data.sepol3, - sizeof(cls_buf), &c) < 0) { - pr_err("sepol: copy cls failed.\n"); - goto exit; - } - if (strncpy_from_user(operation, (void __user *)data.sepol4, - sizeof(operation)) < 0) { - pr_err("sepol: copy operation failed.\n"); - goto exit; - } - if (strncpy_from_user(perm_set, (void __user *)data.sepol5, - sizeof(perm_set)) < 0) { - pr_err("sepol: copy perm_set failed.\n"); - goto exit; - } + bool success = false; + if (subcmd == 1) { + success = ksu_allowxperm(db, s, t, c, perm_set); + } else if (subcmd == 2) { + success = ksu_auditallowxperm(db, s, t, c, perm_set); + } else if (subcmd == 3) { + success = ksu_dontauditxperm(db, s, t, c, perm_set); + } else { + pr_err("sepol: unknown subcmd: %d\n", subcmd); + } + ret = success ? 0 : -EINVAL; + break; + } + case CMD_TYPE_STATE: { + char src[MAX_SEPOL_LEN]; - bool success = false; - if (subcmd == 1) { - success = ksu_allowxperm(db, s, t, c, perm_set); - } else if (subcmd == 2) { - success = ksu_auditallowxperm(db, s, t, c, perm_set); - } else if (subcmd == 3) { - success = ksu_dontauditxperm(db, s, t, c, perm_set); - } else { - pr_err("sepol: unknown subcmd: %d\n", subcmd); - } - ret = success ? 0 : -EINVAL; - break; - } - case CMD_TYPE_STATE: { - char src[MAX_SEPOL_LEN]; + if (strncpy_from_user(src, (void __user *)data.sepol1, + sizeof(src)) < 0) { + pr_err("sepol: copy src failed.\n"); + goto exit; + } - if (strncpy_from_user(src, (void __user *)data.sepol1, - sizeof(src)) < 0) { - pr_err("sepol: copy src failed.\n"); - goto exit; - } + bool success = false; + if (subcmd == 1) { + success = ksu_permissive(db, src); + } else if (subcmd == 2) { + success = ksu_enforce(db, src); + } else { + pr_err("sepol: unknown subcmd: %d\n", subcmd); + } + if (success) + ret = 0; + break; + } + case CMD_TYPE: + case CMD_TYPE_ATTR: { + char type[MAX_SEPOL_LEN]; + char attr[MAX_SEPOL_LEN]; - bool success = false; - if (subcmd == 1) { - success = ksu_permissive(db, src); - } else if (subcmd == 2) { - success = ksu_enforce(db, src); - } else { - pr_err("sepol: unknown subcmd: %d\n", subcmd); - } - if (success) - ret = 0; - break; - } - case CMD_TYPE: - case CMD_TYPE_ATTR: { - char type[MAX_SEPOL_LEN]; - char attr[MAX_SEPOL_LEN]; + if (strncpy_from_user(type, (void __user *)data.sepol1, + sizeof(type)) < 0) { + pr_err("sepol: copy type failed.\n"); + goto exit; + } + if (strncpy_from_user(attr, (void __user *)data.sepol2, + sizeof(attr)) < 0) { + pr_err("sepol: copy attr failed.\n"); + goto exit; + } - if (strncpy_from_user(type, (void __user *)data.sepol1, - sizeof(type)) < 0) { - pr_err("sepol: copy type failed.\n"); - goto exit; - } - if (strncpy_from_user(attr, (void __user *)data.sepol2, - sizeof(attr)) < 0) { - pr_err("sepol: copy attr failed.\n"); - goto exit; - } + bool success = false; + if (cmd == CMD_TYPE) { + success = ksu_type(db, type, attr); + } else { + success = ksu_typeattribute(db, type, attr); + } + if (!success) { + pr_err("sepol: %d failed.\n", cmd); + goto exit; + } + ret = 0; + break; + } + case CMD_ATTR: { + char attr[MAX_SEPOL_LEN]; - bool success = false; - if (cmd == CMD_TYPE) { - success = ksu_type(db, type, attr); - } else { - success = ksu_typeattribute(db, type, attr); - } - if (!success) { - pr_err("sepol: %d failed.\n", cmd); - goto exit; - } - ret = 0; - break; - } - case CMD_ATTR: { - char attr[MAX_SEPOL_LEN]; + if (strncpy_from_user(attr, (void __user *)data.sepol1, + sizeof(attr)) < 0) { + pr_err("sepol: copy attr failed.\n"); + goto exit; + } + if (!ksu_attribute(db, attr)) { + pr_err("sepol: %d failed.\n", cmd); + goto exit; + } + ret = 0; + break; + } + case CMD_TYPE_TRANSITION: { + char src[MAX_SEPOL_LEN]; + char tgt[MAX_SEPOL_LEN]; + char cls[MAX_SEPOL_LEN]; + char default_type[MAX_SEPOL_LEN]; + char object[MAX_SEPOL_LEN]; - if (strncpy_from_user(attr, (void __user *)data.sepol1, - sizeof(attr)) < 0) { - pr_err("sepol: copy attr failed.\n"); - goto exit; - } - if (!ksu_attribute(db, attr)) { - pr_err("sepol: %d failed.\n", cmd); - goto exit; - } - ret = 0; - break; - } - case CMD_TYPE_TRANSITION: { - char src[MAX_SEPOL_LEN]; - char tgt[MAX_SEPOL_LEN]; - char cls[MAX_SEPOL_LEN]; - char default_type[MAX_SEPOL_LEN]; - char object[MAX_SEPOL_LEN]; + if (strncpy_from_user(src, (void __user *)data.sepol1, + sizeof(src)) < 0) { + pr_err("sepol: copy src failed.\n"); + goto exit; + } + if (strncpy_from_user(tgt, (void __user *)data.sepol2, + sizeof(tgt)) < 0) { + pr_err("sepol: copy tgt failed.\n"); + goto exit; + } + if (strncpy_from_user(cls, (void __user *)data.sepol3, + sizeof(cls)) < 0) { + pr_err("sepol: copy cls failed.\n"); + goto exit; + } + if (strncpy_from_user(default_type, (void __user *)data.sepol4, + sizeof(default_type)) < 0) { + pr_err("sepol: copy default_type failed.\n"); + goto exit; + } + char *real_object; + if ((void __user *)data.sepol5 == NULL) { + real_object = NULL; + } else { + if (strncpy_from_user(object, + (void __user *)data.sepol5, + sizeof(object)) < 0) { + pr_err("sepol: copy object failed.\n"); + goto exit; + } + real_object = object; + } - if (strncpy_from_user(src, (void __user *)data.sepol1, - sizeof(src)) < 0) { - pr_err("sepol: copy src failed.\n"); - goto exit; - } - if (strncpy_from_user(tgt, (void __user *)data.sepol2, - sizeof(tgt)) < 0) { - pr_err("sepol: copy tgt failed.\n"); - goto exit; - } - if (strncpy_from_user(cls, (void __user *)data.sepol3, - sizeof(cls)) < 0) { - pr_err("sepol: copy cls failed.\n"); - goto exit; - } - if (strncpy_from_user(default_type, (void __user *)data.sepol4, - sizeof(default_type)) < 0) { - pr_err("sepol: copy default_type failed.\n"); - goto exit; - } - char *real_object; - if ((void __user *)data.sepol5 == NULL) { - real_object = NULL; - } else { - if (strncpy_from_user(object, - (void __user *)data.sepol5, - sizeof(object)) < 0) { - pr_err("sepol: copy object failed.\n"); - goto exit; - } - real_object = object; - } + bool success = ksu_type_transition(db, src, tgt, cls, + default_type, real_object); + if (success) + ret = 0; + break; + } + case CMD_TYPE_CHANGE: { + char src[MAX_SEPOL_LEN]; + char tgt[MAX_SEPOL_LEN]; + char cls[MAX_SEPOL_LEN]; + char default_type[MAX_SEPOL_LEN]; - bool success = ksu_type_transition(db, src, tgt, cls, - default_type, real_object); - if (success) - ret = 0; - break; - } - case CMD_TYPE_CHANGE: { - char src[MAX_SEPOL_LEN]; - char tgt[MAX_SEPOL_LEN]; - char cls[MAX_SEPOL_LEN]; - char default_type[MAX_SEPOL_LEN]; + if (strncpy_from_user(src, (void __user *)data.sepol1, + sizeof(src)) < 0) { + pr_err("sepol: copy src failed.\n"); + goto exit; + } + if (strncpy_from_user(tgt, (void __user *)data.sepol2, + sizeof(tgt)) < 0) { + pr_err("sepol: copy tgt failed.\n"); + goto exit; + } + if (strncpy_from_user(cls, (void __user *)data.sepol3, + sizeof(cls)) < 0) { + pr_err("sepol: copy cls failed.\n"); + goto exit; + } + if (strncpy_from_user(default_type, (void __user *)data.sepol4, + sizeof(default_type)) < 0) { + pr_err("sepol: copy default_type failed.\n"); + goto exit; + } + bool success = false; + if (subcmd == 1) { + success = ksu_type_change(db, src, tgt, cls, + default_type); + } else if (subcmd == 2) { + success = ksu_type_member(db, src, tgt, cls, + default_type); + } else { + pr_err("sepol: unknown subcmd: %d\n", subcmd); + } + if (success) + ret = 0; + break; + } + case CMD_GENFSCON: { + char name[MAX_SEPOL_LEN]; + char path[MAX_SEPOL_LEN]; + char context[MAX_SEPOL_LEN]; + if (strncpy_from_user(name, (void __user *)data.sepol1, + sizeof(name)) < 0) { + pr_err("sepol: copy name failed.\n"); + goto exit; + } + if (strncpy_from_user(path, (void __user *)data.sepol2, + sizeof(path)) < 0) { + pr_err("sepol: copy path failed.\n"); + goto exit; + } + if (strncpy_from_user(context, (void __user *)data.sepol3, + sizeof(context)) < 0) { + pr_err("sepol: copy context failed.\n"); + goto exit; + } - if (strncpy_from_user(src, (void __user *)data.sepol1, - sizeof(src)) < 0) { - pr_err("sepol: copy src failed.\n"); - goto exit; - } - if (strncpy_from_user(tgt, (void __user *)data.sepol2, - sizeof(tgt)) < 0) { - pr_err("sepol: copy tgt failed.\n"); - goto exit; - } - if (strncpy_from_user(cls, (void __user *)data.sepol3, - sizeof(cls)) < 0) { - pr_err("sepol: copy cls failed.\n"); - goto exit; - } - if (strncpy_from_user(default_type, (void __user *)data.sepol4, - sizeof(default_type)) < 0) { - pr_err("sepol: copy default_type failed.\n"); - goto exit; - } - bool success = false; - if (subcmd == 1) { - success = ksu_type_change(db, src, tgt, cls, - default_type); - } else if (subcmd == 2) { - success = ksu_type_member(db, src, tgt, cls, - default_type); - } else { - pr_err("sepol: unknown subcmd: %d\n", subcmd); - } - if (success) - ret = 0; - break; - } - case CMD_GENFSCON: { - char name[MAX_SEPOL_LEN]; - char path[MAX_SEPOL_LEN]; - char context[MAX_SEPOL_LEN]; - if (strncpy_from_user(name, (void __user *)data.sepol1, - sizeof(name)) < 0) { - pr_err("sepol: copy name failed.\n"); - goto exit; - } - if (strncpy_from_user(path, (void __user *)data.sepol2, - sizeof(path)) < 0) { - pr_err("sepol: copy path failed.\n"); - goto exit; - } - if (strncpy_from_user(context, (void __user *)data.sepol3, - sizeof(context)) < 0) { - pr_err("sepol: copy context failed.\n"); - goto exit; - } - - if (!ksu_genfscon(db, name, path, context)) { - pr_err("sepol: %d failed.\n", cmd); - goto exit; - } - ret = 0; - break; - } - default: { - pr_err("sepol: unknown cmd: %d\n", cmd); - break; - } - } + if (!ksu_genfscon(db, name, path, context)) { + pr_err("sepol: %d failed.\n", cmd); + goto exit; + } + ret = 0; + break; + } + default: { + pr_err("sepol: unknown cmd: %d\n", cmd); + break; + } + } exit: - mutex_unlock(&ksu_rules); + mutex_unlock(&ksu_rules); - // only allow and xallow needs to reset avc cache, but we cannot do that because - // we are in atomic context. so we just reset it every time. - reset_avc_cache(); + // only allow and xallow needs to reset avc cache, but we cannot do that because + // we are in atomic context. so we just reset it every time. + reset_avc_cache(); - return ret; -} + return ret; +} \ No newline at end of file diff --git a/kernel/selinux/selinux.c b/kernel/selinux/selinux.c index 6d76e9b4..04a7b5ed 100644 --- a/kernel/selinux/selinux.c +++ b/kernel/selinux/selinux.c @@ -1,6 +1,7 @@ #include "linux/cred.h" #include "linux/sched.h" -#include +#include "linux/security.h" +#include "linux/version.h" #include "selinux_defs.h" #include "../klog.h" // IWYU pragma: keep @@ -8,163 +9,178 @@ static int transive_to_domain(const char *domain) { - struct cred *cred; - struct task_security_struct *tsec; - u32 sid; - int error; + struct cred *cred; + struct task_security_struct *tsec; + u32 sid; + int error; - cred = (struct cred *)__task_cred(current); + cred = (struct cred *)__task_cred(current); - tsec = cred->security; - if (!tsec) { - pr_err("tsec == NULL!\n"); - return -1; - } + tsec = cred->security; + if (!tsec) { + pr_err("tsec == NULL!\n"); + return -1; + } - error = security_secctx_to_secid(domain, strlen(domain), &sid); - if (error) { - pr_info("security_secctx_to_secid %s -> sid: %d, error: %d\n", - domain, sid, error); - } - - if (!error) { - tsec->sid = sid; - tsec->create_sid = 0; - tsec->keycreate_sid = 0; - tsec->sockcreate_sid = 0; - } - - return error; + error = security_secctx_to_secid(domain, strlen(domain), &sid); + if (error) { + pr_info("security_secctx_to_secid %s -> sid: %d, error: %d\n", + domain, sid, error); + } + if (!error) { + tsec->sid = sid; + tsec->create_sid = 0; + tsec->keycreate_sid = 0; + tsec->sockcreate_sid = 0; + } + return error; } #if LINUX_VERSION_CODE <= KERNEL_VERSION(4, 19, 0) -bool __maybe_unused is_ksu_transition(const struct task_security_struct *old_tsec, - const struct task_security_struct *new_tsec) +bool __maybe_unused +is_ksu_transition(const struct task_security_struct *old_tsec, + const struct task_security_struct *new_tsec) { - static u32 ksu_sid; - char *secdata; - u32 seclen; - bool allowed = false; + static u32 ksu_sid; + char *secdata; + u32 seclen; + bool allowed = false; - if (!ksu_sid) - security_secctx_to_secid(KERNEL_SU_DOMAIN, strlen(KERNEL_SU_DOMAIN), &ksu_sid); + if (!ksu_sid) + security_secctx_to_secid(KERNEL_SU_DOMAIN, + strlen(KERNEL_SU_DOMAIN), &ksu_sid); - if (security_secid_to_secctx(old_tsec->sid, &secdata, &seclen)) - return false; + if (security_secid_to_secctx(old_tsec->sid, &secdata, &seclen)) + return false; - allowed = (!strcmp("u:r:init:s0", secdata) && new_tsec->sid == ksu_sid); - security_release_secctx(secdata, seclen); - return allowed; + allowed = (!strcmp("u:r:init:s0", secdata) && new_tsec->sid == ksu_sid); + security_release_secctx(secdata, seclen); + return allowed; } #endif + void setup_selinux(const char *domain) { - if (transive_to_domain(domain)) { - pr_err("transive domain failed.\n"); - return; - } + if (transive_to_domain(domain)) { + pr_err("transive domain failed.\n"); + return; + } } void setenforce(bool enforce) { - __setenforce(enforce); + __setenforce(enforce); } bool getenforce(void) { - if (is_selinux_disabled()) { - return false; - } + if (is_selinux_disabled()) { + return false; + } - return __is_selinux_enforcing(); + return __is_selinux_enforcing(); } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) && \ + !defined(KSU_COMPAT_HAS_CURRENT_SID) +/* + * get the subjective security ID of the current task + */ +static inline u32 current_sid(void) +{ + const struct task_security_struct *tsec = current_security(); + + return tsec->sid; +} +#endif + #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 14, 0) struct lsm_context { - char *context; - u32 len; + char *context; + u32 len; }; static int __security_secid_to_secctx(u32 secid, struct lsm_context *cp) { - return security_secid_to_secctx(secid, &cp->context, &cp->len); + return security_secid_to_secctx(secid, &cp->context, &cp->len); } static void __security_release_secctx(struct lsm_context *cp) { - return security_release_secctx(cp->context, cp->len); + security_release_secctx(cp->context, cp->len); } #else #define __security_secid_to_secctx security_secid_to_secctx #define __security_release_secctx security_release_secctx #endif -bool is_task_ksu_domain(const struct cred* cred) +bool is_task_ksu_domain(const struct cred *cred) { - struct lsm_context ctx; - bool result; - if (!cred) { - return false; - } - const struct task_security_struct *tsec = selinux_cred(cred); - if (!tsec) { - return false; - } - int err = __security_secid_to_secctx(tsec->sid, &ctx); - if (err) { - return false; - } - result = strncmp(KERNEL_SU_DOMAIN, ctx.context, ctx.len) == 0; - __security_release_secctx(&ctx); - return result; + struct lsm_context ctx; + bool result; + if (!cred) { + return false; + } + const struct task_security_struct *tsec = __selinux_cred(cred); + if (!tsec) { + return false; + } + int err = __security_secid_to_secctx(tsec->sid, &ctx); + if (err) { + return false; + } + result = strncmp(KERNEL_SU_DOMAIN, ctx.context, ctx.len) == 0; + __security_release_secctx(&ctx); + return result; } -bool is_ksu_domain() +bool is_ksu_domain(void) { - current_sid(); - return is_task_ksu_domain(current_cred()); + current_sid(); + return is_task_ksu_domain(current_cred()); } -bool is_context(const struct cred* cred, const char* context) +bool is_context(const struct cred *cred, const char *context) { - if (!cred) { - return false; - } - const struct task_security_struct * tsec = selinux_cred(cred); - if (!tsec) { - return false; - } - struct lsm_context ctx; - bool result; - int err = __security_secid_to_secctx(tsec->sid, &ctx); - if (err) { - return false; - } - result = strncmp(context, ctx.context, ctx.len) == 0; - __security_release_secctx(&ctx); - return result; + if (!cred) { + return false; + } + const struct task_security_struct *tsec = __selinux_cred(cred); + if (!tsec) { + return false; + } + struct lsm_context ctx; + bool result; + int err = __security_secid_to_secctx(tsec->sid, &ctx); + if (err) { + return false; + } + result = strncmp(context, ctx.context, ctx.len) == 0; + __security_release_secctx(&ctx); + return result; } -bool is_zygote(const struct cred* cred) +bool is_zygote(const struct cred *cred) { - return is_context(cred, "u:r:zygote:s0"); + return is_context(cred, "u:r:zygote:s0"); } -bool is_init(const struct cred* cred) { - return is_context(cred, "u:r:init:s0"); +bool is_init(const struct cred *cred) +{ + return is_context(cred, "u:r:init:s0"); } #define KSU_FILE_DOMAIN "u:object_r:ksu_file:s0" -u32 ksu_get_ksu_file_sid() +u32 ksu_get_ksu_file_sid(void) { - u32 ksu_file_sid = 0; - int err = security_secctx_to_secid(KSU_FILE_DOMAIN, strlen(KSU_FILE_DOMAIN), - &ksu_file_sid); - if (err) { - pr_info("get ksufile sid err %d\n", err); - } - return ksu_file_sid; + u32 ksu_file_sid = 0; + int err = security_secctx_to_secid( + KSU_FILE_DOMAIN, strlen(KSU_FILE_DOMAIN), &ksu_file_sid); + if (err) { + pr_info("get ksufile sid err %d\n", err); + } + return ksu_file_sid; } #ifdef CONFIG_KSU_SUSFS diff --git a/kernel/selinux/selinux.h b/kernel/selinux/selinux.h index 7ae6046d..8f110f15 100644 --- a/kernel/selinux/selinux.h +++ b/kernel/selinux/selinux.h @@ -1,11 +1,12 @@ #ifndef __KSU_H_SELINUX #define __KSU_H_SELINUX -#include -#include -#include "linux/sched.h" +#include "linux/types.h" +#include "linux/version.h" +#include "linux/cred.h" -#ifdef KSU_COMPAT_HAS_SELINUX_STATE +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) || \ + defined(KSU_COMPAT_HAS_SELINUX_STATE) #define KSU_COMPAT_USE_SELINUX_STATE #endif @@ -15,13 +16,13 @@ void setenforce(bool); bool getenforce(void); -bool is_task_ksu_domain(const struct cred* cred); +bool is_task_ksu_domain(const struct cred *cred); bool is_ksu_domain(void); -bool is_zygote(const struct cred* cred); +bool is_zygote(const struct cred *cred); -bool is_init(const struct cred* cred); +bool is_init(const struct cred *cred); void apply_kernelsu_rules(void); @@ -42,4 +43,4 @@ bool susfs_is_current_init_domain(void); void susfs_set_priv_app_sid(void); #endif // #ifdef CONFIG_KSU_SUSFS -#endif +#endif \ No newline at end of file diff --git a/kernel/selinux/selinux_defs.h b/kernel/selinux/selinux_defs.h index bdd41b77..51d1e7ec 100644 --- a/kernel/selinux/selinux_defs.h +++ b/kernel/selinux/selinux_defs.h @@ -12,25 +12,31 @@ #ifdef CONFIG_SECURITY_SELINUX_DISABLE #ifdef KSU_COMPAT_USE_SELINUX_STATE -#define is_selinux_disabled() (selinux_state.disabled) +#define is_selinux_disabled() (selinux_state.disabled) #else -#define is_selinux_disabled() (selinux_disabled) +#define is_selinux_disabled() (selinux_disabled) #endif #else -#define is_selinux_disabled() (0) +#define is_selinux_disabled() (0) #endif #ifdef CONFIG_SECURITY_SELINUX_DEVELOP #ifdef KSU_COMPAT_USE_SELINUX_STATE -#define __is_selinux_enforcing() (selinux_state.enforcing) -#define __setenforce(val) selinux_state.enforcing = val +#define __is_selinux_enforcing() (selinux_state.enforcing) +#define __setenforce(val) selinux_state.enforcing = val #elif defined(SAMSUNG_SELINUX_PORTING) || !defined(KSU_COMPAT_USE_SELINUX_STATE) -#define __is_selinux_enforcing() (selinux_enforcing) -#define __setenforce(val) selinux_enforcing = val +#define __is_selinux_enforcing() (selinux_enforcing) +#define __setenforce(val) selinux_enforcing = val #endif #else -#define __is_selinux_enforcing() (1) +#define __is_selinux_enforcing() (1) #define __setenforce(val) #endif +#ifdef KSU_OPTIONAL_SELINUX_CRED +#define __selinux_cred(cred) (selinux_cred(cred)) +#else +#define __selinux_cred(cred) (cred->security) #endif + +#endif \ No newline at end of file diff --git a/kernel/selinux/sepolicy.c b/kernel/selinux/sepolicy.c index 2dd0d321..0a6abec2 100644 --- a/kernel/selinux/sepolicy.c +++ b/kernel/selinux/sepolicy.c @@ -6,6 +6,7 @@ #include "sepolicy.h" #include "../klog.h" // IWYU pragma: keep #include "ss/symtab.h" +#include "../kernel_compat.h" // Add check Huawei Device #define KSU_SUPPORT_ADD_TYPE @@ -14,44 +15,44 @@ ////////////////////////////////////////////////////// static struct avtab_node *get_avtab_node(struct policydb *db, - struct avtab_key *key, - struct avtab_extended_perms *xperms); + struct avtab_key *key, + struct avtab_extended_perms *xperms); static bool add_rule(struct policydb *db, const char *s, const char *t, - const char *c, const char *p, int effect, bool invert); + const char *c, const char *p, int effect, bool invert); static void add_rule_raw(struct policydb *db, struct type_datum *src, - struct type_datum *tgt, struct class_datum *cls, - struct perm_datum *perm, int effect, bool invert); + struct type_datum *tgt, struct class_datum *cls, + struct perm_datum *perm, int effect, bool invert); static void add_xperm_rule_raw(struct policydb *db, struct type_datum *src, - struct type_datum *tgt, struct class_datum *cls, - uint16_t low, uint16_t high, int effect, - bool invert); + struct type_datum *tgt, struct class_datum *cls, + uint16_t low, uint16_t high, int effect, + bool invert); static bool add_xperm_rule(struct policydb *db, const char *s, const char *t, - const char *c, const char *range, int effect, - bool invert); + const char *c, const char *range, int effect, + bool invert); static bool add_type_rule(struct policydb *db, const char *s, const char *t, - const char *c, const char *d, int effect); + const char *c, const char *d, int effect); static bool add_filename_trans(struct policydb *db, const char *s, - const char *t, const char *c, const char *d, - const char *o); + const char *t, const char *c, const char *d, + const char *o); static bool add_genfscon(struct policydb *db, const char *fs_name, - const char *path, const char *context); + const char *path, const char *context); static bool add_type(struct policydb *db, const char *type_name, bool attr); static bool set_type_state(struct policydb *db, const char *type_name, - bool permissive); + bool permissive); static void add_typeattribute_raw(struct policydb *db, struct type_datum *type, - struct type_datum *attr); + struct type_datum *attr); static bool add_typeattribute(struct policydb *db, const char *type, - const char *attr); + const char *attr); ////////////////////////////////////////////////////// // Implementation @@ -62,18 +63,18 @@ static bool add_typeattribute(struct policydb *db, const char *type, #define strip_av(effect, invert) ((effect == AVTAB_AUDITDENY) == !invert) #define ksu_hash_for_each(node_ptr, n_slot, cur) \ - int i; \ - for (i = 0; i < n_slot; ++i) \ - for (cur = node_ptr[i]; cur; cur = cur->next) + int i; \ + for (i = 0; i < n_slot; ++i) \ + for (cur = node_ptr[i]; cur; cur = cur->next) // htable is a struct instead of pointer above 5.8.0: // https://elixir.bootlin.com/linux/v5.8-rc1/source/security/selinux/ss/symtab.h #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) #define ksu_hashtab_for_each(htab, cur) \ - ksu_hash_for_each(htab.htable, htab.size, cur) + ksu_hash_for_each(htab.htable, htab.size, cur) #else #define ksu_hashtab_for_each(htab, cur) \ - ksu_hash_for_each(htab->htable, htab->size, cur) + ksu_hash_for_each(htab->htable, htab->size, cur) #endif // symtab_search is introduced on 5.9.0: @@ -84,186 +85,186 @@ static bool add_typeattribute(struct policydb *db, const char *type, #endif #define avtab_for_each(avtab, cur) \ - ksu_hash_for_each(avtab.htable, avtab.nslot, cur); + ksu_hash_for_each(avtab.htable, avtab.nslot, cur); static struct avtab_node *get_avtab_node(struct policydb *db, - struct avtab_key *key, - struct avtab_extended_perms *xperms) + struct avtab_key *key, + struct avtab_extended_perms *xperms) { - struct avtab_node *node; + struct avtab_node *node; - /* AVTAB_XPERMS entries are not necessarily unique */ - if (key->specified & AVTAB_XPERMS) { - bool match = false; - node = avtab_search_node(&db->te_avtab, key); - while (node) { - if ((node->datum.u.xperms->specified == - xperms->specified) && - (node->datum.u.xperms->driver == xperms->driver)) { - match = true; - break; - } - node = avtab_search_node_next(node, key->specified); - } - if (!match) - node = NULL; - } else { - node = avtab_search_node(&db->te_avtab, key); - } + /* AVTAB_XPERMS entries are not necessarily unique */ + if (key->specified & AVTAB_XPERMS) { + bool match = false; + node = avtab_search_node(&db->te_avtab, key); + while (node) { + if ((node->datum.u.xperms->specified == + xperms->specified) && + (node->datum.u.xperms->driver == xperms->driver)) { + match = true; + break; + } + node = avtab_search_node_next(node, key->specified); + } + if (!match) + node = NULL; + } else { + node = avtab_search_node(&db->te_avtab, key); + } - if (!node) { - struct avtab_datum avdatum = {}; - /* + if (!node) { + struct avtab_datum avdatum = {}; + /* * AUDITDENY, aka DONTAUDIT, are &= assigned, versus |= for * others. Initialize the data accordingly. */ - if (key->specified & AVTAB_XPERMS) { - avdatum.u.xperms = xperms; - } else { - avdatum.u.data = - key->specified == AVTAB_AUDITDENY ? ~0U : 0U; - } - /* this is used to get the node - insertion is actually unique */ - node = avtab_insert_nonunique(&db->te_avtab, key, &avdatum); + if (key->specified & AVTAB_XPERMS) { + avdatum.u.xperms = xperms; + } else { + avdatum.u.data = + key->specified == AVTAB_AUDITDENY ? ~0U : 0U; + } + /* this is used to get the node - insertion is actually unique */ + node = avtab_insert_nonunique(&db->te_avtab, key, &avdatum); - int grow_size = sizeof(struct avtab_key); - grow_size += sizeof(struct avtab_datum); - if (key->specified & AVTAB_XPERMS) { - grow_size += sizeof(u8); - grow_size += sizeof(u8); - grow_size += sizeof(u32) * - ARRAY_SIZE(avdatum.u.xperms->perms.p); - } - db->len += grow_size; - } + int grow_size = sizeof(struct avtab_key); + grow_size += sizeof(struct avtab_datum); + if (key->specified & AVTAB_XPERMS) { + grow_size += sizeof(u8); + grow_size += sizeof(u8); + grow_size += sizeof(u32) * + ARRAY_SIZE(avdatum.u.xperms->perms.p); + } + db->len += grow_size; + } - return node; + return node; } static bool add_rule(struct policydb *db, const char *s, const char *t, - const char *c, const char *p, int effect, bool invert) + const char *c, const char *p, int effect, bool invert) { - struct type_datum *src = NULL, *tgt = NULL; - struct class_datum *cls = NULL; - struct perm_datum *perm = NULL; + struct type_datum *src = NULL, *tgt = NULL; + struct class_datum *cls = NULL; + struct perm_datum *perm = NULL; - if (s) { - src = symtab_search(&db->p_types, s); - if (src == NULL) { - pr_info("source type %s does not exist\n", s); - return false; - } - } + if (s) { + src = symtab_search(&db->p_types, s); + if (src == NULL) { + pr_info("source type %s does not exist\n", s); + return false; + } + } - if (t) { - tgt = symtab_search(&db->p_types, t); - if (tgt == NULL) { - pr_info("target type %s does not exist\n", t); - return false; - } - } + if (t) { + tgt = symtab_search(&db->p_types, t); + if (tgt == NULL) { + pr_info("target type %s does not exist\n", t); + return false; + } + } - if (c) { - cls = symtab_search(&db->p_classes, c); - if (cls == NULL) { - pr_info("class %s does not exist\n", c); - return false; - } - } + if (c) { + cls = symtab_search(&db->p_classes, c); + if (cls == NULL) { + pr_info("class %s does not exist\n", c); + return false; + } + } - if (p) { - if (c == NULL) { - pr_info("No class is specified, cannot add perm [%s] \n", - p); - return false; - } + if (p) { + if (c == NULL) { + pr_info("No class is specified, cannot add perm [%s] \n", + p); + return false; + } - perm = symtab_search(&cls->permissions, p); - if (perm == NULL && cls->comdatum != NULL) { - perm = symtab_search(&cls->comdatum->permissions, p); - } - if (perm == NULL) { - pr_info("perm %s does not exist in class %s\n", p, c); - return false; - } - } - add_rule_raw(db, src, tgt, cls, perm, effect, invert); - return true; + perm = symtab_search(&cls->permissions, p); + if (perm == NULL && cls->comdatum != NULL) { + perm = symtab_search(&cls->comdatum->permissions, p); + } + if (perm == NULL) { + pr_info("perm %s does not exist in class %s\n", p, c); + return false; + } + } + add_rule_raw(db, src, tgt, cls, perm, effect, invert); + return true; } static void add_rule_raw(struct policydb *db, struct type_datum *src, - struct type_datum *tgt, struct class_datum *cls, - struct perm_datum *perm, int effect, bool invert) + struct type_datum *tgt, struct class_datum *cls, + struct perm_datum *perm, int effect, bool invert) { - if (src == NULL) { - struct hashtab_node *node; - if (strip_av(effect, invert)) { - ksu_hashtab_for_each(db->p_types.table, node) - { - add_rule_raw(db, - (struct type_datum *)node->datum, - tgt, cls, perm, effect, invert); - }; - } else { - ksu_hashtab_for_each(db->p_types.table, node) - { - struct type_datum *type = - (struct type_datum *)(node->datum); - if (type->attribute) { - add_rule_raw(db, type, tgt, cls, perm, - effect, invert); - } - }; - } - } else if (tgt == NULL) { - struct hashtab_node *node; - if (strip_av(effect, invert)) { - ksu_hashtab_for_each(db->p_types.table, node) - { - add_rule_raw(db, src, - (struct type_datum *)node->datum, - cls, perm, effect, invert); - }; - } else { - ksu_hashtab_for_each(db->p_types.table, node) - { - struct type_datum *type = - (struct type_datum *)(node->datum); - if (type->attribute) { - add_rule_raw(db, src, type, cls, perm, - effect, invert); - } - }; - } - } else if (cls == NULL) { - struct hashtab_node *node; - ksu_hashtab_for_each(db->p_classes.table, node) - { - add_rule_raw(db, src, tgt, - (struct class_datum *)node->datum, perm, - effect, invert); - } - } else { - struct avtab_key key; - key.source_type = src->value; - key.target_type = tgt->value; - key.target_class = cls->value; - key.specified = effect; + if (src == NULL) { + struct hashtab_node *node; + if (strip_av(effect, invert)) { + ksu_hashtab_for_each(db->p_types.table, node) + { + add_rule_raw(db, + (struct type_datum *)node->datum, + tgt, cls, perm, effect, invert); + }; + } else { + ksu_hashtab_for_each(db->p_types.table, node) + { + struct type_datum *type = + (struct type_datum *)(node->datum); + if (type->attribute) { + add_rule_raw(db, type, tgt, cls, perm, + effect, invert); + } + }; + } + } else if (tgt == NULL) { + struct hashtab_node *node; + if (strip_av(effect, invert)) { + ksu_hashtab_for_each(db->p_types.table, node) + { + add_rule_raw(db, src, + (struct type_datum *)node->datum, + cls, perm, effect, invert); + }; + } else { + ksu_hashtab_for_each(db->p_types.table, node) + { + struct type_datum *type = + (struct type_datum *)(node->datum); + if (type->attribute) { + add_rule_raw(db, src, type, cls, perm, + effect, invert); + } + }; + } + } else if (cls == NULL) { + struct hashtab_node *node; + ksu_hashtab_for_each(db->p_classes.table, node) + { + add_rule_raw(db, src, tgt, + (struct class_datum *)node->datum, perm, + effect, invert); + } + } else { + struct avtab_key key; + key.source_type = src->value; + key.target_type = tgt->value; + key.target_class = cls->value; + key.specified = effect; - struct avtab_node *node = get_avtab_node(db, &key, NULL); - if (invert) { - if (perm) - node->datum.u.data &= - ~(1U << (perm->value - 1)); - else - node->datum.u.data = 0U; - } else { - if (perm) - node->datum.u.data |= 1U << (perm->value - 1); - else - node->datum.u.data = ~0U; - } - } + struct avtab_node *node = get_avtab_node(db, &key, NULL); + if (invert) { + if (perm) + node->datum.u.data &= + ~(1U << (perm->value - 1)); + else + node->datum.u.data = 0U; + } else { + if (perm) + node->datum.u.data |= 1U << (perm->value - 1); + else + node->datum.u.data = ~0U; + } + } } #define ioctl_driver(x) (x >> 8 & 0xFF) @@ -274,183 +275,183 @@ static void add_rule_raw(struct policydb *db, struct type_datum *src, #define xperm_clear(x, p) (p[x >> 5] &= ~(1 << (x & 0x1f))) static void add_xperm_rule_raw(struct policydb *db, struct type_datum *src, - struct type_datum *tgt, struct class_datum *cls, - uint16_t low, uint16_t high, int effect, - bool invert) + struct type_datum *tgt, struct class_datum *cls, + uint16_t low, uint16_t high, int effect, + bool invert) { - if (src == NULL) { - struct hashtab_node *node; - ksu_hashtab_for_each(db->p_types.table, node) - { - struct type_datum *type = - (struct type_datum *)(node->datum); - if (type->attribute) { - add_xperm_rule_raw(db, type, tgt, cls, low, - high, effect, invert); - } - }; - } else if (tgt == NULL) { - struct hashtab_node *node; - ksu_hashtab_for_each(db->p_types.table, node) - { - struct type_datum *type = - (struct type_datum *)(node->datum); - if (type->attribute) { - add_xperm_rule_raw(db, src, type, cls, low, - high, effect, invert); - } - }; - } else if (cls == NULL) { - struct hashtab_node *node; - ksu_hashtab_for_each(db->p_classes.table, node) - { - add_xperm_rule_raw(db, src, tgt, - (struct class_datum *)(node->datum), - low, high, effect, invert); - }; - } else { - struct avtab_key key; - key.source_type = src->value; - key.target_type = tgt->value; - key.target_class = cls->value; - key.specified = effect; + if (src == NULL) { + struct hashtab_node *node; + ksu_hashtab_for_each(db->p_types.table, node) + { + struct type_datum *type = + (struct type_datum *)(node->datum); + if (type->attribute) { + add_xperm_rule_raw(db, type, tgt, cls, low, + high, effect, invert); + } + }; + } else if (tgt == NULL) { + struct hashtab_node *node; + ksu_hashtab_for_each(db->p_types.table, node) + { + struct type_datum *type = + (struct type_datum *)(node->datum); + if (type->attribute) { + add_xperm_rule_raw(db, src, type, cls, low, + high, effect, invert); + } + }; + } else if (cls == NULL) { + struct hashtab_node *node; + ksu_hashtab_for_each(db->p_classes.table, node) + { + add_xperm_rule_raw(db, src, tgt, + (struct class_datum *)(node->datum), + low, high, effect, invert); + }; + } else { + struct avtab_key key; + key.source_type = src->value; + key.target_type = tgt->value; + key.target_class = cls->value; + key.specified = effect; - struct avtab_datum *datum; - struct avtab_node *node; - struct avtab_extended_perms xperms; + struct avtab_datum *datum; + struct avtab_node *node; + struct avtab_extended_perms xperms; - memset(&xperms, 0, sizeof(xperms)); - if (ioctl_driver(low) != ioctl_driver(high)) { - xperms.specified = AVTAB_XPERMS_IOCTLDRIVER; - xperms.driver = 0; - } else { - xperms.specified = AVTAB_XPERMS_IOCTLFUNCTION; - xperms.driver = ioctl_driver(low); - } - int i; - if (xperms.specified == AVTAB_XPERMS_IOCTLDRIVER) { - for (i = ioctl_driver(low); i <= ioctl_driver(high); - ++i) { - if (invert) - xperm_clear(i, xperms.perms.p); - else - xperm_set(i, xperms.perms.p); - } - } else { - for (i = ioctl_func(low); i <= ioctl_func(high); ++i) { - if (invert) - xperm_clear(i, xperms.perms.p); - else - xperm_set(i, xperms.perms.p); - } - } + memset(&xperms, 0, sizeof(xperms)); + if (ioctl_driver(low) != ioctl_driver(high)) { + xperms.specified = AVTAB_XPERMS_IOCTLDRIVER; + xperms.driver = 0; + } else { + xperms.specified = AVTAB_XPERMS_IOCTLFUNCTION; + xperms.driver = ioctl_driver(low); + } + int i; + if (xperms.specified == AVTAB_XPERMS_IOCTLDRIVER) { + for (i = ioctl_driver(low); i <= ioctl_driver(high); + ++i) { + if (invert) + xperm_clear(i, xperms.perms.p); + else + xperm_set(i, xperms.perms.p); + } + } else { + for (i = ioctl_func(low); i <= ioctl_func(high); ++i) { + if (invert) + xperm_clear(i, xperms.perms.p); + else + xperm_set(i, xperms.perms.p); + } + } - node = get_avtab_node(db, &key, &xperms); - if (!node) { - pr_warn("add_xperm_rule_raw cannot found node!\n"); - return; - } - datum = &node->datum; + node = get_avtab_node(db, &key, &xperms); + if (!node) { + pr_warn("add_xperm_rule_raw cannot found node!\n"); + return; + } + datum = &node->datum; - if (datum->u.xperms == NULL) { - datum->u.xperms = - (struct avtab_extended_perms *)(kzalloc( - sizeof(xperms), GFP_KERNEL)); - if (!datum->u.xperms) { - pr_err("alloc xperms failed\n"); - return; - } - memcpy(datum->u.xperms, &xperms, sizeof(xperms)); - } - } + if (datum->u.xperms == NULL) { + datum->u.xperms = + (struct avtab_extended_perms *)(kzalloc( + sizeof(xperms), GFP_KERNEL)); + if (!datum->u.xperms) { + pr_err("alloc xperms failed\n"); + return; + } + memcpy(datum->u.xperms, &xperms, sizeof(xperms)); + } + } } static bool add_xperm_rule(struct policydb *db, const char *s, const char *t, - const char *c, const char *range, int effect, - bool invert) + const char *c, const char *range, int effect, + bool invert) { - struct type_datum *src = NULL, *tgt = NULL; - struct class_datum *cls = NULL; + struct type_datum *src = NULL, *tgt = NULL; + struct class_datum *cls = NULL; - if (s) { - src = symtab_search(&db->p_types, s); - if (src == NULL) { - pr_info("source type %s does not exist\n", s); - return false; - } - } + if (s) { + src = symtab_search(&db->p_types, s); + if (src == NULL) { + pr_info("source type %s does not exist\n", s); + return false; + } + } - if (t) { - tgt = symtab_search(&db->p_types, t); - if (tgt == NULL) { - pr_info("target type %s does not exist\n", t); - return false; - } - } + if (t) { + tgt = symtab_search(&db->p_types, t); + if (tgt == NULL) { + pr_info("target type %s does not exist\n", t); + return false; + } + } - if (c) { - cls = symtab_search(&db->p_classes, c); - if (cls == NULL) { - pr_info("class %s does not exist\n", c); - return false; - } - } + if (c) { + cls = symtab_search(&db->p_classes, c); + if (cls == NULL) { + pr_info("class %s does not exist\n", c); + return false; + } + } - u16 low, high; + u16 low, high; - if (range) { - if (strchr(range, '-')) { - sscanf(range, "%hx-%hx", &low, &high); - } else { - sscanf(range, "%hx", &low); - high = low; - } - } else { - low = 0; - high = 0xFFFF; - } + if (range) { + if (strchr(range, '-')) { + sscanf(range, "%hx-%hx", &low, &high); + } else { + sscanf(range, "%hx", &low); + high = low; + } + } else { + low = 0; + high = 0xFFFF; + } - add_xperm_rule_raw(db, src, tgt, cls, low, high, effect, invert); - return true; + add_xperm_rule_raw(db, src, tgt, cls, low, high, effect, invert); + return true; } static bool add_type_rule(struct policydb *db, const char *s, const char *t, - const char *c, const char *d, int effect) + const char *c, const char *d, int effect) { - struct type_datum *src, *tgt, *def; - struct class_datum *cls; + struct type_datum *src, *tgt, *def; + struct class_datum *cls; - src = symtab_search(&db->p_types, s); - if (src == NULL) { - pr_info("source type %s does not exist\n", s); - return false; - } - tgt = symtab_search(&db->p_types, t); - if (tgt == NULL) { - pr_info("target type %s does not exist\n", t); - return false; - } - cls = symtab_search(&db->p_classes, c); - if (cls == NULL) { - pr_info("class %s does not exist\n", c); - return false; - } - def = symtab_search(&db->p_types, d); - if (def == NULL) { - pr_info("default type %s does not exist\n", d); - return false; - } + src = symtab_search(&db->p_types, s); + if (src == NULL) { + pr_info("source type %s does not exist\n", s); + return false; + } + tgt = symtab_search(&db->p_types, t); + if (tgt == NULL) { + pr_info("target type %s does not exist\n", t); + return false; + } + cls = symtab_search(&db->p_classes, c); + if (cls == NULL) { + pr_info("class %s does not exist\n", c); + return false; + } + def = symtab_search(&db->p_types, d); + if (def == NULL) { + pr_info("default type %s does not exist\n", d); + return false; + } - struct avtab_key key; - key.source_type = src->value; - key.target_type = tgt->value; - key.target_class = cls->value; - key.specified = effect; + struct avtab_key key; + key.source_type = src->value; + key.target_type = tgt->value; + key.target_class = cls->value; + key.specified = effect; - struct avtab_node *node = get_avtab_node(db, &key, NULL); - node->datum.u.data = def->value; + struct avtab_node *node = get_avtab_node(db, &key, NULL); + node->datum.u.data = def->value; - return true; + return true; } // 5.9.0 : static inline int hashtab_insert(struct hashtab *h, void *key, void @@ -459,504 +460,504 @@ static bool add_type_rule(struct policydb *db, const char *s, const char *t, #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) static u32 filenametr_hash(const void *k) { - const struct filename_trans_key *ft = k; - unsigned long hash; - unsigned int byte_num; - unsigned char focus; + const struct filename_trans_key *ft = k; + unsigned long hash; + unsigned int byte_num; + unsigned char focus; - hash = ft->ttype ^ ft->tclass; + hash = ft->ttype ^ ft->tclass; - byte_num = 0; - while ((focus = ft->name[byte_num++])) - hash = partial_name_hash(focus, hash); - return hash; + byte_num = 0; + while ((focus = ft->name[byte_num++])) + hash = partial_name_hash(focus, hash); + return hash; } static int filenametr_cmp(const void *k1, const void *k2) { - const struct filename_trans_key *ft1 = k1; - const struct filename_trans_key *ft2 = k2; - int v; + const struct filename_trans_key *ft1 = k1; + const struct filename_trans_key *ft2 = k2; + int v; - v = ft1->ttype - ft2->ttype; - if (v) - return v; + v = ft1->ttype - ft2->ttype; + if (v) + return v; - v = ft1->tclass - ft2->tclass; - if (v) - return v; + v = ft1->tclass - ft2->tclass; + if (v) + return v; - return strcmp(ft1->name, ft2->name); + return strcmp(ft1->name, ft2->name); } static const struct hashtab_key_params filenametr_key_params = { - .hash = filenametr_hash, - .cmp = filenametr_cmp, + .hash = filenametr_hash, + .cmp = filenametr_cmp, }; #endif static bool add_filename_trans(struct policydb *db, const char *s, - const char *t, const char *c, const char *d, - const char *o) + const char *t, const char *c, const char *d, + const char *o) { - struct type_datum *src, *tgt, *def; - struct class_datum *cls; + struct type_datum *src, *tgt, *def; + struct class_datum *cls; - src = symtab_search(&db->p_types, s); - if (src == NULL) { - pr_warn("source type %s does not exist\n", s); - return false; - } - tgt = symtab_search(&db->p_types, t); - if (tgt == NULL) { - pr_warn("target type %s does not exist\n", t); - return false; - } - cls = symtab_search(&db->p_classes, c); - if (cls == NULL) { - pr_warn("class %s does not exist\n", c); - return false; - } - def = symtab_search(&db->p_types, d); - if (def == NULL) { - pr_warn("default type %s does not exist\n", d); - return false; - } + src = symtab_search(&db->p_types, s); + if (src == NULL) { + pr_warn("source type %s does not exist\n", s); + return false; + } + tgt = symtab_search(&db->p_types, t); + if (tgt == NULL) { + pr_warn("target type %s does not exist\n", t); + return false; + } + cls = symtab_search(&db->p_classes, c); + if (cls == NULL) { + pr_warn("class %s does not exist\n", c); + return false; + } + def = symtab_search(&db->p_types, d); + if (def == NULL) { + pr_warn("default type %s does not exist\n", d); + return false; + } #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0) - struct filename_trans_key key; - key.ttype = tgt->value; - key.tclass = cls->value; - key.name = (char *)o; + struct filename_trans_key key; + key.ttype = tgt->value; + key.tclass = cls->value; + key.name = (char *)o; - struct filename_trans_datum *last = NULL; + struct filename_trans_datum *last = NULL; #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) - struct filename_trans_datum *trans = - policydb_filenametr_search(db, &key); + struct filename_trans_datum *trans = + policydb_filenametr_search(db, &key); #else - struct filename_trans_datum *trans = - hashtab_search(&db->filename_trans, &key); + struct filename_trans_datum *trans = + hashtab_search(&db->filename_trans, &key); #endif - while (trans) { - if (ebitmap_get_bit(&trans->stypes, src->value - 1)) { - // Duplicate, overwrite existing data and return - trans->otype = def->value; - return true; - } - if (trans->otype == def->value) - break; - last = trans; - trans = trans->next; - } + while (trans) { + if (ebitmap_get_bit(&trans->stypes, src->value - 1)) { + // Duplicate, overwrite existing data and return + trans->otype = def->value; + return true; + } + if (trans->otype == def->value) + break; + last = trans; + trans = trans->next; + } - if (trans == NULL) { - trans = (struct filename_trans_datum *)kcalloc(1 ,sizeof(*trans), - GFP_ATOMIC); - struct filename_trans_key *new_key = - (struct filename_trans_key *)kzalloc(sizeof(*new_key), - GFP_ATOMIC); - *new_key = key; - new_key->name = kstrdup(key.name, GFP_ATOMIC); - trans->next = last; - trans->otype = def->value; - hashtab_insert(&db->filename_trans, new_key, trans, - filenametr_key_params); - } + if (trans == NULL) { + trans = (struct filename_trans_datum *)kcalloc(sizeof(*trans), + 1, GFP_ATOMIC); + struct filename_trans_key *new_key = + (struct filename_trans_key *)kzalloc(sizeof(*new_key), + GFP_ATOMIC); + *new_key = key; + new_key->name = kstrdup(key.name, GFP_ATOMIC); + trans->next = last; + trans->otype = def->value; + hashtab_insert(&db->filename_trans, new_key, trans, + filenametr_key_params); + } - db->compat_filename_trans_count++; - return ebitmap_set_bit(&trans->stypes, src->value - 1, 1) == 0; + db->compat_filename_trans_count++; + return ebitmap_set_bit(&trans->stypes, src->value - 1, 1) == 0; #else // < 5.7.0, has no filename_trans_key, but struct filename_trans - struct filename_trans key; - key.ttype = tgt->value; - key.tclass = cls->value; - key.name = (char *)o; + struct filename_trans key; + key.ttype = tgt->value; + key.tclass = cls->value; + key.name = (char *)o; - struct filename_trans_datum *trans = - hashtab_search(db->filename_trans, &key); + struct filename_trans_datum *trans = + hashtab_search(db->filename_trans, &key); - if (trans == NULL) { - trans = (struct filename_trans_datum *)kcalloc(sizeof(*trans), - 1, GFP_ATOMIC); - if (!trans) { - pr_err("add_filename_trans: Failed to alloc datum\n"); - return false; - } - struct filename_trans *new_key = - (struct filename_trans *)kmalloc(sizeof(*new_key), - GFP_ATOMIC); - if (!new_key) { - pr_err("add_filename_trans: Failed to alloc new_key\n"); - return false; - } - *new_key = key; - new_key->name = kstrdup(key.name, GFP_ATOMIC); - trans->otype = def->value; - hashtab_insert(db->filename_trans, new_key, trans); - } + if (trans == NULL) { + trans = (struct filename_trans_datum *)kcalloc(sizeof(*trans), + 1, GFP_ATOMIC); + if (!trans) { + pr_err("add_filename_trans: Failed to alloc datum\n"); + return false; + } + struct filename_trans *new_key = + (struct filename_trans *)kzalloc(sizeof(*new_key), + GFP_ATOMIC); + if (!new_key) { + pr_err("add_filename_trans: Failed to alloc new_key\n"); + return false; + } + *new_key = key; + new_key->name = kstrdup(key.name, GFP_ATOMIC); + trans->otype = def->value; + hashtab_insert(db->filename_trans, new_key, trans); + } - return ebitmap_set_bit(&db->filename_trans_ttypes, src->value - 1, 1) == - 0; + return ebitmap_set_bit(&db->filename_trans_ttypes, src->value - 1, 1) == + 0; #endif } static bool add_genfscon(struct policydb *db, const char *fs_name, - const char *path, const char *context) + const char *path, const char *context) { - return false; + return false; } static void *ksu_realloc(void *old, size_t new_size, size_t old_size) { - // we can't use krealloc, because it may be read-only - void *new = kzalloc(new_size, GFP_ATOMIC); - if (!new) { - return NULL; - } - if (old_size) { - memcpy(new, old, old_size); - } - // we can't use kfree, because it may be read-only - // there maybe some leaks, maybe we can check ptr_write, but it's not a big deal - // kfree(old); - return new; + // we can't use krealloc, because it may be read-only + void *new = kzalloc(new_size, GFP_ATOMIC); + if (!new) { + return NULL; + } + if (old_size) { + memcpy(new, old, old_size); + } + // we can't use kfree, because it may be read-only + // there maybe some leaks, maybe we can check ptr_write, but it's not a big deal + // kfree(old); + return new; } static bool add_type(struct policydb *db, const char *type_name, bool attr) { #ifdef KSU_SUPPORT_ADD_TYPE - struct type_datum *type = symtab_search(&db->p_types, type_name); - if (type) { - pr_warn("Type %s already exists\n", type_name); - return true; - } + struct type_datum *type = symtab_search(&db->p_types, type_name); + if (type) { + pr_warn("Type %s already exists\n", type_name); + return true; + } - u32 value = ++db->p_types.nprim; - type = (struct type_datum *)kzalloc(sizeof(struct type_datum), - GFP_ATOMIC); - if (!type) { - pr_err("add_type: alloc type_datum failed.\n"); - return false; - } + u32 value = ++db->p_types.nprim; + type = (struct type_datum *)kzalloc(sizeof(struct type_datum), + GFP_ATOMIC); + if (!type) { + pr_err("add_type: alloc type_datum failed.\n"); + return false; + } - type->primary = 1; - type->value = value; - type->attribute = attr; + type->primary = 1; + type->value = value; + type->attribute = attr; - char *key = kstrdup(type_name, GFP_ATOMIC); - if (!key) { - pr_err("add_type: alloc key failed.\n"); - return false; - } + char *key = kstrdup(type_name, GFP_ATOMIC); + if (!key) { + pr_err("add_type: alloc key failed.\n"); + return false; + } - if (symtab_insert(&db->p_types, key, type)) { - pr_err("add_type: insert symtab failed.\n"); - return false; - } + if (symtab_insert(&db->p_types, key, type)) { + pr_err("add_type: insert symtab failed.\n"); + return false; + } #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) - struct ebitmap *new_type_attr_map_array = - ksu_realloc(db->type_attr_map_array, - value * sizeof(struct ebitmap), - (value - 1) * sizeof(struct ebitmap)); + struct ebitmap *new_type_attr_map_array = + ksu_realloc(db->type_attr_map_array, + value * sizeof(struct ebitmap), + (value - 1) * sizeof(struct ebitmap)); - if (!new_type_attr_map_array) { - pr_err("add_type: alloc type_attr_map_array failed\n"); - return false; - } + if (!new_type_attr_map_array) { + pr_err("add_type: alloc type_attr_map_array failed\n"); + return false; + } - struct type_datum **new_type_val_to_struct = - ksu_realloc(db->type_val_to_struct, - sizeof(*db->type_val_to_struct) * value, - sizeof(*db->type_val_to_struct) * (value - 1)); + struct type_datum **new_type_val_to_struct = + ksu_realloc(db->type_val_to_struct, + sizeof(*db->type_val_to_struct) * value, + sizeof(*db->type_val_to_struct) * (value - 1)); - if (!new_type_val_to_struct) { - pr_err("add_type: alloc type_val_to_struct failed\n"); - return false; - } + if (!new_type_val_to_struct) { + pr_err("add_type: alloc type_val_to_struct failed\n"); + return false; + } - char **new_val_to_name_types = - ksu_realloc(db->sym_val_to_name[SYM_TYPES], - sizeof(char *) * value, - sizeof(char *) * (value - 1)); - if (!new_val_to_name_types) { - pr_err("add_type: alloc val_to_name failed\n"); - return false; - } + char **new_val_to_name_types = + ksu_realloc(db->sym_val_to_name[SYM_TYPES], + sizeof(char *) * value, + sizeof(char *) * (value - 1)); + if (!new_val_to_name_types) { + pr_err("add_type: alloc val_to_name failed\n"); + return false; + } - db->type_attr_map_array = new_type_attr_map_array; - ebitmap_init(&db->type_attr_map_array[value - 1]); - ebitmap_set_bit(&db->type_attr_map_array[value - 1], value - 1, 1); + db->type_attr_map_array = new_type_attr_map_array; + ebitmap_init(&db->type_attr_map_array[value - 1]); + ebitmap_set_bit(&db->type_attr_map_array[value - 1], value - 1, 1); - db->type_val_to_struct = new_type_val_to_struct; - db->type_val_to_struct[value - 1] = type; + db->type_val_to_struct = new_type_val_to_struct; + db->type_val_to_struct[value - 1] = type; - db->sym_val_to_name[SYM_TYPES] = new_val_to_name_types; - db->sym_val_to_name[SYM_TYPES][value - 1] = key; + db->sym_val_to_name[SYM_TYPES] = new_val_to_name_types; + db->sym_val_to_name[SYM_TYPES][value - 1] = key; - int i; - for (i = 0; i < db->p_roles.nprim; ++i) { - ebitmap_set_bit(&db->role_val_to_struct[i]->types, value - 1, - 1); - } + int i; + for (i = 0; i < db->p_roles.nprim; ++i) { + ebitmap_set_bit(&db->role_val_to_struct[i]->types, value - 1, + 1); + } - return true; + return true; #elif defined(CONFIG_IS_HW_HISI) - /* + /* * Huawei use type_attr_map and type_val_to_struct. * And use ebitmap not flex_array. */ - size_t new_size = sizeof(struct ebitmap) * db->p_types.nprim; - struct ebitmap *new_type_attr_map = - (krealloc(db->type_attr_map, new_size, GFP_ATOMIC)); + size_t new_size = sizeof(struct ebitmap) * db->p_types.nprim; + struct ebitmap *new_type_attr_map = + (krealloc(db->type_attr_map, new_size, GFP_ATOMIC)); - struct type_datum **new_type_val_to_struct = - krealloc(db->type_val_to_struct, - sizeof(*db->type_val_to_struct) * db->p_types.nprim, - GFP_ATOMIC); + struct type_datum **new_type_val_to_struct = + krealloc(db->type_val_to_struct, + sizeof(*db->type_val_to_struct) * db->p_types.nprim, + GFP_ATOMIC); - if (!new_type_attr_map) { - pr_err("add_type: alloc type_attr_map failed\n"); - return false; - } + if (!new_type_attr_map) { + pr_err("add_type: alloc type_attr_map failed\n"); + return false; + } - if (!new_type_val_to_struct) { - pr_err("add_type: alloc type_val_to_struct failed\n"); - return false; - } + if (!new_type_val_to_struct) { + pr_err("add_type: alloc type_val_to_struct failed\n"); + return false; + } - char **new_val_to_name_types = - krealloc(db->sym_val_to_name[SYM_TYPES], - sizeof(char *) * db->symtab[SYM_TYPES].nprim, - GFP_KERNEL); - if (!new_val_to_name_types) { - pr_err("add_type: alloc val_to_name failed\n"); - return false; - } + char **new_val_to_name_types = + krealloc(db->sym_val_to_name[SYM_TYPES], + sizeof(char *) * db->symtab[SYM_TYPES].nprim, + GFP_KERNEL); + if (!new_val_to_name_types) { + pr_err("add_type: alloc val_to_name failed\n"); + return false; + } - db->type_attr_map = new_type_attr_map; - ebitmap_init(&db->type_attr_map[value - 1], HISI_SELINUX_EBITMAP_RO); - ebitmap_set_bit(&db->type_attr_map[value - 1], value - 1, 1); + db->type_attr_map = new_type_attr_map; + ebitmap_init(&db->type_attr_map[value - 1], HISI_SELINUX_EBITMAP_RO); + ebitmap_set_bit(&db->type_attr_map[value - 1], value - 1, 1); - db->type_val_to_struct = new_type_val_to_struct; - db->type_val_to_struct[value - 1] = type; + db->type_val_to_struct = new_type_val_to_struct; + db->type_val_to_struct[value - 1] = type; - db->sym_val_to_name[SYM_TYPES] = new_val_to_name_types; - db->sym_val_to_name[SYM_TYPES][value - 1] = key; + db->sym_val_to_name[SYM_TYPES] = new_val_to_name_types; + db->sym_val_to_name[SYM_TYPES][value - 1] = key; - int i; - for (i = 0; i < db->p_roles.nprim; ++i) { - ebitmap_set_bit(&db->role_val_to_struct[i]->types, value - 1, - 1); - } + int i; + for (i = 0; i < db->p_roles.nprim; ++i) { + ebitmap_set_bit(&db->role_val_to_struct[i]->types, value - 1, + 1); + } - return true; + return true; #else - // flex_array is not extensible, we need to create a new bigger one instead - struct flex_array *new_type_attr_map_array = - flex_array_alloc(sizeof(struct ebitmap), db->p_types.nprim, - GFP_ATOMIC | __GFP_ZERO); + // flex_array is not extensible, we need to create a new bigger one instead + struct flex_array *new_type_attr_map_array = + flex_array_alloc(sizeof(struct ebitmap), db->p_types.nprim, + GFP_ATOMIC | __GFP_ZERO); - struct flex_array *new_type_val_to_struct = - flex_array_alloc(sizeof(struct type_datum *), db->p_types.nprim, - GFP_ATOMIC | __GFP_ZERO); + struct flex_array *new_type_val_to_struct = + flex_array_alloc(sizeof(struct type_datum *), db->p_types.nprim, + GFP_ATOMIC | __GFP_ZERO); - struct flex_array *new_val_to_name_types = - flex_array_alloc(sizeof(char *), db->symtab[SYM_TYPES].nprim, - GFP_ATOMIC | __GFP_ZERO); + struct flex_array *new_val_to_name_types = + flex_array_alloc(sizeof(char *), db->symtab[SYM_TYPES].nprim, + GFP_ATOMIC | __GFP_ZERO); - if (!new_type_attr_map_array) { - pr_err("add_type: alloc type_attr_map_array failed\n"); - return false; - } + if (!new_type_attr_map_array) { + pr_err("add_type: alloc type_attr_map_array failed\n"); + return false; + } - if (!new_type_val_to_struct) { - pr_err("add_type: alloc type_val_to_struct failed\n"); - return false; - } + if (!new_type_val_to_struct) { + pr_err("add_type: alloc type_val_to_struct failed\n"); + return false; + } - if (!new_val_to_name_types) { - pr_err("add_type: alloc val_to_name failed\n"); - return false; - } + if (!new_val_to_name_types) { + pr_err("add_type: alloc val_to_name failed\n"); + return false; + } - // preallocate so we don't have to worry about the put ever failing - if (flex_array_prealloc(new_type_attr_map_array, 0, db->p_types.nprim, - GFP_ATOMIC | __GFP_ZERO)) { - pr_err("add_type: prealloc type_attr_map_array failed\n"); - return false; - } + // preallocate so we don't have to worry about the put ever failing + if (flex_array_prealloc(new_type_attr_map_array, 0, db->p_types.nprim, + GFP_ATOMIC | __GFP_ZERO)) { + pr_err("add_type: prealloc type_attr_map_array failed\n"); + return false; + } - if (flex_array_prealloc(new_type_val_to_struct, 0, db->p_types.nprim, - GFP_ATOMIC | __GFP_ZERO)) { - pr_err("add_type: prealloc type_val_to_struct_array failed\n"); - return false; - } + if (flex_array_prealloc(new_type_val_to_struct, 0, db->p_types.nprim, + GFP_ATOMIC | __GFP_ZERO)) { + pr_err("add_type: prealloc type_val_to_struct_array failed\n"); + return false; + } - if (flex_array_prealloc(new_val_to_name_types, 0, - db->symtab[SYM_TYPES].nprim, - GFP_ATOMIC | __GFP_ZERO)) { - pr_err("add_type: prealloc val_to_name_types failed\n"); - return false; - } + if (flex_array_prealloc(new_val_to_name_types, 0, + db->symtab[SYM_TYPES].nprim, + GFP_ATOMIC | __GFP_ZERO)) { + pr_err("add_type: prealloc val_to_name_types failed\n"); + return false; + } - int j; - void *old_elem; - // copy the old data or pointers to new flex arrays - for (j = 0; j < db->type_attr_map_array->total_nr_elements; j++) { - old_elem = flex_array_get(db->type_attr_map_array, j); - if (old_elem) - flex_array_put(new_type_attr_map_array, j, old_elem, - GFP_ATOMIC | __GFP_ZERO); - } + int j; + void *old_elem; + // copy the old data or pointers to new flex arrays + for (j = 0; j < db->type_attr_map_array->total_nr_elements; j++) { + old_elem = flex_array_get(db->type_attr_map_array, j); + if (old_elem) + flex_array_put(new_type_attr_map_array, j, old_elem, + GFP_ATOMIC | __GFP_ZERO); + } - for (j = 0; j < db->type_val_to_struct_array->total_nr_elements; j++) { - old_elem = flex_array_get_ptr(db->type_val_to_struct_array, j); - if (old_elem) - flex_array_put_ptr(new_type_val_to_struct, j, old_elem, - GFP_ATOMIC | __GFP_ZERO); - } + for (j = 0; j < db->type_val_to_struct_array->total_nr_elements; j++) { + old_elem = flex_array_get_ptr(db->type_val_to_struct_array, j); + if (old_elem) + flex_array_put_ptr(new_type_val_to_struct, j, old_elem, + GFP_ATOMIC | __GFP_ZERO); + } - for (j = 0; j < db->symtab[SYM_TYPES].nprim; j++) { - old_elem = - flex_array_get_ptr(db->sym_val_to_name[SYM_TYPES], j); - if (old_elem) - flex_array_put_ptr(new_val_to_name_types, j, old_elem, - GFP_ATOMIC | __GFP_ZERO); - } + for (j = 0; j < db->symtab[SYM_TYPES].nprim; j++) { + old_elem = + flex_array_get_ptr(db->sym_val_to_name[SYM_TYPES], j); + if (old_elem) + flex_array_put_ptr(new_val_to_name_types, j, old_elem, + GFP_ATOMIC | __GFP_ZERO); + } - // store the pointer of old flex arrays first, when assigning new ones we - // should free it - struct flex_array *old_fa; + // store the pointer of old flex arrays first, when assigning new ones we + // should free it + struct flex_array *old_fa; - old_fa = db->type_attr_map_array; - db->type_attr_map_array = new_type_attr_map_array; - if (old_fa) { - flex_array_free(old_fa); - } + old_fa = db->type_attr_map_array; + db->type_attr_map_array = new_type_attr_map_array; + if (old_fa) { + flex_array_free(old_fa); + } - ebitmap_init(flex_array_get(db->type_attr_map_array, value - 1)); - ebitmap_set_bit(flex_array_get(db->type_attr_map_array, value - 1), - value - 1, 1); + ebitmap_init(flex_array_get(db->type_attr_map_array, value - 1)); + ebitmap_set_bit(flex_array_get(db->type_attr_map_array, value - 1), + value - 1, 1); - old_fa = db->type_val_to_struct_array; - db->type_val_to_struct_array = new_type_val_to_struct; - if (old_fa) { - flex_array_free(old_fa); - } - flex_array_put_ptr(db->type_val_to_struct_array, value - 1, type, - GFP_ATOMIC | __GFP_ZERO); + old_fa = db->type_val_to_struct_array; + db->type_val_to_struct_array = new_type_val_to_struct; + if (old_fa) { + flex_array_free(old_fa); + } + flex_array_put_ptr(db->type_val_to_struct_array, value - 1, type, + GFP_ATOMIC | __GFP_ZERO); - old_fa = db->sym_val_to_name[SYM_TYPES]; - db->sym_val_to_name[SYM_TYPES] = new_val_to_name_types; - if (old_fa) { - flex_array_free(old_fa); - } - flex_array_put_ptr(db->sym_val_to_name[SYM_TYPES], value - 1, key, - GFP_ATOMIC | __GFP_ZERO); + old_fa = db->sym_val_to_name[SYM_TYPES]; + db->sym_val_to_name[SYM_TYPES] = new_val_to_name_types; + if (old_fa) { + flex_array_free(old_fa); + } + flex_array_put_ptr(db->sym_val_to_name[SYM_TYPES], value - 1, key, + GFP_ATOMIC | __GFP_ZERO); - int i; - for (i = 0; i < db->p_roles.nprim; ++i) { - ebitmap_set_bit(&db->role_val_to_struct[i]->types, value - 1, - 1); - } - return true; + int i; + for (i = 0; i < db->p_roles.nprim; ++i) { + ebitmap_set_bit(&db->role_val_to_struct[i]->types, value - 1, + 1); + } + return true; #endif #else - return false; + return false; #endif } static bool set_type_state(struct policydb *db, const char *type_name, - bool permissive) + bool permissive) { - struct type_datum *type; - if (type_name == NULL) { - struct hashtab_node *node; - ksu_hashtab_for_each(db->p_types.table, node) - { - type = (struct type_datum *)(node->datum); - if (ebitmap_set_bit(&db->permissive_map, type->value, - permissive)) - pr_info("Could not set bit in permissive map\n"); - }; - } else { - type = (struct type_datum *)symtab_search(&db->p_types, - type_name); - if (type == NULL) { - pr_info("type %s does not exist\n", type_name); - return false; - } - if (ebitmap_set_bit(&db->permissive_map, type->value, - permissive)) { - pr_info("Could not set bit in permissive map\n"); - return false; - } - } - return true; + struct type_datum *type; + if (type_name == NULL) { + struct hashtab_node *node; + ksu_hashtab_for_each(db->p_types.table, node) + { + type = (struct type_datum *)(node->datum); + if (ebitmap_set_bit(&db->permissive_map, type->value, + permissive)) + pr_info("Could not set bit in permissive map\n"); + }; + } else { + type = (struct type_datum *)symtab_search(&db->p_types, + type_name); + if (type == NULL) { + pr_info("type %s does not exist\n", type_name); + return false; + } + if (ebitmap_set_bit(&db->permissive_map, type->value, + permissive)) { + pr_info("Could not set bit in permissive map\n"); + return false; + } + } + return true; } static void add_typeattribute_raw(struct policydb *db, struct type_datum *type, - struct type_datum *attr) + struct type_datum *attr) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) - struct ebitmap *sattr = &db->type_attr_map_array[type->value - 1]; + struct ebitmap *sattr = &db->type_attr_map_array[type->value - 1]; #elif defined(CONFIG_IS_HW_HISI) - /* + /* * HISI_SELINUX_EBITMAP_RO is Huawei's unique features. */ - struct ebitmap *sattr = &db->type_attr_map[type->value - 1], - HISI_SELINUX_EBITMAP_RO; + struct ebitmap *sattr = &db->type_attr_map[type->value - 1], + HISI_SELINUX_EBITMAP_RO; #else - struct ebitmap *sattr = - flex_array_get(db->type_attr_map_array, type->value - 1); + struct ebitmap *sattr = + flex_array_get(db->type_attr_map_array, type->value - 1); #endif - ebitmap_set_bit(sattr, attr->value - 1, 1); + ebitmap_set_bit(sattr, attr->value - 1, 1); - struct hashtab_node *node; - struct constraint_node *n; - struct constraint_expr *e; - ksu_hashtab_for_each(db->p_classes.table, node) - { - struct class_datum *cls = (struct class_datum *)(node->datum); - for (n = cls->constraints; n; n = n->next) { - for (e = n->expr; e; e = e->next) { - if (e->expr_type == CEXPR_NAMES && - ebitmap_get_bit(&e->type_names->types, - attr->value - 1)) { - ebitmap_set_bit(&e->names, - type->value - 1, 1); - } - } - } - }; + struct hashtab_node *node; + struct constraint_node *n; + struct constraint_expr *e; + ksu_hashtab_for_each(db->p_classes.table, node) + { + struct class_datum *cls = (struct class_datum *)(node->datum); + for (n = cls->constraints; n; n = n->next) { + for (e = n->expr; e; e = e->next) { + if (e->expr_type == CEXPR_NAMES && + ebitmap_get_bit(&e->type_names->types, + attr->value - 1)) { + ebitmap_set_bit(&e->names, + type->value - 1, 1); + } + } + } + }; } static bool add_typeattribute(struct policydb *db, const char *type, - const char *attr) + const char *attr) { - struct type_datum *type_d = symtab_search(&db->p_types, type); - if (type_d == NULL) { - pr_info("type %s does not exist\n", type); - return false; - } else if (type_d->attribute) { - pr_info("type %s is an attribute\n", attr); - return false; - } + struct type_datum *type_d = symtab_search(&db->p_types, type); + if (type_d == NULL) { + pr_info("type %s does not exist\n", type); + return false; + } else if (type_d->attribute) { + pr_info("type %s is an attribute\n", attr); + return false; + } - struct type_datum *attr_d = symtab_search(&db->p_types, attr); - if (attr_d == NULL) { - pr_info("attribute %s does not exist\n", type); - return false; - } else if (!attr_d->attribute) { - pr_info("type %s is not an attribute \n", attr); - return false; - } + struct type_datum *attr_d = symtab_search(&db->p_types, attr); + if (attr_d == NULL) { + pr_info("attribute %s does not exist\n", type); + return false; + } else if (!attr_d->attribute) { + pr_info("type %s is not an attribute \n", attr); + return false; + } - add_typeattribute_raw(db, type_d, attr_d); - return true; + add_typeattribute_raw(db, type_d, attr_d); + return true; } ////////////////////////////////////////////////////////////////////////// @@ -964,106 +965,106 @@ static bool add_typeattribute(struct policydb *db, const char *type, // Operation on types bool ksu_type(struct policydb *db, const char *name, const char *attr) { - return add_type(db, name, false) && add_typeattribute(db, name, attr); + return add_type(db, name, false) && add_typeattribute(db, name, attr); } bool ksu_attribute(struct policydb *db, const char *name) { - return add_type(db, name, true); + return add_type(db, name, true); } bool ksu_permissive(struct policydb *db, const char *type) { - return set_type_state(db, type, true); + return set_type_state(db, type, true); } bool ksu_enforce(struct policydb *db, const char *type) { - return set_type_state(db, type, false); + return set_type_state(db, type, false); } bool ksu_typeattribute(struct policydb *db, const char *type, const char *attr) { - return add_typeattribute(db, type, attr); + return add_typeattribute(db, type, attr); } bool ksu_exists(struct policydb *db, const char *type) { - return symtab_search(&db->p_types, type) != NULL; + return symtab_search(&db->p_types, type) != NULL; } // Access vector rules bool ksu_allow(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *perm) + const char *cls, const char *perm) { - return add_rule(db, src, tgt, cls, perm, AVTAB_ALLOWED, false); + return add_rule(db, src, tgt, cls, perm, AVTAB_ALLOWED, false); } bool ksu_deny(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *perm) + const char *cls, const char *perm) { - return add_rule(db, src, tgt, cls, perm, AVTAB_ALLOWED, true); + return add_rule(db, src, tgt, cls, perm, AVTAB_ALLOWED, true); } bool ksu_auditallow(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *perm) + const char *cls, const char *perm) { - return add_rule(db, src, tgt, cls, perm, AVTAB_AUDITALLOW, false); + return add_rule(db, src, tgt, cls, perm, AVTAB_AUDITALLOW, false); } bool ksu_dontaudit(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *perm) + const char *cls, const char *perm) { - return add_rule(db, src, tgt, cls, perm, AVTAB_AUDITDENY, true); + return add_rule(db, src, tgt, cls, perm, AVTAB_AUDITDENY, true); } // Extended permissions access vector rules bool ksu_allowxperm(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *range) + const char *cls, const char *range) { - return add_xperm_rule(db, src, tgt, cls, range, AVTAB_XPERMS_ALLOWED, - false); + return add_xperm_rule(db, src, tgt, cls, range, AVTAB_XPERMS_ALLOWED, + false); } bool ksu_auditallowxperm(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *range) + const char *cls, const char *range) { - return add_xperm_rule(db, src, tgt, cls, range, AVTAB_XPERMS_AUDITALLOW, - false); + return add_xperm_rule(db, src, tgt, cls, range, AVTAB_XPERMS_AUDITALLOW, + false); } bool ksu_dontauditxperm(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *range) + const char *cls, const char *range) { - return add_xperm_rule(db, src, tgt, cls, range, AVTAB_XPERMS_DONTAUDIT, - false); + return add_xperm_rule(db, src, tgt, cls, range, AVTAB_XPERMS_DONTAUDIT, + false); } // Type rules bool ksu_type_transition(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *def, const char *obj) + const char *cls, const char *def, const char *obj) { - if (obj) { - return add_filename_trans(db, src, tgt, cls, def, obj); - } else { - return add_type_rule(db, src, tgt, cls, def, AVTAB_TRANSITION); - } + if (obj) { + return add_filename_trans(db, src, tgt, cls, def, obj); + } else { + return add_type_rule(db, src, tgt, cls, def, AVTAB_TRANSITION); + } } bool ksu_type_change(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *def) + const char *cls, const char *def) { - return add_type_rule(db, src, tgt, cls, def, AVTAB_CHANGE); + return add_type_rule(db, src, tgt, cls, def, AVTAB_CHANGE); } bool ksu_type_member(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *def) + const char *cls, const char *def) { - return add_type_rule(db, src, tgt, cls, def, AVTAB_MEMBER); + return add_type_rule(db, src, tgt, cls, def, AVTAB_MEMBER); } // File system labeling bool ksu_genfscon(struct policydb *db, const char *fs_name, const char *path, - const char *ctx) + const char *ctx) { - return add_genfscon(db, fs_name, path, ctx); -} + return add_genfscon(db, fs_name, path, ctx); +} \ No newline at end of file diff --git a/kernel/setuid_hook.c b/kernel/setuid_hook.c index 695555bb..a4f3f9aa 100644 --- a/kernel/setuid_hook.c +++ b/kernel/setuid_hook.c @@ -1,10 +1,12 @@ #include +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) #include +#endif #include #include #include #include -#include #include #include #include @@ -12,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -22,34 +23,20 @@ #include #include #include -#include #include #include #include #include #include -#include -#include -#include #ifdef CONFIG_KSU_SUSFS #include #endif // #ifdef CONFIG_KSU_SUSFS -#ifdef MODULE -#include -#include -#include -#include -#include -#endif - #include "allowlist.h" #include "setuid_hook.h" #include "feature.h" #include "klog.h" // IWYU pragma: keep -#include "kernel_compat.h" -#include "ksu.h" #include "manager.h" #include "selinux/selinux.h" #include "seccomp_cache.h" @@ -58,8 +45,6 @@ #include "syscall_hook_manager.h" #endif #include "kernel_umount.h" -#include "app_profile.h" - #include "sulog.h" #ifdef CONFIG_KSU_SUSFS @@ -100,97 +85,113 @@ static bool ksu_enhanced_security_enabled = false; static int enhanced_security_feature_get(u64 *value) { - *value = ksu_enhanced_security_enabled ? 1 : 0; - return 0; + *value = ksu_enhanced_security_enabled ? 1 : 0; + return 0; } static int enhanced_security_feature_set(u64 value) { - bool enable = value != 0; - ksu_enhanced_security_enabled = enable; - pr_info("enhanced_security: set to %d\n", enable); - return 0; + bool enable = value != 0; + ksu_enhanced_security_enabled = enable; + pr_info("enhanced_security: set to %d\n", enable); + return 0; } static const struct ksu_feature_handler enhanced_security_handler = { - .feature_id = KSU_FEATURE_ENHANCED_SECURITY, - .name = "enhanced_security", - .get_handler = enhanced_security_feature_get, - .set_handler = enhanced_security_feature_set, + .feature_id = KSU_FEATURE_ENHANCED_SECURITY, + .name = "enhanced_security", + .get_handler = enhanced_security_feature_get, + .set_handler = enhanced_security_feature_set, }; static inline bool is_allow_su(void) { - if (is_manager()) { - // we are manager, allow! - return true; - } - return ksu_is_allow_uid_for_current(current_uid().val); + if (is_manager()) { + // we are manager, allow! + return true; + } + return ksu_is_allow_uid_for_current(current_uid().val); } +// force_sig kcompat, TODO: move it out of core_hook.c +// https://elixir.bootlin.com/linux/v5.3-rc1/source/kernel/signal.c#L1613 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0) +#define __force_sig(sig) force_sig(sig) +#else +#define __force_sig(sig) force_sig(sig, current) +#endif +extern void disable_seccomp(struct task_struct *tsk); + #ifndef CONFIG_KSU_SUSFS int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid) { - uid_t new_uid = ruid; + // we rely on the fact that zygote always call setresuid(3) with same uids + uid_t new_uid = ruid; uid_t old_uid = current_uid().val; - - pr_info("handle_setresuid from %d to %d\n", old_uid, new_uid); - // if old process is root, ignore it. - if (old_uid != 0 && ksu_enhanced_security_enabled) { - // disallow any non-ksu domain escalation from non-root to root! - // euid is what we care about here as it controls permission - if (unlikely(euid == 0)) { - if (!is_ksu_domain()) { - pr_warn("find suspicious EoP: %d %s, from %d to %d\n", - current->pid, current->comm, old_uid, new_uid); - ksu_force_sig(SIGKILL); - return 0; - } - } - // disallow appuid decrease to any other uid if it is not allowed to su - if (is_appuid(old_uid)) { - if (euid < current_euid().val && !ksu_is_allow_uid_for_current(old_uid)) { - pr_warn("find suspicious EoP: %d %s, from %d to %d\n", - current->pid, current->comm, old_uid, new_uid); - ksu_force_sig(SIGKILL); - return 0; - } - } - return 0; - } + if (old_uid != new_uid) + pr_info("handle_setresuid from %d to %d\n", old_uid, new_uid); - // if on private space, see if its possibly the manager - if (new_uid > PER_USER_RANGE && new_uid % PER_USER_RANGE == ksu_get_manager_uid()) { - ksu_set_manager_uid(new_uid); - } + // if old process is root, ignore it. + if (old_uid != 0 && ksu_enhanced_security_enabled) { + // disallow any non-ksu domain escalation from non-root to root! + // euid is what we care about here as it controls permission + if (unlikely(euid == 0)) { + if (!is_ksu_domain()) { + pr_warn("find suspicious EoP: %d %s, from %d to %d\n", + current->pid, current->comm, old_uid, + new_uid); + __force_sig(SIGKILL); + return 0; + } + } + // disallow appuid decrease to any other uid if it is not allowed to su + if (is_appuid(old_uid)) { + if (euid < current_euid().val && + !ksu_is_allow_uid_for_current(old_uid)) { + pr_warn("find suspicious EoP: %d %s, from %d to %d\n", + current->pid, current->comm, old_uid, + new_uid); + __force_sig(SIGKILL); + return 0; + } + } + return 0; + } + + // if on private space, see if its possibly the manager + if (new_uid > PER_USER_RANGE && + new_uid % PER_USER_RANGE == ksu_get_manager_uid()) { + ksu_set_manager_uid(new_uid); + } #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) - if (ksu_get_manager_uid() == new_uid) { - pr_info("install fd for manager: %d\n", new_uid); - ksu_install_fd(); - spin_lock_irq(¤t->sighand->siglock); - ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot); - ksu_set_task_tracepoint_flag(current); - spin_unlock_irq(¤t->sighand->siglock); - return 0; - } - - if (ksu_is_allow_uid_for_current(new_uid)) { - if (current->seccomp.mode == SECCOMP_MODE_FILTER && - current->seccomp.filter) { - spin_lock_irq(¤t->sighand->siglock); - ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot); - spin_unlock_irq(¤t->sighand->siglock); - } - ksu_set_task_tracepoint_flag(current); - } else { - ksu_clear_task_tracepoint_flag_if_needed(current); - } -#else - if (ksu_is_allow_uid_for_current(new_uid)) { + if (ksu_get_manager_uid() == new_uid) { + pr_info("install fd for ksu manager(uid=%d)\n", new_uid); + ksu_install_fd(); spin_lock_irq(¤t->sighand->siglock); - disable_seccomp(); + ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot); + ksu_set_task_tracepoint_flag(current); + spin_unlock_irq(¤t->sighand->siglock); + return 0; + } + + if (ksu_is_allow_uid_for_current(new_uid)) { + if (current->seccomp.mode == SECCOMP_MODE_FILTER && + current->seccomp.filter) { + spin_lock_irq(¤t->sighand->siglock); + ksu_seccomp_allow_cache(current->seccomp.filter, + __NR_reboot); + spin_unlock_irq(¤t->sighand->siglock); + } + ksu_set_task_tracepoint_flag(current); + } else { + ksu_clear_task_tracepoint_flag_if_needed(current); + } +#else + if (ksu_is_allow_uid_for_current(new_uid)) { + spin_lock_irq(¤t->sighand->siglock); + disable_seccomp(current); spin_unlock_irq(¤t->sighand->siglock); if (ksu_get_manager_uid() == new_uid) { @@ -203,10 +204,10 @@ int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid) } #endif - // Handle kernel umount - ksu_handle_umount(old_uid, new_uid); + // Handle kernel umount + ksu_handle_umount(old_uid, new_uid); - return 0; + return 0; } #else extern bool ksu_kernel_umount_enabled; @@ -224,7 +225,7 @@ int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid){ if (!is_ksu_domain()) { pr_warn("find suspicious EoP: %d %s, from %d to %d\n", current->pid, current->comm, old_uid, new_uid); - ksu_force_sig(SIGKILL); + __force_sig(SIGKILL); return 0; } } @@ -233,7 +234,7 @@ int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid){ if (euid < current_euid().val && !ksu_is_allow_uid_for_current(old_uid)) { pr_warn("find suspicious EoP: %d %s, from %d to %d\n", current->pid, current->comm, old_uid, new_uid); - ksu_force_sig(SIGKILL); + __force_sig(SIGKILL); return 0; } } @@ -260,18 +261,30 @@ int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid){ // will always return true, that's why we need to explicitly check if new_uid belongs to // ksu manager #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) - if (ksu_get_manager_uid() == new_uid % 100000) { - pr_info("install fd for manager: %d\n", new_uid); - ksu_install_fd(); - spin_lock_irq(¤t->sighand->siglock); - ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot); - spin_unlock_irq(¤t->sighand->siglock); - return 0; - } -#else - if (ksu_is_allow_uid_for_current(new_uid)) { + if (ksu_get_manager_uid() == new_uid) { + pr_info("install fd for ksu manager(uid=%d)\n", new_uid); + ksu_install_fd(); spin_lock_irq(¤t->sighand->siglock); - disable_seccomp(); + ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot); + spin_unlock_irq(¤t->sighand->siglock); + return 0; + } + + if (ksu_is_allow_uid_for_current(new_uid)) { + if (current->seccomp.mode == SECCOMP_MODE_FILTER && + current->seccomp.filter) { + spin_lock_irq(¤t->sighand->siglock); + ksu_seccomp_allow_cache(current->seccomp.filter, + __NR_reboot); + spin_unlock_irq(¤t->sighand->siglock); + } + } else { + ksu_clear_task_tracepoint_flag_if_needed(current); + } +#else + if (ksu_is_allow_uid_for_current(new_uid)) { + spin_lock_irq(¤t->sighand->siglock); + disable_seccomp(current); spin_unlock_irq(¤t->sighand->siglock); if (ksu_get_manager_uid() == new_uid) { @@ -293,16 +306,6 @@ int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid){ if (unlikely(is_some_system_uid(new_uid) && susfs_is_umount_for_zygote_system_process_enabled)) { goto do_umount; } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) - if (ksu_is_allow_uid_for_current(new_uid)) { - if (current->seccomp.mode == SECCOMP_MODE_FILTER && - current->seccomp.filter) { - spin_lock_irq(¤t->sighand->siglock); - ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot); - spin_unlock_irq(¤t->sighand->siglock); - } - } -#endif return 0; @@ -341,15 +344,15 @@ skip_try_umount: void ksu_setuid_hook_init(void) { - ksu_kernel_umount_init(); - if (ksu_register_feature_handler(&enhanced_security_handler)) { - pr_err("Failed to register enhanced security feature handler\n"); - } + ksu_kernel_umount_init(); + if (ksu_register_feature_handler(&enhanced_security_handler)) { + pr_err("Failed to register enhanced security feature handler\n"); + } } void ksu_setuid_hook_exit(void) { - pr_info("ksu_core_exit\n"); - ksu_kernel_umount_exit(); - ksu_unregister_feature_handler(KSU_FEATURE_ENHANCED_SECURITY); -} + pr_info("ksu_core_exit\n"); + ksu_kernel_umount_exit(); + ksu_unregister_feature_handler(KSU_FEATURE_ENHANCED_SECURITY); +} \ No newline at end of file diff --git a/kernel/setuid_hook.h b/kernel/setuid_hook.h index fc5b93a0..f1016290 100644 --- a/kernel/setuid_hook.h +++ b/kernel/setuid_hook.h @@ -1,14 +1,12 @@ -#ifndef __KSU_H_KSU_CORE -#define __KSU_H_KSU_CORE +#ifndef __KSU_H_KSU_SETUID_HOOK +#define __KSU_H_KSU_SETUID_HOOK #include #include -#include "apk_sign.h" -#include void ksu_setuid_hook_init(void); void ksu_setuid_hook_exit(void); int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid); -#endif +#endif \ No newline at end of file diff --git a/kernel/sulog.c b/kernel/sulog.c index 00b8b1ca..21e11c39 100644 --- a/kernel/sulog.c +++ b/kernel/sulog.c @@ -13,8 +13,9 @@ #include #include -#include "klog.h" #include "sulog.h" +#include "klog.h" +#include "kernel_compat.h" #include "ksu.h" #include "feature.h" @@ -164,7 +165,7 @@ static void sulog_work_handler(struct work_struct *work) if (list_empty(&local_queue)) return; - fp = filp_open(SULOG_PATH, O_WRONLY | O_CREAT | O_APPEND, 0640); + fp = ksu_filp_open_compat(SULOG_PATH, O_WRONLY | O_CREAT | O_APPEND, 0640); if (IS_ERR(fp)) { pr_err("sulog: failed to open log file: %ld\n", PTR_ERR(fp)); goto cleanup; @@ -179,7 +180,7 @@ static void sulog_work_handler(struct work_struct *work) } list_for_each_entry(entry, &local_queue, list) - kernel_write(fp, entry->content, strlen(entry->content), &pos); + ksu_kernel_write_compat(fp, entry->content, strlen(entry->content), &pos); vfs_fsync(fp, 0); filp_close(fp, 0); diff --git a/kernel/supercalls.c b/kernel/supercalls.c index d23738d9..303fd897 100644 --- a/kernel/supercalls.c +++ b/kernel/supercalls.c @@ -421,64 +421,74 @@ static int do_set_feature(void __user *arg) return 0; } -static int do_get_wrapper_fd(void __user *arg) { - if (!ksu_file_sid) { - return -EINVAL; - } - - struct ksu_get_wrapper_fd_cmd cmd; - int ret; - - if (copy_from_user(&cmd, arg, sizeof(cmd))) { - pr_err("get_wrapper_fd: copy_from_user failed\n"); - return -EFAULT; - } - - struct file* f = fget(cmd.fd); - if (!f) { - return -EBADF; - } - - struct ksu_file_wrapper *data = ksu_create_file_wrapper(f); - if (data == NULL) { - ret = -ENOMEM; - goto put_orig_file; - } - +// kcompat for older kernel #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0) #define getfd_secure anon_inode_create_getfd -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) +#elif defined(KSU_HAS_GETFD_SECURE) #define getfd_secure anon_inode_getfd_secure #else -#define getfd_secure anon_inode_getfd +// technically not a secure inode, but, this is the only way so. +#define getfd_secure(name, ops, data, flags, __unused) \ + anon_inode_getfd(name, ops, data, flags) #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) - ret = getfd_secure("[ksu_fdwrapper]", &data->ops, data, f->f_flags, NULL); + +static int do_get_wrapper_fd(void __user *arg) +{ + if (!ksu_file_sid) { + return -EINVAL; + } + + struct ksu_get_wrapper_fd_cmd cmd; + int ret; + + if (copy_from_user(&cmd, arg, sizeof(cmd))) { + pr_err("get_wrapper_fd: copy_from_user failed\n"); + return -EFAULT; + } + + struct file *f = fget(cmd.fd); + if (!f) { + return -EBADF; + } + + struct ksu_file_wrapper *data = ksu_create_file_wrapper(f); + if (data == NULL) { + ret = -ENOMEM; + goto put_orig_file; + } + + ret = getfd_secure("[ksu_fdwrapper]", &data->ops, data, f->f_flags, + NULL); + if (ret < 0) { + pr_err("ksu_fdwrapper: getfd failed: %d\n", ret); + goto put_wrapper_data; + } + struct file *pf = fget(ret); + + struct inode *wrapper_inode = file_inode(pf); + // copy original inode mode + wrapper_inode->i_mode = file_inode(f)->i_mode; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) || \ + defined(KSU_OPTIONAL_SELINUX_INODE) + struct inode_security_struct *sec = selinux_inode(wrapper_inode); #else - ret = getfd_secure("[ksu_fdwrapper]", &data->ops, data, f->f_flags); + struct inode_security_struct *sec = + (struct inode_security_struct *)wrapper_inode->i_security; #endif - if (ret < 0) { - pr_err("ksu_fdwrapper: getfd failed: %d\n", ret); - goto put_wrapper_data; - } - struct file* pf = fget(ret); - struct inode* wrapper_inode = file_inode(pf); - // copy original inode mode - wrapper_inode->i_mode = file_inode(f)->i_mode; - struct inode_security_struct *sec = selinux_inode(wrapper_inode); - if (sec) { - sec->sid = ksu_file_sid; - } + if (sec) { + sec->sid = ksu_file_sid; + } - fput(pf); - goto put_orig_file; + fput(pf); + goto put_orig_file; put_wrapper_data: - ksu_delete_file_wrapper(data); + ksu_delete_file_wrapper(data); put_orig_file: - fput(f); + fput(f); - return ret; + return ret; } static int do_manage_mark(void __user *arg) @@ -950,11 +960,7 @@ static void ksu_install_fd_tw_func(struct callback_head *cb) if (copy_to_user(tw->outp, &fd, sizeof(fd))) { pr_err("install ksu fd reply err\n"); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) - close_fd(fd); -#else - __close_fd(current->files, fd); -#endif + do_close_fd(fd); } kfree(tw); diff --git a/kernel/throne_comm.c b/kernel/throne_comm.c index 07de7d41..b4a065d1 100644 --- a/kernel/throne_comm.c +++ b/kernel/throne_comm.c @@ -7,8 +7,9 @@ #include "ksu.h" #include "klog.h" -#include "throne_comm.h" #include "ksu.h" +#include "kernel_compat.h" +#include "throne_comm.h" #define PROC_UID_SCANNER "ksu_uid_scanner" #define UID_SCANNER_STATE_FILE "/data/adb/ksu/.uid_scanner" @@ -49,13 +50,13 @@ static void do_save_throne_state(struct work_struct *work) char state_char = ksu_uid_scanner_enabled ? '1' : '0'; loff_t off = 0; - fp = filp_open(UID_SCANNER_STATE_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0644); + fp = ksu_filp_open_compat(UID_SCANNER_STATE_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (IS_ERR(fp)) { pr_err("save_throne_state create file failed: %ld\n", PTR_ERR(fp)); return; } - if (kernel_write(fp, &state_char, sizeof(state_char), &off) != sizeof(state_char)) { + if (ksu_kernel_write_compat(fp, &state_char, sizeof(state_char), &off) != sizeof(state_char)) { pr_err("save_throne_state write failed\n"); goto exit; } @@ -73,14 +74,14 @@ void do_load_throne_state(struct work_struct *work) loff_t off = 0; ssize_t ret; - fp = filp_open(UID_SCANNER_STATE_FILE, O_RDONLY, 0); + fp = ksu_filp_open_compat(UID_SCANNER_STATE_FILE, O_RDONLY, 0); if (IS_ERR(fp)) { pr_info("throne state file not found, using default: disabled\n"); ksu_uid_scanner_enabled = false; return; } - ret = kernel_read(fp, &state_char, sizeof(state_char), &off); + ret = ksu_kernel_read_compat(fp, &state_char, sizeof(state_char), &off); if (ret != sizeof(state_char)) { pr_err("load_throne_state read err: %zd\n", ret); ksu_uid_scanner_enabled = false; diff --git a/kernel/throne_tracker.c b/kernel/throne_tracker.c index f35173e7..49c2310f 100644 --- a/kernel/throne_tracker.c +++ b/kernel/throne_tracker.c @@ -13,6 +13,7 @@ #include "manager.h" #include "throne_tracker.h" #include "apk_sign.h" +#include "kernel_compat.h" #include "dynamic_manager.h" #include "throne_comm.h" @@ -38,7 +39,7 @@ static int uid_from_um_list(struct list_head *uid_list) ssize_t nr; int cnt = 0; - fp = filp_open(KSU_UID_LIST_PATH, O_RDONLY, 0); + fp = ksu_filp_open_compat(KSU_UID_LIST_PATH, O_RDONLY, 0); if (IS_ERR(fp)) return -ENOENT; @@ -55,7 +56,7 @@ static int uid_from_um_list(struct list_head *uid_list) return -ENOMEM; } - nr = kernel_read(fp, buf, size, &pos); + nr = ksu_kernel_read_compat(fp, buf, size, &pos); filp_close(fp, NULL); if (nr != size) { pr_err("uid_list: short read %zd/%lld\n", nr, size); @@ -361,7 +362,7 @@ void search_manager(const char *path, int depth, struct list_head *uid_data) struct file *file; if (!stop) { - file = filp_open(pos->dirpath, O_RDONLY | O_NOFOLLOW, 0); + file = ksu_filp_open_compat(pos->dirpath, O_RDONLY | O_NOFOLLOW, 0); if (IS_ERR(file)) { pr_err("Failed to open directory: %s, err: %ld\n", pos->dirpath, PTR_ERR(file)); @@ -452,7 +453,7 @@ void track_throne(bool prune_only) } { - fp = filp_open(SYSTEM_PACKAGES_LIST_PATH, O_RDONLY, 0); + fp = ksu_filp_open_compat(SYSTEM_PACKAGES_LIST_PATH, O_RDONLY, 0); if (IS_ERR(fp)) { pr_err("%s: open " SYSTEM_PACKAGES_LIST_PATH " failed: %ld\n", __func__, PTR_ERR(fp)); return; @@ -460,13 +461,13 @@ void track_throne(bool prune_only) for (;;) { ssize_t count = - kernel_read(fp, &chr, sizeof(chr), &pos); + ksu_kernel_read_compat(fp, &chr, sizeof(chr), &pos); if (count != sizeof(chr)) break; if (chr != '\n') continue; - count = kernel_read(fp, buf, sizeof(buf), + count = ksu_kernel_read_compat(fp, buf, sizeof(buf), &line_start); struct uid_data *data = kzalloc(sizeof(struct uid_data), GFP_ATOMIC);