Synchronise some modifications
Co-authored-by: Ylarod <me@ylarod.cn> Co-authored-by: 5ec1cff <56485584+5ec1cff@users.noreply.github.com> Co-authored-by: backslashxx <118538522+backslashxx@users.noreply.github.com> Co-authored-by: u9521 <63995396+u9521@users.noreply.github.com> Co-authored-by: Wang Han <416810799@qq.com> Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Co-authored-by: Faris <rissu.ntk@gmail.com>
This commit is contained in:
@@ -22,7 +22,6 @@ config KSU_MULTI_MANAGER_SUPPORT
|
|||||||
help
|
help
|
||||||
Enable multi KernelSU manager support
|
Enable multi KernelSU manager support
|
||||||
|
|
||||||
|
|
||||||
config KSU_ALLOWLIST_WORKAROUND
|
config KSU_ALLOWLIST_WORKAROUND
|
||||||
bool "KernelSU Session Keyring Init workaround"
|
bool "KernelSU Session Keyring Init workaround"
|
||||||
depends on KSU
|
depends on KSU
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
kernelsu-objs := ksu.o
|
kernelsu-objs := ksu.o
|
||||||
kernelsu-objs += allowlist.o
|
kernelsu-objs += allowlist.o
|
||||||
kernelsu-objs += app_profile.o
|
|
||||||
kernelsu-objs += dynamic_manager.o
|
kernelsu-objs += dynamic_manager.o
|
||||||
|
kernelsu-objs += app_profile.o
|
||||||
kernelsu-objs += apk_sign.o
|
kernelsu-objs += apk_sign.o
|
||||||
kernelsu-objs += sucompat.o
|
kernelsu-objs += sucompat.o
|
||||||
kernelsu-objs += syscall_hook_manager.o
|
kernelsu-objs += syscall_hook_manager.o
|
||||||
kernelsu-objs += throne_tracker.o
|
kernelsu-objs += throne_tracker.o
|
||||||
kernelsu-objs += pkg_observer.o
|
kernelsu-objs += pkg_observer.o
|
||||||
kernelsu-objs += setuid_hook.o
|
kernelsu-objs += setuid_hook.o
|
||||||
|
kernelsu-objs += lsm_hooks.o
|
||||||
kernelsu-objs += kernel_compat.o
|
kernelsu-objs += kernel_compat.o
|
||||||
kernelsu-objs += kernel_umount.o
|
kernelsu-objs += kernel_umount.o
|
||||||
kernelsu-objs += supercalls.o
|
kernelsu-objs += supercalls.o
|
||||||
kernelsu-objs += feature.o
|
kernelsu-objs += feature.o
|
||||||
|
kernelsu-objs += throne_tracker.o
|
||||||
kernelsu-objs += ksud.o
|
kernelsu-objs += ksud.o
|
||||||
kernelsu-objs += embed_ksud.o
|
kernelsu-objs += embed_ksud.o
|
||||||
kernelsu-objs += seccomp_cache.o
|
kernelsu-objs += seccomp_cache.o
|
||||||
kernelsu-objs += file_wrapper.o
|
kernelsu-objs += file_wrapper.o
|
||||||
kernelsu-objs += throne_comm.o
|
kernelsu-objs += throne_comm.o
|
||||||
kernelsu-objs += sulog.o
|
kernelsu-objs += sulog.o
|
||||||
kernelsu-objs += lsm_hook.o
|
|
||||||
|
|
||||||
ifeq ($(CONFIG_KSU_MANUAL_SU), y)
|
ifeq ($(CONFIG_KSU_MANUAL_SU), y)
|
||||||
ccflags-y += -DCONFIG_KSU_MANUAL_SU
|
ccflags-y += -DCONFIG_KSU_MANUAL_SU
|
||||||
kernelsu-objs += manual_su.o
|
kernelsu-objs += manual_su.o
|
||||||
@@ -93,6 +93,8 @@ endif
|
|||||||
ccflags-y += -DKSU_VERSION=$(KSU_VERSION)
|
ccflags-y += -DKSU_VERSION=$(KSU_VERSION)
|
||||||
ccflags-y += -DKSU_VERSION_FULL=\"$(KSU_VERSION_FULL)\"
|
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)
|
ifeq ($(CONFIG_KSU_MANUAL_HOOK), y)
|
||||||
ccflags-y += -DKSU_MANUAL_HOOK
|
ccflags-y += -DKSU_MANUAL_HOOK
|
||||||
$(info -- SukiSU: KSU_MANUAL_HOOK)
|
$(info -- SukiSU: KSU_MANUAL_HOOK)
|
||||||
@@ -126,6 +128,14 @@ else
|
|||||||
$(info -- KPM is disabled)
|
$(info -- KPM is disabled)
|
||||||
endif
|
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
|
# Handle optional backports
|
||||||
ifeq ($(shell grep -q "strncpy_from_user_nofault" $(srctree)/include/linux/uaccess.h; echo $$?),0)
|
ifeq ($(shell grep -q "strncpy_from_user_nofault" $(srctree)/include/linux/uaccess.h; echo $$?),0)
|
||||||
ccflags-y += -DKSU_OPTIONAL_STRNCPY
|
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)
|
ifeq ($(shell grep "ssize_t kernel_write" $(srctree)/fs/read_write.c | grep -q "const void" ; echo $$?),0)
|
||||||
ccflags-y += -DKSU_OPTIONAL_KERNEL_WRITE
|
ccflags-y += -DKSU_OPTIONAL_KERNEL_WRITE
|
||||||
endif
|
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)
|
ifeq ($(shell grep -q "inode_security_struct\s\+\*selinux_inode" $(srctree)/security/selinux/include/objsec.h; echo $$?),0)
|
||||||
ccflags-y += -DKSU_OPTIONAL_SELINUX_INODE
|
ccflags-y += -DKSU_OPTIONAL_SELINUX_INODE
|
||||||
endif
|
endif
|
||||||
ifeq ($(shell grep -q "int\s\+path_umount" $(srctree)/fs/namespace.c; echo $$?),0)
|
ifeq ($(shell grep -q "task_security_struct\s\+\*selinux_cred" $(srctree)/security/selinux/include/objsec.h; echo $$?),0)
|
||||||
ccflags-y += -DKSU_HAS_PATH_UMOUNT
|
ccflags-y += -DKSU_OPTIONAL_SELINUX_CRED
|
||||||
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)
|
|
||||||
endif
|
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
|
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)
|
ifeq ($(shell grep -q "CONFIG_KDP_CRED" $(srctree)/kernel/cred.c; echo $$?),0)
|
||||||
ccflags-y += -DSAMSUNG_UH_DRIVER_EXIST
|
ccflags-y += -DSAMSUNG_UH_DRIVER_EXIST
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Samsung SELinux Porting
|
|
||||||
ifeq ($(shell grep -q "SEC_SELINUX_PORTING_COMMON" $(srctree)/security/selinux/avc.c; echo $$?),0)
|
ifeq ($(shell grep -q "SEC_SELINUX_PORTING_COMMON" $(srctree)/security/selinux/avc.c; echo $$?),0)
|
||||||
ccflags-y += -DSAMSUNG_SELINUX_PORTING
|
ccflags-y += -DSAMSUNG_SELINUX_PORTING
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Function proc_ops check
|
# Function proc_ops check
|
||||||
ifeq ($(shell grep -q "struct proc_ops " $(srctree)/include/linux/proc_fs.h; echo $$?),0)
|
ifeq ($(shell grep -q "struct proc_ops " $(srctree)/include/linux/proc_fs.h; echo $$?),0)
|
||||||
ccflags-y += -DKSU_COMPAT_HAS_PROC_OPS
|
ccflags-y += -DKSU_COMPAT_HAS_PROC_OPS
|
||||||
endif
|
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
|
# Custom Signs
|
||||||
ifdef KSU_EXPECTED_SIZE
|
ifdef KSU_EXPECTED_SIZE
|
||||||
ccflags-y += -DEXPECTED_SIZE=$(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))
|
$(info -- SukiSU Manager package name: $(KSU_MANAGER_PACKAGE))
|
||||||
endif
|
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-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat
|
||||||
ccflags-y += -Wno-declaration-after-statement -Wno-unused-function -Wno-unused-variable
|
ccflags-y += -Wno-declaration-after-statement -Wno-unused-function -Wno-unused-variable
|
||||||
|
|||||||
@@ -21,10 +21,10 @@
|
|||||||
|
|
||||||
#include "klog.h" // IWYU pragma: keep
|
#include "klog.h" // IWYU pragma: keep
|
||||||
#include "ksud.h"
|
#include "ksud.h"
|
||||||
#include "kernel_compat.h"
|
|
||||||
#include "selinux/selinux.h"
|
#include "selinux/selinux.h"
|
||||||
#include "allowlist.h"
|
#include "allowlist.h"
|
||||||
#include "manager.h"
|
#include "manager.h"
|
||||||
|
#include "kernel_compat.h"
|
||||||
#ifndef CONFIG_KSU_SUSFS
|
#ifndef CONFIG_KSU_SUSFS
|
||||||
#include "syscall_hook_manager.h"
|
#include "syscall_hook_manager.h"
|
||||||
#endif // #ifndef CONFIG_KSU_SUSFS
|
#endif // #ifndef CONFIG_KSU_SUSFS
|
||||||
@@ -41,61 +41,59 @@ static DEFINE_MUTEX(allowlist_mutex);
|
|||||||
static struct root_profile default_root_profile;
|
static struct root_profile default_root_profile;
|
||||||
static struct non_root_profile default_non_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
|
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 int allow_list_pointer __read_mostly = 0;
|
||||||
|
|
||||||
static void remove_uid_from_arr(uid_t uid)
|
static void remove_uid_from_arr(uid_t uid)
|
||||||
{
|
{
|
||||||
int *temp_arr;
|
int *temp_arr;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
if (allow_list_pointer == 0)
|
if (allow_list_pointer == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
temp_arr = kzalloc(sizeof(allow_list_arr), GFP_KERNEL);
|
temp_arr = kzalloc(sizeof(allow_list_arr), GFP_KERNEL);
|
||||||
if (temp_arr == NULL) {
|
if (temp_arr == NULL) {
|
||||||
pr_err("%s: unable to allocate memory\n", __func__);
|
pr_err("%s: unable to allocate memory\n", __func__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = j = 0; i < allow_list_pointer; i++) {
|
for (i = j = 0; i < allow_list_pointer; i++) {
|
||||||
if (allow_list_arr[i] == uid)
|
if (allow_list_arr[i] == uid)
|
||||||
continue;
|
continue;
|
||||||
temp_arr[j++] = allow_list_arr[i];
|
temp_arr[j++] = allow_list_arr[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
allow_list_pointer = j;
|
allow_list_pointer = j;
|
||||||
|
|
||||||
for (; j < ARRAY_SIZE(allow_list_arr); j++)
|
for (; j < ARRAY_SIZE(allow_list_arr); j++)
|
||||||
temp_arr[j] = -1;
|
temp_arr[j] = -1;
|
||||||
|
|
||||||
memcpy(&allow_list_arr, temp_arr, PAGE_SIZE);
|
memcpy(&allow_list_arr, temp_arr, PAGE_SIZE);
|
||||||
kfree(temp_arr);
|
kfree(temp_arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_default_profiles(void)
|
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.uid = 0;
|
||||||
default_root_profile.gid = 0;
|
default_root_profile.gid = 0;
|
||||||
default_root_profile.groups_count = 1;
|
default_root_profile.groups_count = 1;
|
||||||
default_root_profile.groups[0] = 0;
|
default_root_profile.groups[0] = 0;
|
||||||
memcpy(&default_root_profile.capabilities.effective, &full_cap,
|
memcpy(&default_root_profile.capabilities.effective, &full_cap,
|
||||||
sizeof(default_root_profile.capabilities.effective));
|
sizeof(default_root_profile.capabilities.effective));
|
||||||
default_root_profile.namespaces = 0;
|
default_root_profile.namespaces = 0;
|
||||||
strcpy(default_root_profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN);
|
strcpy(default_root_profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN);
|
||||||
|
|
||||||
// This means that we will umount modules by default!
|
// This means that we will umount modules by default!
|
||||||
default_non_root_profile.umount_modules = true;
|
default_non_root_profile.umount_modules = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct perm_data {
|
struct perm_data {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
struct app_profile profile;
|
struct app_profile profile;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct list_head allow_list;
|
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"
|
#define KERNEL_SU_ALLOWLIST "/data/adb/ksu/.allowlist"
|
||||||
|
|
||||||
|
void persistent_allow_list(void);
|
||||||
|
|
||||||
void ksu_show_allow_list(void)
|
void ksu_show_allow_list(void)
|
||||||
{
|
{
|
||||||
struct perm_data *p = NULL;
|
struct perm_data *p = NULL;
|
||||||
struct list_head *pos = NULL;
|
struct list_head *pos = NULL;
|
||||||
pr_info("ksu_show_allow_list\n");
|
pr_info("ksu_show_allow_list\n");
|
||||||
list_for_each (pos, &allow_list) {
|
list_for_each (pos, &allow_list) {
|
||||||
p = list_entry(pos, struct perm_data, list);
|
p = list_entry(pos, struct perm_data, list);
|
||||||
pr_info("uid :%d, allow: %d\n", p->profile.current_uid,
|
pr_info("uid :%d, allow: %d\n", p->profile.current_uid,
|
||||||
p->profile.allow_su);
|
p->profile.allow_su);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_KSU_DEBUG
|
#ifdef CONFIG_KSU_DEBUG
|
||||||
static void ksu_grant_root_to_shell(void)
|
static void ksu_grant_root_to_shell(void)
|
||||||
{
|
{
|
||||||
struct app_profile profile = {
|
struct app_profile profile = {
|
||||||
.version = KSU_APP_PROFILE_VER,
|
.version = KSU_APP_PROFILE_VER,
|
||||||
.allow_su = true,
|
.allow_su = true,
|
||||||
.current_uid = 2000,
|
.current_uid = 2000,
|
||||||
};
|
};
|
||||||
strcpy(profile.key, "com.android.shell");
|
strcpy(profile.key, "com.android.shell");
|
||||||
strcpy(profile.rp_config.profile.selinux_domain,
|
strcpy(profile.rp_config.profile.selinux_domain,
|
||||||
KSU_DEFAULT_SELINUX_DOMAIN);
|
KSU_DEFAULT_SELINUX_DOMAIN);
|
||||||
ksu_set_app_profile(&profile, false);
|
ksu_set_app_profile(&profile, false);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool ksu_get_app_profile(struct app_profile *profile)
|
bool ksu_get_app_profile(struct app_profile *profile)
|
||||||
{
|
{
|
||||||
struct perm_data *p = NULL;
|
struct perm_data *p = NULL;
|
||||||
struct list_head *pos = NULL;
|
struct list_head *pos = NULL;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
list_for_each (pos, &allow_list) {
|
list_for_each (pos, &allow_list) {
|
||||||
p = list_entry(pos, struct perm_data, list);
|
p = list_entry(pos, struct perm_data, list);
|
||||||
bool uid_match = profile->current_uid == p->profile.current_uid;
|
bool uid_match = profile->current_uid == p->profile.current_uid;
|
||||||
if (uid_match) {
|
if (uid_match) {
|
||||||
// found it, override it with ours
|
// found it, override it with ours
|
||||||
memcpy(profile, &p->profile, sizeof(*profile));
|
memcpy(profile, &p->profile, sizeof(*profile));
|
||||||
found = true;
|
found = true;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool forbid_system_uid(uid_t uid)
|
static inline bool forbid_system_uid(uid_t uid)
|
||||||
{
|
{
|
||||||
#define SHELL_UID 2000
|
#define SHELL_UID 2000
|
||||||
#define SYSTEM_UID 1000
|
#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)
|
static bool profile_valid(struct app_profile *profile)
|
||||||
{
|
{
|
||||||
if (!profile) {
|
if (!profile) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (profile->version < KSU_APP_PROFILE_VER) {
|
if (profile->version < KSU_APP_PROFILE_VER) {
|
||||||
pr_info("Unsupported profile version: %d\n", profile->version);
|
pr_info("Unsupported profile version: %d\n", profile->version);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (profile->allow_su) {
|
if (profile->allow_su) {
|
||||||
if (profile->rp_config.profile.groups_count > KSU_MAX_GROUPS) {
|
if (profile->rp_config.profile.groups_count > KSU_MAX_GROUPS) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen(profile->rp_config.profile.selinux_domain) == 0) {
|
if (strlen(profile->rp_config.profile.selinux_domain) == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ksu_set_app_profile(struct app_profile *profile, bool persist)
|
bool ksu_set_app_profile(struct app_profile *profile, bool persist)
|
||||||
{
|
{
|
||||||
struct perm_data *p = NULL;
|
struct perm_data *p = NULL;
|
||||||
struct list_head *pos = NULL;
|
struct list_head *pos = NULL;
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
if (!profile_valid(profile)) {
|
if (!profile_valid(profile)) {
|
||||||
pr_err("Failed to set app profile: invalid profile!\n");
|
pr_err("Failed to set app profile: invalid profile!\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_for_each (pos, &allow_list) {
|
list_for_each (pos, &allow_list) {
|
||||||
p = list_entry(pos, struct perm_data, 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
|
// both uid and package must match, otherwise it will break multiple package with different user id
|
||||||
if (profile->current_uid == p->profile.current_uid &&
|
if (profile->current_uid == p->profile.current_uid &&
|
||||||
!strcmp(profile->key, p->profile.key)) {
|
!strcmp(profile->key, p->profile.key)) {
|
||||||
// found it, just override it all!
|
// found it, just override it all!
|
||||||
memcpy(&p->profile, profile, sizeof(*profile));
|
memcpy(&p->profile, profile, sizeof(*profile));
|
||||||
result = true;
|
result = true;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// not found, alloc a new node!
|
// not found, alloc a new node!
|
||||||
p = (struct perm_data *)kzalloc(sizeof(struct perm_data), GFP_KERNEL);
|
p = (struct perm_data *)kzalloc(sizeof(struct perm_data), GFP_KERNEL);
|
||||||
if (!p) {
|
if (!p) {
|
||||||
pr_err("ksu_set_app_profile alloc failed\n");
|
pr_err("ksu_set_app_profile alloc failed\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(&p->profile, profile, sizeof(*profile));
|
memcpy(&p->profile, profile, sizeof(*profile));
|
||||||
if (profile->allow_su) {
|
if (profile->allow_su) {
|
||||||
pr_info("set root profile, key: %s, uid: %d, gid: %d, context: %s\n",
|
pr_info("set root profile, key: %s, uid: %d, gid: %d, context: %s\n",
|
||||||
profile->key, profile->current_uid,
|
profile->key, profile->current_uid,
|
||||||
profile->rp_config.profile.gid,
|
profile->rp_config.profile.gid,
|
||||||
profile->rp_config.profile.selinux_domain);
|
profile->rp_config.profile.selinux_domain);
|
||||||
} else {
|
} else {
|
||||||
pr_info("set app profile, key: %s, uid: %d, umount modules: %d\n",
|
pr_info("set app profile, key: %s, uid: %d, umount modules: %d\n",
|
||||||
profile->key, profile->current_uid,
|
profile->key, profile->current_uid,
|
||||||
profile->nrp_config.profile.umount_modules);
|
profile->nrp_config.profile.umount_modules);
|
||||||
}
|
}
|
||||||
list_add_tail(&p->list, &allow_list);
|
list_add_tail(&p->list, &allow_list);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (profile->current_uid <= BITMAP_UID_MAX) {
|
if (profile->current_uid <= BITMAP_UID_MAX) {
|
||||||
if (profile->allow_su)
|
if (profile->allow_su)
|
||||||
allow_list_bitmap[profile->current_uid / BITS_PER_BYTE] |=
|
allow_list_bitmap[profile->current_uid / BITS_PER_BYTE] |=
|
||||||
1 << (profile->current_uid % BITS_PER_BYTE);
|
1 << (profile->current_uid % BITS_PER_BYTE);
|
||||||
else
|
else
|
||||||
allow_list_bitmap[profile->current_uid / BITS_PER_BYTE] &=
|
allow_list_bitmap[profile->current_uid / BITS_PER_BYTE] &=
|
||||||
~(1 << (profile->current_uid % BITS_PER_BYTE));
|
~(1 << (profile->current_uid % BITS_PER_BYTE));
|
||||||
} else {
|
} else {
|
||||||
if (profile->allow_su) {
|
if (profile->allow_su) {
|
||||||
/*
|
/*
|
||||||
* 1024 apps with uid higher than BITMAP_UID_MAX
|
* 1024 apps with uid higher than BITMAP_UID_MAX
|
||||||
* registered to request superuser?
|
* registered to request superuser?
|
||||||
*/
|
*/
|
||||||
if (allow_list_pointer >= ARRAY_SIZE(allow_list_arr)) {
|
if (allow_list_pointer >= ARRAY_SIZE(allow_list_arr)) {
|
||||||
pr_err("too many apps registered\n");
|
pr_err("too many apps registered\n");
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
allow_list_arr[allow_list_pointer++] = profile->current_uid;
|
allow_list_arr[allow_list_pointer++] =
|
||||||
} else {
|
profile->current_uid;
|
||||||
remove_uid_from_arr(profile->current_uid);
|
} else {
|
||||||
}
|
remove_uid_from_arr(profile->current_uid);
|
||||||
}
|
}
|
||||||
result = true;
|
}
|
||||||
|
result = true;
|
||||||
|
|
||||||
// check if the default profiles is changed, cache it to a single struct to accelerate access.
|
// check if the default profiles is changed, cache it to a single struct to accelerate access.
|
||||||
if (unlikely(!strcmp(profile->key, "$"))) {
|
if (unlikely(!strcmp(profile->key, "$"))) {
|
||||||
// set default non root profile
|
// set default non root profile
|
||||||
memcpy(&default_non_root_profile, &profile->nrp_config.profile,
|
memcpy(&default_non_root_profile, &profile->nrp_config.profile,
|
||||||
sizeof(default_non_root_profile));
|
sizeof(default_non_root_profile));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(!strcmp(profile->key, "#"))) {
|
if (unlikely(!strcmp(profile->key, "#"))) {
|
||||||
// set default root profile
|
// set default root profile
|
||||||
memcpy(&default_root_profile, &profile->rp_config.profile,
|
memcpy(&default_root_profile, &profile->rp_config.profile,
|
||||||
sizeof(default_root_profile));
|
sizeof(default_root_profile));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (persist) {
|
if (persist) {
|
||||||
persistent_allow_list();
|
persistent_allow_list();
|
||||||
#ifndef CONFIG_KSU_SUSFS
|
// FIXME: use a new flag
|
||||||
// FIXME: use a new flag
|
ksu_mark_running_process();
|
||||||
ksu_mark_running_process();
|
}
|
||||||
#endif // #ifndef CONFIG_KSU_SUSFS
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool __ksu_is_allow_uid(uid_t uid)
|
bool __ksu_is_allow_uid(uid_t uid)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (forbid_system_uid(uid)) {
|
if (forbid_system_uid(uid)) {
|
||||||
// do not bother going through the list if it's system
|
// do not bother going through the list if it's system
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (likely(ksu_is_manager_uid_valid()) &&
|
if (likely(ksu_is_manager_uid_valid()) &&
|
||||||
unlikely(ksu_get_manager_uid() == uid)) {
|
unlikely(ksu_get_manager_uid() == uid)) {
|
||||||
// manager is always allowed!
|
// manager is always allowed!
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (likely(uid <= BITMAP_UID_MAX)) {
|
if (likely(uid <= BITMAP_UID_MAX)) {
|
||||||
return !!(allow_list_bitmap[uid / BITS_PER_BYTE] &
|
return !!(allow_list_bitmap[uid / BITS_PER_BYTE] &
|
||||||
(1 << (uid % BITS_PER_BYTE)));
|
(1 << (uid % BITS_PER_BYTE)));
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; i < allow_list_pointer; i++) {
|
for (i = 0; i < allow_list_pointer; i++) {
|
||||||
if (allow_list_arr[i] == uid)
|
if (allow_list_arr[i] == uid)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool __ksu_is_allow_uid_for_current(uid_t uid)
|
bool __ksu_is_allow_uid_for_current(uid_t uid)
|
||||||
{
|
{
|
||||||
if (unlikely(uid == 0)) {
|
if (unlikely(uid == 0)) {
|
||||||
// already root, but only allow our domain.
|
// already root, but only allow our domain.
|
||||||
return is_ksu_domain();
|
return is_ksu_domain();
|
||||||
}
|
}
|
||||||
return __ksu_is_allow_uid(uid);
|
return __ksu_is_allow_uid(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ksu_uid_should_umount(uid_t uid)
|
bool ksu_uid_should_umount(uid_t uid)
|
||||||
{
|
{
|
||||||
struct app_profile profile = { .current_uid = uid };
|
struct app_profile profile = { .current_uid = uid };
|
||||||
if (likely(ksu_is_manager_uid_valid()) &&
|
if (likely(ksu_is_manager_uid_valid()) &&
|
||||||
unlikely(ksu_get_manager_uid() == uid)) {
|
unlikely(ksu_get_manager_uid() == uid)) {
|
||||||
// we should not umount on manager!
|
// we should not umount on manager!
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool found = ksu_get_app_profile(&profile);
|
bool found = ksu_get_app_profile(&profile);
|
||||||
if (!found) {
|
if (!found) {
|
||||||
// no app profile found, it must be non root app
|
// no app profile found, it must be non root app
|
||||||
return default_non_root_profile.umount_modules;
|
return default_non_root_profile.umount_modules;
|
||||||
}
|
}
|
||||||
if (profile.allow_su) {
|
if (profile.allow_su) {
|
||||||
// if found and it is granted to su, we shouldn't umount for it
|
// if found and it is granted to su, we shouldn't umount for it
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
// found an app profile
|
// found an app profile
|
||||||
if (profile.nrp_config.use_default) {
|
if (profile.nrp_config.use_default) {
|
||||||
return default_non_root_profile.umount_modules;
|
return default_non_root_profile.umount_modules;
|
||||||
} else {
|
} else {
|
||||||
return profile.nrp_config.profile.umount_modules;
|
return profile.nrp_config.profile.umount_modules;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct root_profile *ksu_get_root_profile(uid_t uid)
|
struct root_profile *ksu_get_root_profile(uid_t uid)
|
||||||
{
|
{
|
||||||
struct perm_data *p = NULL;
|
struct perm_data *p = NULL;
|
||||||
struct list_head *pos = NULL;
|
struct list_head *pos = NULL;
|
||||||
|
|
||||||
list_for_each (pos, &allow_list) {
|
list_for_each (pos, &allow_list) {
|
||||||
p = list_entry(pos, struct perm_data, list);
|
p = list_entry(pos, struct perm_data, list);
|
||||||
if (uid == p->profile.current_uid && p->profile.allow_su) {
|
if (uid == p->profile.current_uid && p->profile.allow_su) {
|
||||||
if (!p->profile.rp_config.use_default) {
|
if (!p->profile.rp_config.use_default) {
|
||||||
return &p->profile.rp_config.profile;
|
return &p->profile.rp_config.profile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// use default profile
|
// use default profile
|
||||||
return &default_root_profile;
|
return &default_root_profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ksu_get_allow_list(int *array, int *length, bool allow)
|
bool ksu_get_allow_list(int *array, int *length, bool allow)
|
||||||
{
|
{
|
||||||
struct perm_data *p = NULL;
|
struct perm_data *p = NULL;
|
||||||
struct list_head *pos = NULL;
|
struct list_head *pos = NULL;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
list_for_each (pos, &allow_list) {
|
list_for_each (pos, &allow_list) {
|
||||||
p = list_entry(pos, struct perm_data, list);
|
p = list_entry(pos, struct perm_data, list);
|
||||||
// pr_info("get_allow_list uid: %d allow: %d\n", p->uid, p->allow);
|
// pr_info("get_allow_list uid: %d allow: %d\n", p->uid, p->allow);
|
||||||
if (p->profile.allow_su == allow) {
|
if (p->profile.allow_su == allow) {
|
||||||
array[i++] = p->profile.current_uid;
|
array[i++] = p->profile.current_uid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*length = i;
|
*length = i;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_persistent_allow_list(struct callback_head *_cb)
|
static void do_persistent_allow_list(struct callback_head *_cb)
|
||||||
{
|
{
|
||||||
u32 magic = FILE_MAGIC;
|
u32 magic = FILE_MAGIC;
|
||||||
u32 version = FILE_FORMAT_VERSION;
|
u32 version = FILE_FORMAT_VERSION;
|
||||||
struct perm_data *p = NULL;
|
struct perm_data *p = NULL;
|
||||||
struct list_head *pos = NULL;
|
struct list_head *pos = NULL;
|
||||||
loff_t off = 0;
|
loff_t off = 0;
|
||||||
|
|
||||||
mutex_lock(&allowlist_mutex);
|
mutex_lock(&allowlist_mutex);
|
||||||
struct file *fp =
|
struct file *fp = ksu_filp_open_compat(
|
||||||
filp_open(KERNEL_SU_ALLOWLIST, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
KERNEL_SU_ALLOWLIST, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||||
if (IS_ERR(fp)) {
|
if (IS_ERR(fp)) {
|
||||||
pr_err("save_allow_list create file failed: %ld\n", PTR_ERR(fp));
|
pr_err("save_allow_list create file failed: %ld\n",
|
||||||
goto unlock;
|
PTR_ERR(fp));
|
||||||
}
|
goto unlock;
|
||||||
|
}
|
||||||
|
|
||||||
// store magic and version
|
// store magic and version
|
||||||
if (kernel_write(fp, &magic, sizeof(magic), &off) != sizeof(magic)) {
|
if (ksu_kernel_write_compat(fp, &magic, sizeof(magic), &off) !=
|
||||||
pr_err("save_allow_list write magic failed.\n");
|
sizeof(magic)) {
|
||||||
goto close_file;
|
pr_err("save_allow_list write magic failed.\n");
|
||||||
}
|
goto close_file;
|
||||||
|
}
|
||||||
|
|
||||||
if (kernel_write(fp, &version, sizeof(version), &off) != sizeof(version)) {
|
if (ksu_kernel_write_compat(fp, &version, sizeof(version), &off) !=
|
||||||
pr_err("save_allow_list write version failed.\n");
|
sizeof(version)) {
|
||||||
goto close_file;
|
pr_err("save_allow_list write version failed.\n");
|
||||||
}
|
goto close_file;
|
||||||
|
}
|
||||||
|
|
||||||
list_for_each (pos, &allow_list) {
|
list_for_each (pos, &allow_list) {
|
||||||
p = list_entry(pos, struct perm_data, list);
|
p = list_entry(pos, struct perm_data, list);
|
||||||
pr_info("save allow list, name: %s uid :%d, allow: %d\n",
|
pr_info("save allow list, name: %s uid :%d, allow: %d\n",
|
||||||
p->profile.key, p->profile.current_uid, p->profile.allow_su);
|
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:
|
close_file:
|
||||||
filp_close(fp, 0);
|
filp_close(fp, 0);
|
||||||
unlock:
|
unlock:
|
||||||
mutex_unlock(&allowlist_mutex);
|
mutex_unlock(&allowlist_mutex);
|
||||||
kfree(_cb);
|
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);
|
tsk = get_pid_task(find_vpid(1), PIDTYPE_PID);
|
||||||
if (!tsk) {
|
if (!tsk) {
|
||||||
pr_err("save_allow_list find init task err\n");
|
pr_err("save_allow_list find init task err\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct callback_head *cb =
|
struct callback_head *cb =
|
||||||
kzalloc(sizeof(struct callback_head), GFP_KERNEL);
|
kzalloc(sizeof(struct callback_head), GFP_KERNEL);
|
||||||
if (!cb) {
|
if (!cb) {
|
||||||
pr_err("save_allow_list alloc cb err\b");
|
pr_err("save_allow_list alloc cb err\b");
|
||||||
goto put_task;
|
goto put_task;
|
||||||
}
|
}
|
||||||
cb->func = do_persistent_allow_list;
|
cb->func = do_persistent_allow_list;
|
||||||
task_work_add(tsk, cb, TWA_RESUME);
|
task_work_add(tsk, cb, TWA_RESUME);
|
||||||
|
|
||||||
put_task:
|
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;
|
loff_t off = 0;
|
||||||
ssize_t ret = 0;
|
ssize_t ret = 0;
|
||||||
struct file *fp = NULL;
|
struct file *fp = NULL;
|
||||||
u32 magic;
|
u32 magic;
|
||||||
u32 version;
|
u32 version;
|
||||||
|
|
||||||
#ifdef CONFIG_KSU_DEBUG
|
#ifdef CONFIG_KSU_DEBUG
|
||||||
// always allow adb shell by default
|
// always allow adb shell by default
|
||||||
ksu_grant_root_to_shell();
|
ksu_grant_root_to_shell();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// load allowlist now!
|
// load allowlist now!
|
||||||
fp = filp_open(KERNEL_SU_ALLOWLIST, O_RDONLY, 0);
|
fp = ksu_filp_open_compat(KERNEL_SU_ALLOWLIST, O_RDONLY, 0);
|
||||||
if (IS_ERR(fp)) {
|
if (IS_ERR(fp)) {
|
||||||
pr_err("load_allow_list open file failed: %ld\n", PTR_ERR(fp));
|
pr_err("load_allow_list open file failed: %ld\n", PTR_ERR(fp));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify magic
|
// verify magic
|
||||||
if (kernel_read(fp, &magic, sizeof(magic), &off) != sizeof(magic) ||
|
if (ksu_kernel_read_compat(fp, &magic, sizeof(magic), &off) !=
|
||||||
magic != FILE_MAGIC) {
|
sizeof(magic) ||
|
||||||
pr_err("allowlist file invalid: %d!\n", magic);
|
magic != FILE_MAGIC) {
|
||||||
goto exit;
|
pr_err("allowlist file invalid: %d!\n", magic);
|
||||||
}
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
if (kernel_read(fp, &version, sizeof(version), &off) != sizeof(version)) {
|
if (ksu_kernel_read_compat(fp, &version, sizeof(version), &off) !=
|
||||||
pr_err("allowlist read version: %d failed\n", version);
|
sizeof(version)) {
|
||||||
goto exit;
|
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) {
|
while (true) {
|
||||||
struct app_profile profile;
|
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) {
|
if (ret <= 0) {
|
||||||
pr_info("load_allow_list read err: %zd\n", ret);
|
pr_info("load_allow_list read err: %zd\n", ret);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_info("load_allow_uid, name: %s, uid: %d, allow: %d\n", profile.key,
|
pr_info("load_allow_uid, name: %s, uid: %d, allow: %d\n",
|
||||||
profile.current_uid, profile.allow_su);
|
profile.key, profile.current_uid, profile.allow_su);
|
||||||
ksu_set_app_profile(&profile, false);
|
ksu_set_app_profile(&profile, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
ksu_show_allow_list();
|
ksu_show_allow_list();
|
||||||
filp_close(fp, 0);
|
filp_close(fp, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ksu_prune_allowlist(bool (*is_uid_valid)(uid_t, char *, void *),
|
void ksu_prune_allowlist(bool (*is_uid_valid)(uid_t, char *, void *),
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
struct perm_data *np = NULL;
|
struct perm_data *np = NULL;
|
||||||
struct perm_data *n = NULL;
|
struct perm_data *n = NULL;
|
||||||
|
|
||||||
if (!ksu_boot_completed) {
|
if (!ksu_boot_completed) {
|
||||||
pr_info("boot not completed, skip prune\n");
|
pr_info("boot not completed, skip prune\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool modified = false;
|
bool modified = false;
|
||||||
// TODO: use RCU!
|
// TODO: use RCU!
|
||||||
mutex_lock(&allowlist_mutex);
|
mutex_lock(&allowlist_mutex);
|
||||||
list_for_each_entry_safe (np, n, &allow_list, list) {
|
list_for_each_entry_safe (np, n, &allow_list, list) {
|
||||||
uid_t uid = np->profile.current_uid;
|
uid_t uid = np->profile.current_uid;
|
||||||
char *package = np->profile.key;
|
char *package = np->profile.key;
|
||||||
// we use this uid for special cases, don't prune it!
|
// we use this uid for special cases, don't prune it!
|
||||||
bool is_preserved_uid = uid == KSU_APP_PROFILE_PRESERVE_UID;
|
bool is_preserved_uid = uid == KSU_APP_PROFILE_PRESERVE_UID;
|
||||||
if (!is_preserved_uid && !is_uid_valid(uid, package, data)) {
|
if (!is_preserved_uid && !is_uid_valid(uid, package, data)) {
|
||||||
modified = true;
|
modified = true;
|
||||||
pr_info("prune uid: %d, package: %s\n", uid, package);
|
pr_info("prune uid: %d, package: %s\n", uid, package);
|
||||||
list_del(&np->list);
|
list_del(&np->list);
|
||||||
if (likely(uid <= BITMAP_UID_MAX)) {
|
if (likely(uid <= BITMAP_UID_MAX)) {
|
||||||
allow_list_bitmap[uid / BITS_PER_BYTE] &=
|
allow_list_bitmap[uid / BITS_PER_BYTE] &=
|
||||||
~(1 << (uid % BITS_PER_BYTE));
|
~(1 << (uid % BITS_PER_BYTE));
|
||||||
}
|
}
|
||||||
remove_uid_from_arr(uid);
|
remove_uid_from_arr(uid);
|
||||||
smp_mb();
|
smp_mb();
|
||||||
kfree(np);
|
kfree(np);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(&allowlist_mutex);
|
mutex_unlock(&allowlist_mutex);
|
||||||
|
|
||||||
if (modified) {
|
if (modified) {
|
||||||
persistent_allow_list();
|
persistent_allow_list();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ksu_allowlist_init(void)
|
void ksu_allowlist_init(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
BUILD_BUG_ON(sizeof(allow_list_bitmap) != PAGE_SIZE);
|
BUILD_BUG_ON(sizeof(allow_list_bitmap) != PAGE_SIZE);
|
||||||
BUILD_BUG_ON(sizeof(allow_list_arr) != PAGE_SIZE);
|
BUILD_BUG_ON(sizeof(allow_list_arr) != PAGE_SIZE);
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(allow_list_arr); i++)
|
for (i = 0; i < ARRAY_SIZE(allow_list_arr); i++)
|
||||||
allow_list_arr[i] = -1;
|
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)
|
void ksu_allowlist_exit(void)
|
||||||
{
|
{
|
||||||
struct perm_data *np = NULL;
|
struct perm_data *np = NULL;
|
||||||
struct perm_data *n = NULL;
|
struct perm_data *n = NULL;
|
||||||
|
|
||||||
persistent_allow_list();
|
// free allowlist
|
||||||
|
mutex_lock(&allowlist_mutex);
|
||||||
// free allowlist
|
list_for_each_entry_safe (np, n, &allow_list, list) {
|
||||||
mutex_lock(&allowlist_mutex);
|
list_del(&np->list);
|
||||||
list_for_each_entry_safe (np, n, &allow_list, list) {
|
kfree(np);
|
||||||
list_del(&np->list);
|
}
|
||||||
kfree(np);
|
mutex_unlock(&allowlist_mutex);
|
||||||
}
|
|
||||||
mutex_unlock(&allowlist_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_KSU_MANUAL_SU
|
#ifdef CONFIG_KSU_MANUAL_SU
|
||||||
|
|||||||
@@ -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
|
// Check if the uid is in allow list, or current is ksu domain root
|
||||||
bool __ksu_is_allow_uid_for_current(uid_t uid);
|
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);
|
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_get_app_profile(struct app_profile *);
|
||||||
bool ksu_set_app_profile(struct app_profile *, bool persist);
|
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)
|
static inline bool is_appuid(uid_t uid)
|
||||||
{
|
{
|
||||||
uid_t appid = uid % PER_USER_RANGE;
|
uid_t appid = uid % PER_USER_RANGE;
|
||||||
return appid >= FIRST_APPLICATION_UID && appid <= LAST_APPLICATION_UID;
|
return appid >= FIRST_APPLICATION_UID && appid <= LAST_APPLICATION_UID;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_KSU_MANUAL_SU
|
#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);
|
void ksu_temp_revoke_root_once(uid_t uid);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "dynamic_manager.h"
|
#include "dynamic_manager.h"
|
||||||
#include "klog.h" // IWYU pragma: keep
|
#include "klog.h" // IWYU pragma: keep
|
||||||
#include "manager_sign.h"
|
#include "manager_sign.h"
|
||||||
|
#include "kernel_compat.h"
|
||||||
|
|
||||||
struct sdesc {
|
struct sdesc {
|
||||||
struct shash_desc shash;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
kernel_read(fp, cert, size4, pos);
|
ksu_kernel_read_compat(fp, cert, size4, pos);
|
||||||
|
|
||||||
unsigned char digest[SHA256_DIGEST_SIZE];
|
unsigned char digest[SHA256_DIGEST_SIZE];
|
||||||
if (ksu_sha256(cert, size4, digest) < 0) {
|
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;
|
apk_sign_key_t sign_key;
|
||||||
bool signature_valid = false;
|
bool signature_valid = false;
|
||||||
|
|
||||||
kernel_read(fp, size4, 0x4, pos); // signer-sequence length
|
ksu_kernel_read_compat(fp, size4, 0x4, pos); // signer-sequence length
|
||||||
kernel_read(fp, size4, 0x4, pos); // signer length
|
ksu_kernel_read_compat(fp, size4, 0x4, pos); // signer length
|
||||||
kernel_read(fp, size4, 0x4, pos); // signed data length
|
ksu_kernel_read_compat(fp, size4, 0x4, pos); // signed data length
|
||||||
|
|
||||||
*offset += 0x4 * 3;
|
*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;
|
*pos += *size4;
|
||||||
*offset += 0x4 + *size4;
|
*offset += 0x4 + *size4;
|
||||||
|
|
||||||
kernel_read(fp, size4, 0x4, pos); // certificates length
|
ksu_kernel_read_compat(fp, size4, 0x4, pos); // certificates length
|
||||||
kernel_read(fp, size4, 0x4, pos); // certificate length
|
ksu_kernel_read_compat(fp, size4, 0x4, pos); // certificate length
|
||||||
*offset += 0x4 * 2;
|
*offset += 0x4 * 2;
|
||||||
|
|
||||||
if (ksu_is_dynamic_manager_enabled()) {
|
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");
|
pr_info("cert length overlimit\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
kernel_read(fp, cert, *size4, pos);
|
ksu_kernel_read_compat(fp, cert, *size4, pos);
|
||||||
unsigned char digest[SHA256_DIGEST_SIZE];
|
unsigned char digest[SHA256_DIGEST_SIZE];
|
||||||
if (ksu_sha256(cert, *size4, digest) < 0 ) {
|
if (ksu_sha256(cert, *size4, digest) < 0 ) {
|
||||||
pr_info("sha256 error\n");
|
pr_info("sha256 error\n");
|
||||||
@@ -220,7 +221,7 @@ static bool has_v1_signature_file(struct file *fp)
|
|||||||
|
|
||||||
loff_t pos = 0;
|
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), &pos) ==
|
||||||
sizeof(struct zip_entry_header)) {
|
sizeof(struct zip_entry_header)) {
|
||||||
if (header.signature != 0x04034b50) {
|
if (header.signature != 0x04034b50) {
|
||||||
@@ -230,7 +231,7 @@ static bool has_v1_signature_file(struct file *fp)
|
|||||||
// Read the entry file name
|
// Read the entry file name
|
||||||
if (header.file_name_length == sizeof(MANIFEST) - 1) {
|
if (header.file_name_length == sizeof(MANIFEST) - 1) {
|
||||||
char fileName[sizeof(MANIFEST)];
|
char fileName[sizeof(MANIFEST)];
|
||||||
kernel_read(fp, fileName,
|
ksu_kernel_read_compat(fp, fileName,
|
||||||
header.file_name_length, &pos);
|
header.file_name_length, &pos);
|
||||||
fileName[header.file_name_length] = '\0';
|
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;
|
bool v3_1_signing_exist = false;
|
||||||
int matched_index = -1;
|
int matched_index = -1;
|
||||||
int i;
|
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)) {
|
if (IS_ERR(fp)) {
|
||||||
pr_err("open %s error.\n", path);
|
pr_err("open %s error.\n", path);
|
||||||
return false;
|
return false;
|
||||||
@@ -284,10 +285,10 @@ static __always_inline bool check_v2_signature(char *path, bool check_multi_mana
|
|||||||
for (i = 0;; ++i) {
|
for (i = 0;; ++i) {
|
||||||
unsigned short n;
|
unsigned short n;
|
||||||
pos = generic_file_llseek(fp, -i - 2, SEEK_END);
|
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) {
|
if (n == i) {
|
||||||
pos -= 22;
|
pos -= 22;
|
||||||
kernel_read(fp, &size4, 4, &pos);
|
ksu_kernel_read_compat(fp, &size4, 4, &pos);
|
||||||
if ((size4 ^ 0xcafebabeu) == 0xccfbf1eeu) {
|
if ((size4 ^ 0xcafebabeu) == 0xccfbf1eeu) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -300,17 +301,17 @@ static __always_inline bool check_v2_signature(char *path, bool check_multi_mana
|
|||||||
|
|
||||||
pos += 12;
|
pos += 12;
|
||||||
// offset
|
// offset
|
||||||
kernel_read(fp, &size4, 0x4, &pos);
|
ksu_kernel_read_compat(fp, &size4, 0x4, &pos);
|
||||||
pos = size4 - 0x18;
|
pos = size4 - 0x18;
|
||||||
|
|
||||||
kernel_read(fp, &size8, 0x8, &pos);
|
ksu_kernel_read_compat(fp, &size8, 0x8, &pos);
|
||||||
kernel_read(fp, buffer, 0x10, &pos);
|
ksu_kernel_read_compat(fp, buffer, 0x10, &pos);
|
||||||
if (strcmp((char *)buffer, "APK Sig Block 42")) {
|
if (strcmp((char *)buffer, "APK Sig Block 42")) {
|
||||||
goto clean;
|
goto clean;
|
||||||
}
|
}
|
||||||
|
|
||||||
pos = size4 - (size8 + 0x8);
|
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) {
|
if (size_of_block != size8) {
|
||||||
goto clean;
|
goto clean;
|
||||||
}
|
}
|
||||||
@@ -319,12 +320,12 @@ static __always_inline bool check_v2_signature(char *path, bool check_multi_mana
|
|||||||
while (loop_count++ < 10) {
|
while (loop_count++ < 10) {
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
kernel_read(fp, &size8, 0x8,
|
ksu_kernel_read_compat(fp, &size8, 0x8,
|
||||||
&pos); // sequence length
|
&pos); // sequence length
|
||||||
if (size8 == size_of_block) {
|
if (size8 == size_of_block) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
kernel_read(fp, &id, 0x4, &pos); // id
|
ksu_kernel_read_compat(fp, &id, 0x4, &pos); // id
|
||||||
offset = 4;
|
offset = 4;
|
||||||
if (id == 0x7109871au) {
|
if (id == 0x7109871au) {
|
||||||
v2_signing_blocks++;
|
v2_signing_blocks++;
|
||||||
|
|||||||
@@ -1,21 +1,31 @@
|
|||||||
|
#include <linux/version.h>
|
||||||
#include <linux/capability.h>
|
#include <linux/capability.h>
|
||||||
#include <linux/cred.h>
|
#include <linux/cred.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/fdtable.h>
|
||||||
|
#include <linux/file.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/proc_ns.h>
|
||||||
|
#include <linux/pid.h>
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
||||||
|
#include <linux/sched/signal.h> // signal_struct
|
||||||
|
#include <linux/sched/task.h>
|
||||||
|
#endif
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/sched/signal.h>
|
|
||||||
#include <linux/seccomp.h>
|
#include <linux/seccomp.h>
|
||||||
#include <linux/thread_info.h>
|
#include <linux/thread_info.h>
|
||||||
#include <linux/uidgid.h>
|
#include <linux/uidgid.h>
|
||||||
#include <linux/version.h>
|
#include <linux/syscalls.h>
|
||||||
#include "objsec.h"
|
|
||||||
|
|
||||||
#include "allowlist.h"
|
#include "allowlist.h"
|
||||||
#include "app_profile.h"
|
#include "app_profile.h"
|
||||||
|
#include "arch.h"
|
||||||
|
#include "kernel_compat.h"
|
||||||
#include "klog.h" // IWYU pragma: keep
|
#include "klog.h" // IWYU pragma: keep
|
||||||
#include "selinux/selinux.h"
|
#include "selinux/selinux.h"
|
||||||
#ifndef CONFIG_KSU_SUSFS
|
#ifndef CONFIG_KSU_SUSFS
|
||||||
#include "syscall_hook_manager.h"
|
#include "syscall_hook_manager.h"
|
||||||
#endif
|
#endif
|
||||||
#include "sucompat.h"
|
|
||||||
#include "sulog.h"
|
#include "sulog.h"
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION (6, 7, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION (6, 7, 0)
|
||||||
@@ -26,51 +36,55 @@
|
|||||||
|
|
||||||
static void setup_groups(struct root_profile *profile, struct cred *cred)
|
static void setup_groups(struct root_profile *profile, struct cred *cred)
|
||||||
{
|
{
|
||||||
if (profile->groups_count > KSU_MAX_GROUPS) {
|
if (profile->groups_count > KSU_MAX_GROUPS) {
|
||||||
pr_warn("Failed to setgroups, too large group: %d!\n",
|
pr_warn("Failed to setgroups, too large group: %d!\n",
|
||||||
profile->uid);
|
profile->uid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (profile->groups_count == 1 && profile->groups[0] == 0) {
|
if (profile->groups_count == 1 && profile->groups[0] == 0) {
|
||||||
// setgroup to root and return early.
|
// setgroup to root and return early.
|
||||||
if (cred->group_info)
|
if (cred->group_info)
|
||||||
put_group_info(cred->group_info);
|
put_group_info(cred->group_info);
|
||||||
cred->group_info = get_group_info(&root_groups);
|
cred->group_info = get_group_info(&root_groups);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 ngroups = profile->groups_count;
|
u32 ngroups = profile->groups_count;
|
||||||
struct group_info *group_info = groups_alloc(ngroups);
|
struct group_info *group_info = groups_alloc(ngroups);
|
||||||
if (!group_info) {
|
if (!group_info) {
|
||||||
pr_warn("Failed to setgroups, ENOMEM for: %d\n", profile->uid);
|
pr_warn("Failed to setgroups, ENOMEM for: %d\n", profile->uid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < ngroups; i++) {
|
for (i = 0; i < ngroups; i++) {
|
||||||
gid_t gid = profile->groups[i];
|
gid_t gid = profile->groups[i];
|
||||||
kgid_t kgid = make_kgid(current_user_ns(), gid);
|
kgid_t kgid = make_kgid(current_user_ns(), gid);
|
||||||
if (!gid_valid(kgid)) {
|
if (!gid_valid(kgid)) {
|
||||||
pr_warn("Failed to setgroups, invalid gid: %d\n", gid);
|
pr_warn("Failed to setgroups, invalid gid: %d\n", gid);
|
||||||
put_group_info(group_info);
|
put_group_info(group_info);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
|
||||||
group_info->gid[i] = kgid;
|
group_info->gid[i] = kgid;
|
||||||
#else
|
#else
|
||||||
GROUP_AT(group_info, i) = kgid;
|
GROUP_AT(group_info, i) = kgid;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
groups_sort(group_info);
|
groups_sort(group_info);
|
||||||
set_groups(cred, group_info);
|
set_groups(cred, group_info);
|
||||||
put_group_info(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
|
// disable seccomp
|
||||||
#if defined(CONFIG_GENERIC_ENTRY) && \
|
#if defined(CONFIG_GENERIC_ENTRY) && \
|
||||||
LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
|
LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
|
||||||
@@ -80,83 +94,97 @@ void disable_seccomp(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_SECCOMP
|
#ifdef CONFIG_SECCOMP
|
||||||
current->seccomp.mode = 0;
|
tsk->seccomp.mode = 0;
|
||||||
current->seccomp.filter = NULL;
|
if (tsk->seccomp.filter) {
|
||||||
atomic_set(¤t->seccomp.filter_count, 0);
|
// 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
|
#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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void escape_with_root_profile(void)
|
void escape_with_root_profile(void)
|
||||||
{
|
{
|
||||||
struct cred *cred;
|
struct cred *cred;
|
||||||
#ifndef CONFIG_KSU_SUSFS
|
// a bit useless, but we just want less ifdefs
|
||||||
struct task_struct *p = current;
|
struct task_struct *p = current;
|
||||||
struct task_struct *t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
cred = prepare_creds();
|
if (current_euid().val == 0) {
|
||||||
if (!cred) {
|
pr_warn("Already root, don't escape!\n");
|
||||||
pr_warn("prepare_creds failed!\n");
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (cred->euid.val == 0) {
|
cred = prepare_creds();
|
||||||
pr_warn("Already root, don't escape!\n");
|
if (!cred) {
|
||||||
#if __SULOG_GATE
|
pr_warn("prepare_creds failed!\n");
|
||||||
ksu_sulog_report_su_grant(current_euid().val, NULL, "escape_to_root_failed");
|
return;
|
||||||
#endif
|
}
|
||||||
abort_creds(cred);
|
|
||||||
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->uid.val = profile->uid;
|
||||||
cred->suid.val = profile->uid;
|
cred->suid.val = profile->uid;
|
||||||
cred->euid.val = profile->uid;
|
cred->euid.val = profile->uid;
|
||||||
cred->fsuid.val = profile->uid;
|
cred->fsuid.val = profile->uid;
|
||||||
|
|
||||||
cred->gid.val = profile->gid;
|
cred->gid.val = profile->gid;
|
||||||
cred->fsgid.val = profile->gid;
|
cred->fsgid.val = profile->gid;
|
||||||
cred->sgid.val = profile->gid;
|
cred->sgid.val = profile->gid;
|
||||||
cred->egid.val = profile->gid;
|
cred->egid.val = profile->gid;
|
||||||
cred->securebits = 0;
|
cred->securebits = 0;
|
||||||
|
|
||||||
BUILD_BUG_ON(sizeof(profile->capabilities.effective) !=
|
BUILD_BUG_ON(sizeof(profile->capabilities.effective) !=
|
||||||
sizeof(kernel_cap_t));
|
sizeof(kernel_cap_t));
|
||||||
|
|
||||||
// setup capabilities
|
// setup capabilities
|
||||||
// we need CAP_DAC_READ_SEARCH becuase `/data/adb/ksud` is not accessible for non root process
|
// 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!
|
// we add it here but don't add it to cap_inhertiable, it would be dropped automaticly after exec!
|
||||||
u64 cap_for_ksud =
|
u64 cap_for_ksud =
|
||||||
profile->capabilities.effective | CAP_DAC_READ_SEARCH;
|
profile->capabilities.effective | CAP_DAC_READ_SEARCH;
|
||||||
memcpy(&cred->cap_effective, &cap_for_ksud,
|
memcpy(&cred->cap_effective, &cap_for_ksud,
|
||||||
sizeof(cred->cap_effective));
|
sizeof(cred->cap_effective));
|
||||||
memcpy(&cred->cap_permitted, &profile->capabilities.effective,
|
memcpy(&cred->cap_permitted, &profile->capabilities.effective,
|
||||||
sizeof(cred->cap_permitted));
|
sizeof(cred->cap_permitted));
|
||||||
memcpy(&cred->cap_bset, &profile->capabilities.effective,
|
memcpy(&cred->cap_bset, &profile->capabilities.effective,
|
||||||
sizeof(cred->cap_bset));
|
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
|
// Refer to kernel/seccomp.c: seccomp_set_mode_strict
|
||||||
// When disabling Seccomp, ensure that current->sighand->siglock is held during the operation.
|
// When disabling Seccomp, ensure that current->sighand->siglock is held during the operation.
|
||||||
spin_lock_irq(¤t->sighand->siglock);
|
spin_lock_irq(&p->sighand->siglock);
|
||||||
disable_seccomp();
|
disable_seccomp(p);
|
||||||
spin_unlock_irq(¤t->sighand->siglock);
|
spin_unlock_irq(&p->sighand->siglock);
|
||||||
|
|
||||||
setup_selinux(profile->selinux_domain);
|
setup_selinux(profile->selinux_domain);
|
||||||
#if __SULOG_GATE
|
#if __SULOG_GATE
|
||||||
ksu_sulog_report_su_grant(current_euid().val, NULL, "escape_to_root");
|
ksu_sulog_report_su_grant(current_euid().val, NULL, "escape_to_root");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef CONFIG_KSU_SUSFS
|
#ifndef CONFIG_KSU_SUSFS
|
||||||
for_each_thread (p, t) {
|
struct task_struct *t;
|
||||||
ksu_set_task_tracepoint_flag(t);
|
for_each_thread (p, t) {
|
||||||
}
|
ksu_set_task_tracepoint_flag(t);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,10 +248,6 @@ void escape_to_root_for_cmd_su(uid_t target_uid, pid_t target_pid)
|
|||||||
{
|
{
|
||||||
struct cred *newcreds;
|
struct cred *newcreds;
|
||||||
struct task_struct *target_task;
|
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);
|
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");
|
ksu_sulog_report_su_grant(target_uid, "cmd_su", "manual_escalation");
|
||||||
#endif
|
#endif
|
||||||
#ifndef CONFIG_KSU_SUSFS
|
#ifndef CONFIG_KSU_SUSFS
|
||||||
|
struct task_struct *p = current;
|
||||||
|
struct task_struct *t;
|
||||||
for_each_thread (p, t) {
|
for_each_thread (p, t) {
|
||||||
ksu_set_task_tracepoint_flag(t);
|
ksu_set_task_tracepoint_flag(t);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,9 +62,6 @@ struct app_profile {
|
|||||||
|
|
||||||
// Escalate current process to root with the appropriate profile
|
// Escalate current process to root with the appropriate profile
|
||||||
void escape_with_root_profile(void);
|
void escape_with_root_profile(void);
|
||||||
|
|
||||||
void escape_to_root_for_cmd_su(uid_t target_uid, pid_t target_pid);
|
void escape_to_root_for_cmd_su(uid_t target_uid, pid_t target_pid);
|
||||||
|
|
||||||
void disable_seccomp(void);
|
#endif
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -19,26 +19,16 @@
|
|||||||
#define __PT_IP_REG pc
|
#define __PT_IP_REG pc
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
|
||||||
#define PRCTL_SYMBOL "__arm64_sys_prctl"
|
|
||||||
#define REBOOT_SYMBOL "__arm64_sys_reboot"
|
#define REBOOT_SYMBOL "__arm64_sys_reboot"
|
||||||
#define SYS_READ_SYMBOL "__arm64_sys_read"
|
#define SYS_READ_SYMBOL "__arm64_sys_read"
|
||||||
#define SYS_EXECVE_SYMBOL "__arm64_sys_execve"
|
#define SYS_EXECVE_SYMBOL "__arm64_sys_execve"
|
||||||
#define SYS_EXECVE_COMPAT_SYMBOL "__arm64_compat_sys_execve"
|
#define SYS_SETNS_SYMBOL __arm64_sys_setns
|
||||||
#else
|
#else
|
||||||
#define PRCTL_SYMBOL "sys_prctl"
|
|
||||||
#define REBOOT_SYMBOL "sys_reboot"
|
#define REBOOT_SYMBOL "sys_reboot"
|
||||||
#define SYS_READ_SYMBOL "sys_read"
|
#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_SYMBOL "sys_execve"
|
||||||
#define SYS_EXECVE_COMPAT_SYMBOL "compat_sys_execve"
|
#define SYS_SETNS_SYMBOL sys_setns
|
||||||
#endif
|
#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__)
|
#elif defined(__x86_64__)
|
||||||
|
|
||||||
@@ -55,28 +45,18 @@
|
|||||||
#define __PT_RC_REG ax
|
#define __PT_RC_REG ax
|
||||||
#define __PT_SP_REG sp
|
#define __PT_SP_REG sp
|
||||||
#define __PT_IP_REG ip
|
#define __PT_IP_REG ip
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
|
||||||
#define PRCTL_SYMBOL "__x64_sys_prctl"
|
|
||||||
#define REBOOT_SYMBOL "__x64_sys_reboot"
|
#define REBOOT_SYMBOL "__x64_sys_reboot"
|
||||||
#define SYS_READ_SYMBOL "__x64_sys_read"
|
#define SYS_READ_SYMBOL "__x64_sys_read"
|
||||||
#define SYS_EXECVE_SYMBOL "__x64_sys_execve"
|
#define SYS_EXECVE_SYMBOL "__x64_sys_execve"
|
||||||
#define SYS_EXECVE_COMPAT_SYMBOL "__x64_compat_sys_execve"
|
#define SYS_SETNS_SYMBOL __x64_sys_setns
|
||||||
#else
|
#else
|
||||||
#define PRCTL_SYMBOL "sys_prctl"
|
|
||||||
#define REBOOT_SYMBOL "sys_reboot"
|
#define REBOOT_SYMBOL "sys_reboot"
|
||||||
#define SYS_READ_SYMBOL "sys_read"
|
#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_SYMBOL "sys_execve"
|
||||||
#define SYS_EXECVE_COMPAT_SYMBOL "compat_sys_execve"
|
#define SYS_SETNS_SYMBOL sys_setns
|
||||||
#endif
|
#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
|
#else
|
||||||
#ifdef KSU_KPROBES_HOOK
|
#ifdef KSU_KPROBES_HOOK
|
||||||
@@ -108,4 +88,4 @@
|
|||||||
#define PT_REAL_REGS(regs) ((regs))
|
#define PT_REAL_REGS(regs) ((regs))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "dynamic_manager.h"
|
#include "dynamic_manager.h"
|
||||||
#include "klog.h" // IWYU pragma: keep
|
#include "klog.h" // IWYU pragma: keep
|
||||||
#include "manager.h"
|
#include "manager.h"
|
||||||
|
#include "kernel_compat.h"
|
||||||
|
|
||||||
#define MAX_MANAGERS 2
|
#define MAX_MANAGERS 2
|
||||||
|
|
||||||
@@ -232,23 +233,23 @@ static void do_save_dynamic_manager(struct work_struct *work)
|
|||||||
return;
|
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)) {
|
if (IS_ERR(fp)) {
|
||||||
pr_err("save_dynamic_manager create file failed: %ld\n", PTR_ERR(fp));
|
pr_err("save_dynamic_manager create file failed: %ld\n", PTR_ERR(fp));
|
||||||
return;
|
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");
|
pr_err("save_dynamic_manager write magic failed.\n");
|
||||||
goto exit;
|
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");
|
pr_err("save_dynamic_manager write version failed.\n");
|
||||||
goto exit;
|
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");
|
pr_err("save_dynamic_manager write config failed.\n");
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
@@ -270,7 +271,7 @@ static void do_load_dynamic_manager(struct work_struct *work)
|
|||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int i;
|
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 (IS_ERR(fp)) {
|
||||||
if (PTR_ERR(fp) == -ENOENT) {
|
if (PTR_ERR(fp) == -ENOENT) {
|
||||||
pr_info("No saved dynamic manager config found\n");
|
pr_info("No saved dynamic manager config found\n");
|
||||||
@@ -280,20 +281,20 @@ static void do_load_dynamic_manager(struct work_struct *work)
|
|||||||
return;
|
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) {
|
magic != DYNAMIC_MANAGER_FILE_MAGIC) {
|
||||||
pr_err("dynamic manager file invalid magic: %x!\n", magic);
|
pr_err("dynamic manager file invalid magic: %x!\n", magic);
|
||||||
goto exit;
|
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");
|
pr_err("dynamic manager read version failed\n");
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_info("dynamic manager file version: %d\n", version);
|
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) {
|
if (ret <= 0) {
|
||||||
pr_info("load_dynamic_manager read err: %zd\n", ret);
|
pr_info("load_dynamic_manager read err: %zd\n", ret);
|
||||||
goto exit;
|
goto exit;
|
||||||
@@ -347,14 +348,14 @@ static void do_clear_dynamic_manager(struct work_struct *work)
|
|||||||
|
|
||||||
memset(zero_buffer, 0, sizeof(zero_buffer));
|
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)) {
|
if (IS_ERR(fp)) {
|
||||||
pr_err("clear_dynamic_manager create file failed: %ld\n", PTR_ERR(fp));
|
pr_err("clear_dynamic_manager create file failed: %ld\n", PTR_ERR(fp));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write null bytes to overwrite the file content
|
// 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");
|
pr_err("clear_dynamic_manager write null bytes failed.\n");
|
||||||
} else {
|
} else {
|
||||||
pr_info("Dynamic sign config file cleared successfully\n");
|
pr_info("Dynamic sign config file cleared successfully\n");
|
||||||
|
|||||||
209
kernel/feature.c
209
kernel/feature.c
@@ -9,165 +9,168 @@ static DEFINE_MUTEX(feature_mutex);
|
|||||||
|
|
||||||
int ksu_register_feature_handler(const struct ksu_feature_handler *handler)
|
int ksu_register_feature_handler(const struct ksu_feature_handler *handler)
|
||||||
{
|
{
|
||||||
if (!handler) {
|
if (!handler) {
|
||||||
pr_err("feature: register handler is NULL\n");
|
pr_err("feature: register handler is NULL\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handler->feature_id >= KSU_FEATURE_MAX) {
|
if (handler->feature_id >= KSU_FEATURE_MAX) {
|
||||||
pr_err("feature: invalid feature_id %u\n", handler->feature_id);
|
pr_err("feature: invalid feature_id %u\n", handler->feature_id);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!handler->get_handler && !handler->set_handler) {
|
if (!handler->get_handler && !handler->set_handler) {
|
||||||
pr_err("feature: no handler provided for feature %u\n", handler->feature_id);
|
pr_err("feature: no handler provided for feature %u\n",
|
||||||
return -EINVAL;
|
handler->feature_id);
|
||||||
}
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
mutex_lock(&feature_mutex);
|
mutex_lock(&feature_mutex);
|
||||||
|
|
||||||
if (feature_handlers[handler->feature_id]) {
|
if (feature_handlers[handler->feature_id]) {
|
||||||
pr_warn("feature: handler for %u already registered, overwriting\n",
|
pr_warn("feature: handler for %u already registered, overwriting\n",
|
||||||
handler->feature_id);
|
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",
|
pr_info("feature: registered handler for %s (id=%u)\n",
|
||||||
handler->name ? handler->name : "unknown", handler->feature_id);
|
handler->name ? handler->name : "unknown", handler->feature_id);
|
||||||
|
|
||||||
mutex_unlock(&feature_mutex);
|
mutex_unlock(&feature_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ksu_unregister_feature_handler(u32 feature_id)
|
int ksu_unregister_feature_handler(u32 feature_id)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (feature_id >= KSU_FEATURE_MAX) {
|
if (feature_id >= KSU_FEATURE_MAX) {
|
||||||
pr_err("feature: invalid feature_id %u\n", feature_id);
|
pr_err("feature: invalid feature_id %u\n", feature_id);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&feature_mutex);
|
mutex_lock(&feature_mutex);
|
||||||
|
|
||||||
if (!feature_handlers[feature_id]) {
|
if (!feature_handlers[feature_id]) {
|
||||||
pr_warn("feature: no handler registered for %u\n", feature_id);
|
pr_warn("feature: no handler registered for %u\n", feature_id);
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
goto out;
|
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:
|
out:
|
||||||
mutex_unlock(&feature_mutex);
|
mutex_unlock(&feature_mutex);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ksu_get_feature(u32 feature_id, u64 *value, bool *supported)
|
int ksu_get_feature(u32 feature_id, u64 *value, bool *supported)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
const struct ksu_feature_handler *handler;
|
const struct ksu_feature_handler *handler;
|
||||||
|
|
||||||
if (feature_id >= KSU_FEATURE_MAX) {
|
if (feature_id >= KSU_FEATURE_MAX) {
|
||||||
pr_err("feature: invalid feature_id %u\n", feature_id);
|
pr_err("feature: invalid feature_id %u\n", feature_id);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!value || !supported) {
|
if (!value || !supported) {
|
||||||
pr_err("feature: invalid parameters\n");
|
pr_err("feature: invalid parameters\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&feature_mutex);
|
mutex_lock(&feature_mutex);
|
||||||
|
|
||||||
handler = feature_handlers[feature_id];
|
handler = feature_handlers[feature_id];
|
||||||
|
|
||||||
if (!handler) {
|
if (!handler) {
|
||||||
*supported = false;
|
*supported = false;
|
||||||
*value = 0;
|
*value = 0;
|
||||||
pr_debug("feature: feature %u not supported\n", feature_id);
|
pr_debug("feature: feature %u not supported\n", feature_id);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
*supported = true;
|
*supported = true;
|
||||||
|
|
||||||
if (!handler->get_handler) {
|
if (!handler->get_handler) {
|
||||||
pr_warn("feature: no get_handler for feature %u\n", feature_id);
|
pr_warn("feature: no get_handler for feature %u\n", feature_id);
|
||||||
ret = -EOPNOTSUPP;
|
ret = -EOPNOTSUPP;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = handler->get_handler(value);
|
ret = handler->get_handler(value);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("feature: get_handler for %u failed: %d\n", feature_id, ret);
|
pr_err("feature: get_handler for %u failed: %d\n", feature_id,
|
||||||
}
|
ret);
|
||||||
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&feature_mutex);
|
mutex_unlock(&feature_mutex);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ksu_set_feature(u32 feature_id, u64 value)
|
int ksu_set_feature(u32 feature_id, u64 value)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
const struct ksu_feature_handler *handler;
|
const struct ksu_feature_handler *handler;
|
||||||
|
|
||||||
if (feature_id >= KSU_FEATURE_MAX) {
|
if (feature_id >= KSU_FEATURE_MAX) {
|
||||||
pr_err("feature: invalid feature_id %u\n", feature_id);
|
pr_err("feature: invalid feature_id %u\n", feature_id);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&feature_mutex);
|
mutex_lock(&feature_mutex);
|
||||||
|
|
||||||
handler = feature_handlers[feature_id];
|
handler = feature_handlers[feature_id];
|
||||||
|
|
||||||
if (!handler) {
|
if (!handler) {
|
||||||
pr_err("feature: feature %u not registered\n", feature_id);
|
pr_err("feature: feature %u not registered\n", feature_id);
|
||||||
ret = -EOPNOTSUPP;
|
ret = -EOPNOTSUPP;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!handler->set_handler) {
|
if (!handler->set_handler) {
|
||||||
pr_warn("feature: no set_handler for feature %u\n", feature_id);
|
pr_warn("feature: no set_handler for feature %u\n", feature_id);
|
||||||
ret = -EOPNOTSUPP;
|
ret = -EOPNOTSUPP;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = handler->set_handler(value);
|
ret = handler->set_handler(value);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("feature: set_handler for %u failed: %d\n", feature_id, ret);
|
pr_err("feature: set_handler for %u failed: %d\n", feature_id,
|
||||||
}
|
ret);
|
||||||
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&feature_mutex);
|
mutex_unlock(&feature_mutex);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ksu_feature_init(void)
|
void ksu_feature_init(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < KSU_FEATURE_MAX; i++) {
|
for (i = 0; i < KSU_FEATURE_MAX; i++) {
|
||||||
feature_handlers[i] = NULL;
|
feature_handlers[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_info("feature: feature management initialized\n");
|
pr_info("feature: feature management initialized\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ksu_feature_exit(void)
|
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++) {
|
for (i = 0; i < KSU_FEATURE_MAX; i++) {
|
||||||
feature_handlers[i] = NULL;
|
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");
|
||||||
}
|
}
|
||||||
@@ -4,22 +4,22 @@
|
|||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
enum ksu_feature_id {
|
enum ksu_feature_id {
|
||||||
KSU_FEATURE_SU_COMPAT = 0,
|
KSU_FEATURE_SU_COMPAT = 0,
|
||||||
KSU_FEATURE_KERNEL_UMOUNT = 1,
|
KSU_FEATURE_KERNEL_UMOUNT = 1,
|
||||||
KSU_FEATURE_ENHANCED_SECURITY = 2,
|
KSU_FEATURE_ENHANCED_SECURITY = 2,
|
||||||
KSU_FEATURE_SULOG = 3,
|
KSU_FEATURE_SULOG = 3,
|
||||||
|
|
||||||
KSU_FEATURE_MAX
|
KSU_FEATURE_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef int (*ksu_feature_get_t)(u64 *value);
|
typedef int (*ksu_feature_get_t)(u64 *value);
|
||||||
typedef int (*ksu_feature_set_t)(u64 value);
|
typedef int (*ksu_feature_set_t)(u64 value);
|
||||||
|
|
||||||
struct ksu_feature_handler {
|
struct ksu_feature_handler {
|
||||||
u32 feature_id;
|
u32 feature_id;
|
||||||
const char *name;
|
const char *name;
|
||||||
ksu_feature_get_t get_handler;
|
ksu_feature_get_t get_handler;
|
||||||
ksu_feature_set_t set_handler;
|
ksu_feature_set_t set_handler;
|
||||||
};
|
};
|
||||||
|
|
||||||
int ksu_register_feature_handler(const struct ksu_feature_handler *handler);
|
int ksu_register_feature_handler(const struct ksu_feature_handler *handler);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include <linux/anon_inodes.h>
|
#include <linux/anon_inodes.h>
|
||||||
|
#include <linux/aio.h> // kernel 3.18
|
||||||
#include <linux/capability.h>
|
#include <linux/capability.h>
|
||||||
#include <linux/cred.h>
|
#include <linux/cred.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
@@ -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);
|
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) {
|
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 ksu_file_wrapper* data = iocb->ki_filp->private_data;
|
||||||
struct file* orig = data->orig;
|
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;
|
iocb->ki_filp = orig;
|
||||||
return orig->f_op->write_iter(iocb, iovi);
|
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)
|
#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) {
|
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;
|
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;
|
kiocb->ki_filp = orig;
|
||||||
return orig->f_op->iopoll(kiocb, icb, v);
|
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) {
|
static int ksu_wrapper_iopoll(struct kiocb *kiocb, bool spin) {
|
||||||
struct ksu_file_wrapper* data = kiocb->ki_filp->private_data;
|
struct ksu_file_wrapper* data = kiocb->ki_filp->private_data;
|
||||||
struct file* orig = data->orig;
|
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);
|
return orig->f_op->iopoll(kiocb, spin);
|
||||||
}
|
}
|
||||||
#endif
|
#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) {
|
static int ksu_wrapper_iterate (struct file *fp, struct dir_context *dc) {
|
||||||
struct ksu_file_wrapper* data = fp->private_data;
|
struct ksu_file_wrapper* data = fp->private_data;
|
||||||
struct file* orig = data->orig;
|
struct file* orig = data->orig;
|
||||||
@@ -73,13 +74,25 @@ static int ksu_wrapper_iterate (struct file *fp, struct dir_context *dc) {
|
|||||||
}
|
}
|
||||||
#endif
|
#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) {
|
static int ksu_wrapper_iterate_shared(struct file *fp, struct dir_context *dc) {
|
||||||
struct ksu_file_wrapper* data = fp->private_data;
|
struct ksu_file_wrapper* data = fp->private_data;
|
||||||
struct file* orig = data->orig;
|
struct file* orig = data->orig;
|
||||||
return orig->f_op->iterate_shared(orig, dc);
|
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 ksu_file_wrapper* data = fp->private_data;
|
||||||
struct file* orig = data->orig;
|
struct file* orig = data->orig;
|
||||||
return orig->f_op->poll(orig, pts);
|
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;
|
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) {
|
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 ksu_file_wrapper* data = fp->private_data;
|
||||||
struct file* orig = data->orig;
|
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;
|
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
|
#endif
|
||||||
|
|
||||||
static long ksu_wrapper_fallocate(struct file *fp, int mode, loff_t offset, loff_t len) {
|
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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
|
||||||
static void ksu_wrapper_show_fdinfo(struct seq_file *m, struct file *f) {
|
static void ksu_wrapper_show_fdinfo(struct seq_file *m, struct file *f) {
|
||||||
struct ksu_file_wrapper* data = f->private_data;
|
struct ksu_file_wrapper* data = f->private_data;
|
||||||
struct file* orig = data->orig;
|
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);
|
orig->f_op->show_fdinfo(m, orig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
|
||||||
static ssize_t ksu_wrapper_copy_file_range(struct file *f1, loff_t off1, struct file *f2,
|
static int ksu_wrapper_show_fdinfo(struct seq_file *m, struct file *f) {
|
||||||
loff_t off2, size_t sz, unsigned int flags) {
|
struct ksu_file_wrapper* data = f->private_data;
|
||||||
// TODO: determine which file to use
|
|
||||||
struct ksu_file_wrapper* data = f1->private_data;
|
|
||||||
struct file* orig = data->orig;
|
struct file* orig = data->orig;
|
||||||
if (orig->f_op->copy_file_range) {
|
if (orig->f_op->show_fdinfo) {
|
||||||
return orig->f_op->copy_file_range(orig, off1, f2, off2, sz, flags);
|
orig->f_op->show_fdinfo(m, orig);
|
||||||
}
|
}
|
||||||
return -EINVAL;
|
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,
|
static loff_t ksu_wrapper_remap_file_range(struct file *file_in, loff_t pos_in,
|
||||||
struct file *file_out, loff_t pos_out,
|
struct file *file_out, loff_t pos_out,
|
||||||
loff_t len, unsigned int remap_flags) {
|
loff_t len, unsigned int remap_flags) {
|
||||||
// TODO: determine which file to use
|
if (remap_flags & REMAP_FILE_DEDUP) {
|
||||||
struct ksu_file_wrapper* data = file_in->private_data;
|
struct ksu_file_wrapper* data = file_out->private_data;
|
||||||
struct file* orig = data->orig;
|
struct file* orig = data->orig;
|
||||||
if (orig->f_op->remap_file_range) {
|
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 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) {
|
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 ksu_file_wrapper* data = fp->private_data;
|
||||||
struct file* orig = data->orig;
|
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;
|
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
|
#endif
|
||||||
|
|
||||||
static int ksu_wrapper_release(struct inode *inode, struct file *filp) {
|
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.llseek = fp->f_op->llseek ? ksu_wrapper_llseek : NULL;
|
||||||
p->ops.read = fp->f_op->read ? ksu_wrapper_read : NULL;
|
p->ops.read = fp->f_op->read ? ksu_wrapper_read : NULL;
|
||||||
p->ops.write = fp->f_op->write ? ksu_wrapper_write : 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.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;
|
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;
|
p->ops.iopoll = fp->f_op->iopoll ? ksu_wrapper_iopoll : NULL;
|
||||||
#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))
|
||||||
p->ops.iterate = fp->f_op->iterate ? ksu_wrapper_iterate : NULL;
|
p->ops.iterate = fp->f_op->iterate ? ksu_wrapper_iterate : NULL;
|
||||||
#endif
|
#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;
|
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.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.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;
|
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.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.setlease = fp->f_op->setlease ? ksu_wrapper_setlease : NULL;
|
||||||
p->ops.fallocate = fp->f_op->fallocate ? ksu_wrapper_fallocate : 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.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
|
#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)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
|
||||||
p->ops.splice_eof = fp->f_op->splice_eof ? ksu_wrapper_splice_eof : NULL;
|
p->ops.splice_eof = fp->f_op->splice_eof ? ksu_wrapper_splice_eof : NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -4,15 +4,11 @@
|
|||||||
#include <linux/file.h>
|
#include <linux/file.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
|
|
||||||
typedef unsigned int __poll_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct ksu_file_wrapper {
|
struct ksu_file_wrapper {
|
||||||
struct file* orig;
|
struct file *orig;
|
||||||
struct file_operations ops;
|
struct file_operations ops;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ksu_file_wrapper* ksu_create_file_wrapper(struct file* fp);
|
struct ksu_file_wrapper *ksu_create_file_wrapper(struct file *fp);
|
||||||
void ksu_delete_file_wrapper(struct ksu_file_wrapper* data);
|
void ksu_delete_file_wrapper(struct ksu_file_wrapper *data);
|
||||||
#endif // KSU_FILE_WRAPPER_H
|
#endif // KSU_FILE_WRAPPER_H
|
||||||
@@ -1,8 +1,5 @@
|
|||||||
#include <linux/version.h>
|
#include <linux/version.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/nsproxy.h>
|
|
||||||
#include <linux/filter.h>
|
|
||||||
#include <linux/seccomp.h>
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
||||||
#include <linux/sched/task.h>
|
#include <linux/sched/task.h>
|
||||||
#else
|
#else
|
||||||
@@ -12,69 +9,117 @@
|
|||||||
#include "klog.h" // IWYU pragma: keep
|
#include "klog.h" // IWYU pragma: keep
|
||||||
#include "kernel_compat.h"
|
#include "kernel_compat.h"
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \
|
||||||
defined(CONFIG_IS_HW_HISI) || \
|
defined(CONFIG_IS_HW_HISI) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND)
|
||||||
defined(CONFIG_KSU_ALLOWLIST_WORKAROUND)
|
|
||||||
#include <linux/key.h>
|
#include <linux/key.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/cred.h>
|
#include <linux/cred.h>
|
||||||
|
#include <linux/lsm_hooks.h>
|
||||||
|
|
||||||
|
extern int install_session_keyring_to_cred(struct cred *, struct key *);
|
||||||
struct key *init_session_keyring = NULL;
|
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;
|
struct cred *new;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
new = prepare_creds();
|
new = prepare_creds();
|
||||||
if (!new)
|
if (!new)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
ret = install_session_keyring_to_cred(new, keyring);
|
ret = install_session_keyring_to_cred(new, keyring);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
abort_creds(new);
|
abort_creds(new);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return commit_creds(new);
|
return commit_creds(new);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) || defined(KSU_OPTIONAL_STRNCPY)
|
struct file *ksu_filp_open_compat(const char *filename, int flags, umode_t mode)
|
||||||
long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr,
|
|
||||||
long count)
|
|
||||||
{
|
{
|
||||||
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)
|
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
|
||||||
long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr,
|
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
|
#else
|
||||||
// Copied from: https://elixir.bootlin.com/linux/v4.9.337/source/mm/maccess.c#L201
|
// 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 ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr,
|
||||||
long count)
|
long count)
|
||||||
{
|
{
|
||||||
mm_segment_t old_fs = get_fs();
|
mm_segment_t old_fs = get_fs();
|
||||||
long ret;
|
long ret;
|
||||||
|
|
||||||
if (unlikely(count <= 0))
|
if (unlikely(count <= 0))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
set_fs(USER_DS);
|
set_fs(USER_DS);
|
||||||
pagefault_disable();
|
pagefault_disable();
|
||||||
ret = strncpy_from_user(dst, unsafe_addr, count);
|
ret = strncpy_from_user(dst, unsafe_addr, count);
|
||||||
pagefault_enable();
|
pagefault_enable();
|
||||||
set_fs(old_fs);
|
set_fs(old_fs);
|
||||||
|
|
||||||
if (ret >= count) {
|
if (ret >= count) {
|
||||||
ret = count;
|
ret = count;
|
||||||
dst[ret - 1] = '\0';
|
dst[ret - 1] = '\0';
|
||||||
} else if (ret > 0) {
|
} else if (ret > 0) {
|
||||||
ret++;
|
ret++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -3,7 +3,24 @@
|
|||||||
|
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/version.h>
|
#include <linux/version.h>
|
||||||
#include <linux/cred.h>
|
#include <linux/task_work.h>
|
||||||
|
#include <linux/fdtable.h>
|
||||||
|
#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
|
// Checks for UH, KDP and RKP
|
||||||
#ifdef SAMSUNG_UH_DRIVER_EXIST
|
#ifdef SAMSUNG_UH_DRIVER_EXIST
|
||||||
@@ -13,29 +30,44 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern long ksu_strncpy_from_user_nofault(char *dst,
|
extern long ksu_strncpy_from_user_nofault(char *dst,
|
||||||
const void __user *unsafe_addr,
|
const void __user *unsafe_addr,
|
||||||
long count);
|
long count);
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \
|
extern struct file *ksu_filp_open_compat(const char *filename, int flags,
|
||||||
defined(CONFIG_IS_HW_HISI) || \
|
umode_t mode);
|
||||||
defined(CONFIG_KSU_ALLOWLIST_WORKAROUND)
|
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;
|
extern struct key *init_session_keyring;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)
|
#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
|
#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
|
#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)
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 7, 0)
|
||||||
#define TWA_RESUME true
|
#ifndef TWA_RESUME
|
||||||
|
#define TWA_RESUME true
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)
|
static inline int do_close_fd(unsigned int fd)
|
||||||
#define ksu_force_sig(sig) force_sig(sig);
|
{
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
|
||||||
|
return close_fd(fd);
|
||||||
#else
|
#else
|
||||||
#define ksu_force_sig(sig) force_sig(sig, current);
|
return __close_fd(current->files, fd);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,71 +1,67 @@
|
|||||||
#include <linux/version.h>
|
#include <linux/version.h>
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/nsproxy.h>
|
#include <linux/sched/task.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
#include <linux/filter.h>
|
#include <linux/filter.h>
|
||||||
#include <linux/seccomp.h>
|
#include <linux/seccomp.h>
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
|
||||||
#include <linux/sched/task.h>
|
|
||||||
#else
|
|
||||||
#include <linux/sched.h>
|
|
||||||
#endif
|
|
||||||
#include <linux/uaccess.h>
|
|
||||||
#include "klog.h" // IWYU pragma: keep
|
#include "klog.h" // IWYU pragma: keep
|
||||||
#include "seccomp_cache.h"
|
#include "seccomp_cache.h"
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 2) // Android backport this feature in 5.10.2
|
|
||||||
struct action_cache {
|
struct action_cache {
|
||||||
DECLARE_BITMAP(allow_native, NR_syscalls);
|
DECLARE_BITMAP(allow_native, SECCOMP_ARCH_NATIVE_NR);
|
||||||
#ifdef SECCOMP_ARCH_COMPAT
|
#ifdef SECCOMP_ARCH_COMPAT
|
||||||
DECLARE_BITMAP(allow_compat, SECCOMP_ARCH_COMPAT_NR);
|
DECLARE_BITMAP(allow_compat, SECCOMP_ARCH_COMPAT_NR);
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct seccomp_filter {
|
struct seccomp_filter {
|
||||||
refcount_t refs;
|
refcount_t refs;
|
||||||
refcount_t users;
|
refcount_t users;
|
||||||
bool log;
|
bool log;
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
|
||||||
bool wait_killable_recv;
|
bool wait_killable_recv;
|
||||||
#endif
|
#endif
|
||||||
struct action_cache cache;
|
struct action_cache cache;
|
||||||
struct seccomp_filter *prev;
|
struct seccomp_filter *prev;
|
||||||
struct bpf_prog *prog;
|
struct bpf_prog *prog;
|
||||||
struct notification *notif;
|
struct notification *notif;
|
||||||
struct mutex notify_lock;
|
struct mutex notify_lock;
|
||||||
wait_queue_head_t wqh;
|
wait_queue_head_t wqh;
|
||||||
};
|
};
|
||||||
|
|
||||||
void ksu_seccomp_clear_cache(struct seccomp_filter *filter, int nr)
|
void ksu_seccomp_clear_cache(struct seccomp_filter *filter, int nr)
|
||||||
{
|
{
|
||||||
if (!filter) {
|
if (!filter) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nr >= 0 && nr < NR_syscalls) {
|
if (nr >= 0 && nr < SECCOMP_ARCH_NATIVE_NR) {
|
||||||
clear_bit(nr, filter->cache.allow_native);
|
clear_bit(nr, filter->cache.allow_native);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SECCOMP_ARCH_COMPAT
|
#ifdef SECCOMP_ARCH_COMPAT
|
||||||
if (nr >= 0 && nr < SECCOMP_ARCH_COMPAT_NR) {
|
if (nr >= 0 && nr < SECCOMP_ARCH_COMPAT_NR) {
|
||||||
clear_bit(nr, filter->cache.allow_compat);
|
clear_bit(nr, filter->cache.allow_compat);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ksu_seccomp_allow_cache(struct seccomp_filter *filter, int nr)
|
void ksu_seccomp_allow_cache(struct seccomp_filter *filter, int nr)
|
||||||
{
|
{
|
||||||
if (!filter) {
|
if (!filter) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nr >= 0 && nr < NR_syscalls) {
|
if (nr >= 0 && nr < SECCOMP_ARCH_NATIVE_NR) {
|
||||||
set_bit(nr, filter->cache.allow_native);
|
set_bit(nr, filter->cache.allow_native);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SECCOMP_ARCH_COMPAT
|
#ifdef SECCOMP_ARCH_COMPAT
|
||||||
if (nr >= 0 && nr < SECCOMP_ARCH_COMPAT_NR) {
|
if (nr >= 0 && nr < SECCOMP_ARCH_COMPAT_NR) {
|
||||||
set_bit(nr, filter->cache.allow_compat);
|
set_bit(nr, filter->cache.allow_compat);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/version.h>
|
#include <linux/version.h>
|
||||||
|
|
||||||
#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_clear_cache(struct seccomp_filter *filter, int nr);
|
||||||
extern void ksu_seccomp_allow_cache(struct seccomp_filter *filter, int nr);
|
extern void ksu_seccomp_allow_cache(struct seccomp_filter *filter, int nr);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#include "selinux.h"
|
#include "selinux.h"
|
||||||
#include "sepolicy.h"
|
#include "sepolicy.h"
|
||||||
#include "ss/services.h"
|
#include "ss/services.h"
|
||||||
#include "linux/lsm_audit.h"
|
#include "linux/lsm_audit.h" // IWYU pragma: keep
|
||||||
#include "xfrm.h"
|
#include "xfrm.h"
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
||||||
@@ -20,128 +20,125 @@
|
|||||||
|
|
||||||
static struct policydb *get_policydb(void)
|
static struct policydb *get_policydb(void)
|
||||||
{
|
{
|
||||||
struct policydb *db;
|
struct policydb *db;
|
||||||
// selinux_state does not exists before 4.19
|
// selinux_state does not exists before 4.19
|
||||||
#ifdef KSU_COMPAT_USE_SELINUX_STATE
|
#ifdef KSU_COMPAT_USE_SELINUX_STATE
|
||||||
#ifdef SELINUX_POLICY_INSTEAD_SELINUX_SS
|
#ifdef SELINUX_POLICY_INSTEAD_SELINUX_SS
|
||||||
struct selinux_policy *policy = selinux_state.policy;
|
struct selinux_policy *policy = selinux_state.policy;
|
||||||
db = &policy->policydb;
|
db = &policy->policydb;
|
||||||
#else
|
#else
|
||||||
struct selinux_ss *ss = selinux_state.ss;
|
struct selinux_ss *ss = selinux_state.ss;
|
||||||
db = &ss->policydb;
|
db = &ss->policydb;
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
db = &policydb;
|
db = &policydb;
|
||||||
#endif
|
#endif
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEFINE_MUTEX(ksu_rules);
|
static DEFINE_MUTEX(ksu_rules);
|
||||||
|
|
||||||
void apply_kernelsu_rules(void)
|
void apply_kernelsu_rules(void)
|
||||||
{
|
{
|
||||||
struct policydb *db;
|
struct policydb *db;
|
||||||
|
|
||||||
if (!getenforce()) {
|
if (!getenforce()) {
|
||||||
pr_info("SELinux permissive or disabled, apply rules!\n");
|
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_permissive(db, KERNEL_SU_DOMAIN);
|
||||||
ksu_typeattribute(db, KERNEL_SU_DOMAIN, "mlstrustedsubject");
|
ksu_typeattribute(db, KERNEL_SU_DOMAIN, "mlstrustedsubject");
|
||||||
ksu_typeattribute(db, KERNEL_SU_DOMAIN, "netdomain");
|
ksu_typeattribute(db, KERNEL_SU_DOMAIN, "netdomain");
|
||||||
ksu_typeattribute(db, KERNEL_SU_DOMAIN, "bluetoothdomain");
|
ksu_typeattribute(db, KERNEL_SU_DOMAIN, "bluetoothdomain");
|
||||||
|
|
||||||
// Create unconstrained file type
|
// Create unconstrained file type
|
||||||
ksu_type(db, KERNEL_SU_FILE, "file_type");
|
ksu_type(db, KERNEL_SU_FILE, "file_type");
|
||||||
ksu_typeattribute(db, KERNEL_SU_FILE, "mlstrustedobject");
|
ksu_typeattribute(db, KERNEL_SU_FILE, "mlstrustedobject");
|
||||||
ksu_allow(db, ALL, KERNEL_SU_FILE, ALL, ALL);
|
ksu_allow(db, ALL, KERNEL_SU_FILE, ALL, ALL);
|
||||||
|
|
||||||
// allow all!
|
// allow all!
|
||||||
ksu_allow(db, KERNEL_SU_DOMAIN, ALL, ALL, ALL);
|
ksu_allow(db, KERNEL_SU_DOMAIN, ALL, ALL, ALL);
|
||||||
|
|
||||||
// allow us do any ioctl
|
// allow us do any ioctl
|
||||||
if (db->policyvers >= POLICYDB_VERSION_XPERMS_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, "blk_file", ALL);
|
||||||
ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "fifo_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, "chr_file", ALL);
|
||||||
ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "file", ALL);
|
ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "file", ALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we need to save allowlist in /data/adb/ksu
|
// 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", "dir", ALL);
|
||||||
ksu_allow(db, "kernel", "adb_data_file", "file", ALL);
|
ksu_allow(db, "kernel", "adb_data_file", "file", ALL);
|
||||||
// we need to search /data/app
|
// we need to search /data/app
|
||||||
ksu_allow(db, "kernel", "apk_data_file", "file", "open");
|
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", "open");
|
||||||
ksu_allow(db, "kernel", "apk_data_file", "dir", "read");
|
ksu_allow(db, "kernel", "apk_data_file", "dir", "read");
|
||||||
ksu_allow(db, "kernel", "apk_data_file", "dir", "search");
|
ksu_allow(db, "kernel", "apk_data_file", "dir", "search");
|
||||||
// we may need to do mount on shell
|
// we may need to do mount on shell
|
||||||
ksu_allow(db, "kernel", "shell_data_file", "file", ALL);
|
ksu_allow(db, "kernel", "shell_data_file", "file", ALL);
|
||||||
// we need to read /data/system/packages.list
|
// we need to read /data/system/packages.list
|
||||||
ksu_allow(db, "kernel", "kernel", "capability", "dac_override");
|
ksu_allow(db, "kernel", "kernel", "capability", "dac_override");
|
||||||
// Android 10+:
|
// Android 10+:
|
||||||
// http://aospxref.com/android-12.0.0_r3/xref/system/sepolicy/private/file_contexts#512
|
// http://aospxref.com/android-12.0.0_r3/xref/system/sepolicy/private/file_contexts#512
|
||||||
ksu_allow(db, "kernel", "packages_list_file", "file", ALL);
|
ksu_allow(db, "kernel", "packages_list_file", "file", ALL);
|
||||||
// Kernel 4.4
|
// Kernel 4.4
|
||||||
ksu_allow(db, "kernel", "packages_list_file", "dir", ALL);
|
ksu_allow(db, "kernel", "packages_list_file", "dir", ALL);
|
||||||
// Android 9-:
|
// Android 9-:
|
||||||
// http://aospxref.com/android-9.0.0_r61/xref/system/sepolicy/private/file_contexts#360
|
// 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", "file", ALL);
|
||||||
ksu_allow(db, "kernel", "system_data_file", "dir", ALL);
|
ksu_allow(db, "kernel", "system_data_file", "dir", ALL);
|
||||||
// our ksud triggered by init
|
// our ksud triggered by init
|
||||||
ksu_allow(db, "init", "adb_data_file", "file", ALL);
|
ksu_allow(db, "init", "adb_data_file", "file", ALL);
|
||||||
ksu_allow(db, "init", "adb_data_file", "dir", ALL); // #1289
|
ksu_allow(db, "init", "adb_data_file", "dir", ALL); // #1289
|
||||||
ksu_allow(db, "init", KERNEL_SU_DOMAIN, ALL, ALL);
|
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
|
// copied from Magisk rules
|
||||||
ksu_allow(db, "zygote", "adb_data_file", "dir", "search");
|
// 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
|
// allowLog
|
||||||
// suRights
|
ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "dir", "search");
|
||||||
ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "dir", "search");
|
ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "read");
|
||||||
ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "dir", "read");
|
ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "open");
|
||||||
ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "file", "open");
|
ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "getattr");
|
||||||
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
|
// dumpsys
|
||||||
ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "dir", "search");
|
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fd", "use");
|
||||||
ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "read");
|
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "write");
|
||||||
ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "open");
|
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "read");
|
||||||
ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "getattr");
|
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "open");
|
||||||
|
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "getattr");
|
||||||
|
|
||||||
// dumpsys
|
// bootctl
|
||||||
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fd", "use");
|
ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "dir", "search");
|
||||||
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "write");
|
ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "file", "read");
|
||||||
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "read");
|
ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "file", "open");
|
||||||
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "open");
|
ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "process",
|
||||||
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "getattr");
|
"getattr");
|
||||||
|
|
||||||
// bootctl
|
// For mounting loop devices, mirrors, tmpfs
|
||||||
ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "dir", "search");
|
ksu_allow(db, "kernel", ALL, "file", "read");
|
||||||
ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "file", "read");
|
ksu_allow(db, "kernel", ALL, "file", "write");
|
||||||
ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "file", "open");
|
|
||||||
ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "process",
|
|
||||||
"getattr");
|
|
||||||
|
|
||||||
// For mounting loop devices, mirrors, tmpfs
|
// Allow all binder transactions
|
||||||
ksu_allow(db, "kernel", ALL, "file", "read");
|
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "binder", ALL);
|
||||||
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 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
|
#ifdef CONFIG_KSU_SUSFS
|
||||||
// Allow umount in zygote process without installing zygisk
|
// Allow umount in zygote process without installing zygisk
|
||||||
ksu_allow(db, "zygote", "labeledfs", "filesystem", "unmount");
|
ksu_allow(db, "zygote", "labeledfs", "filesystem", "unmount");
|
||||||
@@ -150,8 +147,7 @@ void apply_kernelsu_rules(void)
|
|||||||
susfs_set_ksu_sid();
|
susfs_set_ksu_sid();
|
||||||
susfs_set_zygote_sid();
|
susfs_set_zygote_sid();
|
||||||
#endif
|
#endif
|
||||||
|
mutex_unlock(&ksu_rules);
|
||||||
mutex_unlock(&ksu_rules);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MAX_SEPOL_LEN 128
|
#define MAX_SEPOL_LEN 128
|
||||||
@@ -167,372 +163,369 @@ void apply_kernelsu_rules(void)
|
|||||||
#define CMD_GENFSCON 9
|
#define CMD_GENFSCON 9
|
||||||
|
|
||||||
struct sepol_data {
|
struct sepol_data {
|
||||||
uint32_t cmd;
|
u32 cmd;
|
||||||
uint32_t subcmd;
|
u32 subcmd;
|
||||||
uint64_t sepol1;
|
u64 sepol1;
|
||||||
uint64_t sepol2;
|
u64 sepol2;
|
||||||
uint64_t sepol3;
|
u64 sepol3;
|
||||||
uint64_t sepol4;
|
u64 sepol4;
|
||||||
uint64_t sepol5;
|
u64 sepol5;
|
||||||
uint64_t sepol6;
|
u64 sepol6;
|
||||||
uint64_t sepol7;
|
u64 sepol7;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int get_object(char *buf, char __user *user_object, size_t buf_sz,
|
static int get_object(char *buf, char __user *user_object, size_t buf_sz,
|
||||||
char **object)
|
char **object)
|
||||||
{
|
{
|
||||||
if (!user_object) {
|
if (!user_object) {
|
||||||
*object = ALL;
|
*object = ALL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strncpy_from_user(buf, user_object, buf_sz) < 0) {
|
if (strncpy_from_user(buf, user_object, buf_sz) < 0) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
*object = buf;
|
*object = buf;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 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);
|
extern int avc_ss_reset(u32 seqno);
|
||||||
#else
|
#else
|
||||||
extern int avc_ss_reset(struct selinux_avc *avc, u32 seqno);
|
extern int avc_ss_reset(struct selinux_avc *avc, u32 seqno);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// reset avc cache table, otherwise the new rules will not take effect if already denied
|
// reset avc cache table, otherwise the new rules will not take effect if already denied
|
||||||
static void reset_avc_cache(void)
|
static void reset_avc_cache(void)
|
||||||
{
|
{
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) || \
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) || \
|
||||||
!defined(KSU_COMPAT_USE_SELINUX_STATE)
|
!defined(KSU_COMPAT_USE_SELINUX_STATE)
|
||||||
avc_ss_reset(0);
|
avc_ss_reset(0);
|
||||||
selnl_notify_policyload(0);
|
selnl_notify_policyload(0);
|
||||||
selinux_status_update_policyload(0);
|
selinux_status_update_policyload(0);
|
||||||
#else
|
#else
|
||||||
struct selinux_avc *avc = selinux_state.avc;
|
struct selinux_avc *avc = selinux_state.avc;
|
||||||
avc_ss_reset(avc, 0);
|
avc_ss_reset(avc, 0);
|
||||||
selnl_notify_policyload(0);
|
selnl_notify_policyload(0);
|
||||||
selinux_status_update_policyload(&selinux_state, 0);
|
selinux_status_update_policyload(&selinux_state, 0);
|
||||||
#endif
|
#endif
|
||||||
selinux_xfrm_notify_policyload();
|
selinux_xfrm_notify_policyload();
|
||||||
}
|
}
|
||||||
|
|
||||||
int handle_sepolicy(unsigned long arg3, void __user *arg4)
|
int handle_sepolicy(unsigned long arg3, void __user *arg4)
|
||||||
{
|
{
|
||||||
struct policydb *db;
|
struct policydb *db;
|
||||||
|
|
||||||
if (!arg4) {
|
if (!arg4) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!getenforce()) {
|
if (!getenforce()) {
|
||||||
pr_info("SELinux permissive or disabled when handle policy!\n");
|
pr_info("SELinux permissive or disabled when handle policy!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sepol_data data = { 0 };
|
struct sepol_data data;
|
||||||
if (copy_from_user(&data, arg4, sizeof(struct sepol_data))) {
|
if (copy_from_user(&data, arg4, sizeof(struct sepol_data))) {
|
||||||
pr_err("sepol: copy sepol_data failed.\n");
|
pr_err("sepol: copy sepol_data failed.\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 cmd = data.cmd;
|
u32 cmd = data.cmd;
|
||||||
u32 subcmd = data.subcmd;
|
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) {
|
char *s, *t, *c, *p;
|
||||||
case CMD_NORMAL_PERM: {
|
if (get_object(src_buf, (void __user *)data.sepol1,
|
||||||
char src_buf[MAX_SEPOL_LEN];
|
sizeof(src_buf), &s) < 0) {
|
||||||
char tgt_buf[MAX_SEPOL_LEN];
|
pr_err("sepol: copy src failed.\n");
|
||||||
char cls_buf[MAX_SEPOL_LEN];
|
goto exit;
|
||||||
char perm_buf[MAX_SEPOL_LEN];
|
}
|
||||||
|
|
||||||
char *s, *t, *c, *p;
|
if (get_object(tgt_buf, (void __user *)data.sepol2,
|
||||||
if (get_object(src_buf, (void __user *)data.sepol1,
|
sizeof(tgt_buf), &t) < 0) {
|
||||||
sizeof(src_buf), &s) < 0) {
|
pr_err("sepol: copy tgt failed.\n");
|
||||||
pr_err("sepol: copy src failed.\n");
|
goto exit;
|
||||||
goto exit;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (get_object(tgt_buf, (void __user *)data.sepol2,
|
if (get_object(cls_buf, (void __user *)data.sepol3,
|
||||||
sizeof(tgt_buf), &t) < 0) {
|
sizeof(cls_buf), &c) < 0) {
|
||||||
pr_err("sepol: copy tgt failed.\n");
|
pr_err("sepol: copy cls failed.\n");
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_object(cls_buf, (void __user *)data.sepol3,
|
if (get_object(perm_buf, (void __user *)data.sepol4,
|
||||||
sizeof(cls_buf), &c) < 0) {
|
sizeof(perm_buf), &p) < 0) {
|
||||||
pr_err("sepol: copy cls failed.\n");
|
pr_err("sepol: copy perm failed.\n");
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_object(perm_buf, (void __user *)data.sepol4,
|
bool success = false;
|
||||||
sizeof(perm_buf), &p) < 0) {
|
|
||||||
pr_err("sepol: copy perm failed.\n");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
char __maybe_unused
|
||||||
success = ksu_allow(db, s, t, c, p);
|
operation[MAX_SEPOL_LEN]; // it is always ioctl now!
|
||||||
} else if (subcmd == 2) {
|
char perm_set[MAX_SEPOL_LEN];
|
||||||
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
|
char *s, *t, *c;
|
||||||
operation[MAX_SEPOL_LEN]; // it is always ioctl now!
|
if (get_object(src_buf, (void __user *)data.sepol1,
|
||||||
char perm_set[MAX_SEPOL_LEN];
|
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;
|
bool success = false;
|
||||||
if (get_object(src_buf, (void __user *)data.sepol1,
|
if (subcmd == 1) {
|
||||||
sizeof(src_buf), &s) < 0) {
|
success = ksu_allowxperm(db, s, t, c, perm_set);
|
||||||
pr_err("sepol: copy src failed.\n");
|
} else if (subcmd == 2) {
|
||||||
goto exit;
|
success = ksu_auditallowxperm(db, s, t, c, perm_set);
|
||||||
}
|
} else if (subcmd == 3) {
|
||||||
if (get_object(tgt_buf, (void __user *)data.sepol2,
|
success = ksu_dontauditxperm(db, s, t, c, perm_set);
|
||||||
sizeof(tgt_buf), &t) < 0) {
|
} else {
|
||||||
pr_err("sepol: copy tgt failed.\n");
|
pr_err("sepol: unknown subcmd: %d\n", subcmd);
|
||||||
goto exit;
|
}
|
||||||
}
|
ret = success ? 0 : -EINVAL;
|
||||||
if (get_object(cls_buf, (void __user *)data.sepol3,
|
break;
|
||||||
sizeof(cls_buf), &c) < 0) {
|
}
|
||||||
pr_err("sepol: copy cls failed.\n");
|
case CMD_TYPE_STATE: {
|
||||||
goto exit;
|
char src[MAX_SEPOL_LEN];
|
||||||
}
|
|
||||||
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 (strncpy_from_user(src, (void __user *)data.sepol1,
|
||||||
if (subcmd == 1) {
|
sizeof(src)) < 0) {
|
||||||
success = ksu_allowxperm(db, s, t, c, perm_set);
|
pr_err("sepol: copy src failed.\n");
|
||||||
} else if (subcmd == 2) {
|
goto exit;
|
||||||
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,
|
bool success = false;
|
||||||
sizeof(src)) < 0) {
|
if (subcmd == 1) {
|
||||||
pr_err("sepol: copy src failed.\n");
|
success = ksu_permissive(db, src);
|
||||||
goto exit;
|
} 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 (strncpy_from_user(type, (void __user *)data.sepol1,
|
||||||
if (subcmd == 1) {
|
sizeof(type)) < 0) {
|
||||||
success = ksu_permissive(db, src);
|
pr_err("sepol: copy type failed.\n");
|
||||||
} else if (subcmd == 2) {
|
goto exit;
|
||||||
success = ksu_enforce(db, src);
|
}
|
||||||
} else {
|
if (strncpy_from_user(attr, (void __user *)data.sepol2,
|
||||||
pr_err("sepol: unknown subcmd: %d\n", subcmd);
|
sizeof(attr)) < 0) {
|
||||||
}
|
pr_err("sepol: copy attr failed.\n");
|
||||||
if (success)
|
goto exit;
|
||||||
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,
|
bool success = false;
|
||||||
sizeof(type)) < 0) {
|
if (cmd == CMD_TYPE) {
|
||||||
pr_err("sepol: copy type failed.\n");
|
success = ksu_type(db, type, attr);
|
||||||
goto exit;
|
} else {
|
||||||
}
|
success = ksu_typeattribute(db, type, attr);
|
||||||
if (strncpy_from_user(attr, (void __user *)data.sepol2,
|
}
|
||||||
sizeof(attr)) < 0) {
|
if (!success) {
|
||||||
pr_err("sepol: copy attr failed.\n");
|
pr_err("sepol: %d failed.\n", cmd);
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CMD_ATTR: {
|
||||||
|
char attr[MAX_SEPOL_LEN];
|
||||||
|
|
||||||
bool success = false;
|
if (strncpy_from_user(attr, (void __user *)data.sepol1,
|
||||||
if (cmd == CMD_TYPE) {
|
sizeof(attr)) < 0) {
|
||||||
success = ksu_type(db, type, attr);
|
pr_err("sepol: copy attr failed.\n");
|
||||||
} else {
|
goto exit;
|
||||||
success = ksu_typeattribute(db, type, attr);
|
}
|
||||||
}
|
if (!ksu_attribute(db, attr)) {
|
||||||
if (!success) {
|
pr_err("sepol: %d failed.\n", cmd);
|
||||||
pr_err("sepol: %d failed.\n", cmd);
|
goto exit;
|
||||||
goto exit;
|
}
|
||||||
}
|
ret = 0;
|
||||||
ret = 0;
|
break;
|
||||||
break;
|
}
|
||||||
}
|
case CMD_TYPE_TRANSITION: {
|
||||||
case CMD_ATTR: {
|
char src[MAX_SEPOL_LEN];
|
||||||
char attr[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,
|
if (strncpy_from_user(src, (void __user *)data.sepol1,
|
||||||
sizeof(attr)) < 0) {
|
sizeof(src)) < 0) {
|
||||||
pr_err("sepol: copy attr failed.\n");
|
pr_err("sepol: copy src failed.\n");
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
if (!ksu_attribute(db, attr)) {
|
if (strncpy_from_user(tgt, (void __user *)data.sepol2,
|
||||||
pr_err("sepol: %d failed.\n", cmd);
|
sizeof(tgt)) < 0) {
|
||||||
goto exit;
|
pr_err("sepol: copy tgt failed.\n");
|
||||||
}
|
goto exit;
|
||||||
ret = 0;
|
}
|
||||||
break;
|
if (strncpy_from_user(cls, (void __user *)data.sepol3,
|
||||||
}
|
sizeof(cls)) < 0) {
|
||||||
case CMD_TYPE_TRANSITION: {
|
pr_err("sepol: copy cls failed.\n");
|
||||||
char src[MAX_SEPOL_LEN];
|
goto exit;
|
||||||
char tgt[MAX_SEPOL_LEN];
|
}
|
||||||
char cls[MAX_SEPOL_LEN];
|
if (strncpy_from_user(default_type, (void __user *)data.sepol4,
|
||||||
char default_type[MAX_SEPOL_LEN];
|
sizeof(default_type)) < 0) {
|
||||||
char object[MAX_SEPOL_LEN];
|
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,
|
bool success = ksu_type_transition(db, src, tgt, cls,
|
||||||
sizeof(src)) < 0) {
|
default_type, real_object);
|
||||||
pr_err("sepol: copy src failed.\n");
|
if (success)
|
||||||
goto exit;
|
ret = 0;
|
||||||
}
|
break;
|
||||||
if (strncpy_from_user(tgt, (void __user *)data.sepol2,
|
}
|
||||||
sizeof(tgt)) < 0) {
|
case CMD_TYPE_CHANGE: {
|
||||||
pr_err("sepol: copy tgt failed.\n");
|
char src[MAX_SEPOL_LEN];
|
||||||
goto exit;
|
char tgt[MAX_SEPOL_LEN];
|
||||||
}
|
char cls[MAX_SEPOL_LEN];
|
||||||
if (strncpy_from_user(cls, (void __user *)data.sepol3,
|
char default_type[MAX_SEPOL_LEN];
|
||||||
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,
|
if (strncpy_from_user(src, (void __user *)data.sepol1,
|
||||||
default_type, real_object);
|
sizeof(src)) < 0) {
|
||||||
if (success)
|
pr_err("sepol: copy src failed.\n");
|
||||||
ret = 0;
|
goto exit;
|
||||||
break;
|
}
|
||||||
}
|
if (strncpy_from_user(tgt, (void __user *)data.sepol2,
|
||||||
case CMD_TYPE_CHANGE: {
|
sizeof(tgt)) < 0) {
|
||||||
char src[MAX_SEPOL_LEN];
|
pr_err("sepol: copy tgt failed.\n");
|
||||||
char tgt[MAX_SEPOL_LEN];
|
goto exit;
|
||||||
char cls[MAX_SEPOL_LEN];
|
}
|
||||||
char default_type[MAX_SEPOL_LEN];
|
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,
|
if (!ksu_genfscon(db, name, path, context)) {
|
||||||
sizeof(src)) < 0) {
|
pr_err("sepol: %d failed.\n", cmd);
|
||||||
pr_err("sepol: copy src failed.\n");
|
goto exit;
|
||||||
goto exit;
|
}
|
||||||
}
|
ret = 0;
|
||||||
if (strncpy_from_user(tgt, (void __user *)data.sepol2,
|
break;
|
||||||
sizeof(tgt)) < 0) {
|
}
|
||||||
pr_err("sepol: copy tgt failed.\n");
|
default: {
|
||||||
goto exit;
|
pr_err("sepol: unknown cmd: %d\n", cmd);
|
||||||
}
|
break;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
mutex_unlock(&ksu_rules);
|
mutex_unlock(&ksu_rules);
|
||||||
|
|
||||||
// only allow and xallow needs to reset avc cache, but we cannot do that because
|
// 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.
|
// we are in atomic context. so we just reset it every time.
|
||||||
reset_avc_cache();
|
reset_avc_cache();
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "linux/cred.h"
|
#include "linux/cred.h"
|
||||||
#include "linux/sched.h"
|
#include "linux/sched.h"
|
||||||
#include <linux/version.h>
|
#include "linux/security.h"
|
||||||
|
#include "linux/version.h"
|
||||||
#include "selinux_defs.h"
|
#include "selinux_defs.h"
|
||||||
#include "../klog.h" // IWYU pragma: keep
|
#include "../klog.h" // IWYU pragma: keep
|
||||||
|
|
||||||
@@ -8,163 +9,178 @@
|
|||||||
|
|
||||||
static int transive_to_domain(const char *domain)
|
static int transive_to_domain(const char *domain)
|
||||||
{
|
{
|
||||||
struct cred *cred;
|
struct cred *cred;
|
||||||
struct task_security_struct *tsec;
|
struct task_security_struct *tsec;
|
||||||
u32 sid;
|
u32 sid;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
cred = (struct cred *)__task_cred(current);
|
cred = (struct cred *)__task_cred(current);
|
||||||
|
|
||||||
tsec = cred->security;
|
tsec = cred->security;
|
||||||
if (!tsec) {
|
if (!tsec) {
|
||||||
pr_err("tsec == NULL!\n");
|
pr_err("tsec == NULL!\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = security_secctx_to_secid(domain, strlen(domain), &sid);
|
error = security_secctx_to_secid(domain, strlen(domain), &sid);
|
||||||
if (error) {
|
if (error) {
|
||||||
pr_info("security_secctx_to_secid %s -> sid: %d, error: %d\n",
|
pr_info("security_secctx_to_secid %s -> sid: %d, error: %d\n",
|
||||||
domain, sid, error);
|
domain, sid, error);
|
||||||
}
|
}
|
||||||
|
if (!error) {
|
||||||
if (!error) {
|
tsec->sid = sid;
|
||||||
tsec->sid = sid;
|
tsec->create_sid = 0;
|
||||||
tsec->create_sid = 0;
|
tsec->keycreate_sid = 0;
|
||||||
tsec->keycreate_sid = 0;
|
tsec->sockcreate_sid = 0;
|
||||||
tsec->sockcreate_sid = 0;
|
}
|
||||||
}
|
return error;
|
||||||
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(4, 19, 0)
|
#if LINUX_VERSION_CODE <= KERNEL_VERSION(4, 19, 0)
|
||||||
bool __maybe_unused is_ksu_transition(const struct task_security_struct *old_tsec,
|
bool __maybe_unused
|
||||||
const struct task_security_struct *new_tsec)
|
is_ksu_transition(const struct task_security_struct *old_tsec,
|
||||||
|
const struct task_security_struct *new_tsec)
|
||||||
{
|
{
|
||||||
static u32 ksu_sid;
|
static u32 ksu_sid;
|
||||||
char *secdata;
|
char *secdata;
|
||||||
u32 seclen;
|
u32 seclen;
|
||||||
bool allowed = false;
|
bool allowed = false;
|
||||||
|
|
||||||
if (!ksu_sid)
|
if (!ksu_sid)
|
||||||
security_secctx_to_secid(KERNEL_SU_DOMAIN, strlen(KERNEL_SU_DOMAIN), &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))
|
if (security_secid_to_secctx(old_tsec->sid, &secdata, &seclen))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
allowed = (!strcmp("u:r:init:s0", secdata) && new_tsec->sid == ksu_sid);
|
allowed = (!strcmp("u:r:init:s0", secdata) && new_tsec->sid == ksu_sid);
|
||||||
security_release_secctx(secdata, seclen);
|
security_release_secctx(secdata, seclen);
|
||||||
return allowed;
|
return allowed;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void setup_selinux(const char *domain)
|
void setup_selinux(const char *domain)
|
||||||
{
|
{
|
||||||
if (transive_to_domain(domain)) {
|
if (transive_to_domain(domain)) {
|
||||||
pr_err("transive domain failed.\n");
|
pr_err("transive domain failed.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setenforce(bool enforce)
|
void setenforce(bool enforce)
|
||||||
{
|
{
|
||||||
__setenforce(enforce);
|
__setenforce(enforce);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool getenforce(void)
|
bool getenforce(void)
|
||||||
{
|
{
|
||||||
if (is_selinux_disabled()) {
|
if (is_selinux_disabled()) {
|
||||||
return false;
|
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)
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 14, 0)
|
||||||
struct lsm_context {
|
struct lsm_context {
|
||||||
char *context;
|
char *context;
|
||||||
u32 len;
|
u32 len;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __security_secid_to_secctx(u32 secid, struct lsm_context *cp)
|
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)
|
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
|
#else
|
||||||
#define __security_secid_to_secctx security_secid_to_secctx
|
#define __security_secid_to_secctx security_secid_to_secctx
|
||||||
#define __security_release_secctx security_release_secctx
|
#define __security_release_secctx security_release_secctx
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool is_task_ksu_domain(const struct cred* cred)
|
bool is_task_ksu_domain(const struct cred *cred)
|
||||||
{
|
{
|
||||||
struct lsm_context ctx;
|
struct lsm_context ctx;
|
||||||
bool result;
|
bool result;
|
||||||
if (!cred) {
|
if (!cred) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const struct task_security_struct *tsec = selinux_cred(cred);
|
const struct task_security_struct *tsec = __selinux_cred(cred);
|
||||||
if (!tsec) {
|
if (!tsec) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int err = __security_secid_to_secctx(tsec->sid, &ctx);
|
int err = __security_secid_to_secctx(tsec->sid, &ctx);
|
||||||
if (err) {
|
if (err) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
result = strncmp(KERNEL_SU_DOMAIN, ctx.context, ctx.len) == 0;
|
result = strncmp(KERNEL_SU_DOMAIN, ctx.context, ctx.len) == 0;
|
||||||
__security_release_secctx(&ctx);
|
__security_release_secctx(&ctx);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_ksu_domain()
|
bool is_ksu_domain(void)
|
||||||
{
|
{
|
||||||
current_sid();
|
current_sid();
|
||||||
return is_task_ksu_domain(current_cred());
|
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) {
|
if (!cred) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const struct task_security_struct * tsec = selinux_cred(cred);
|
const struct task_security_struct *tsec = __selinux_cred(cred);
|
||||||
if (!tsec) {
|
if (!tsec) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
struct lsm_context ctx;
|
struct lsm_context ctx;
|
||||||
bool result;
|
bool result;
|
||||||
int err = __security_secid_to_secctx(tsec->sid, &ctx);
|
int err = __security_secid_to_secctx(tsec->sid, &ctx);
|
||||||
if (err) {
|
if (err) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
result = strncmp(context, ctx.context, ctx.len) == 0;
|
result = strncmp(context, ctx.context, ctx.len) == 0;
|
||||||
__security_release_secctx(&ctx);
|
__security_release_secctx(&ctx);
|
||||||
return result;
|
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) {
|
bool is_init(const struct cred *cred)
|
||||||
return is_context(cred, "u:r:init:s0");
|
{
|
||||||
|
return is_context(cred, "u:r:init:s0");
|
||||||
}
|
}
|
||||||
|
|
||||||
#define KSU_FILE_DOMAIN "u:object_r:ksu_file: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;
|
u32 ksu_file_sid = 0;
|
||||||
int err = security_secctx_to_secid(KSU_FILE_DOMAIN, strlen(KSU_FILE_DOMAIN),
|
int err = security_secctx_to_secid(
|
||||||
&ksu_file_sid);
|
KSU_FILE_DOMAIN, strlen(KSU_FILE_DOMAIN), &ksu_file_sid);
|
||||||
if (err) {
|
if (err) {
|
||||||
pr_info("get ksufile sid err %d\n", err);
|
pr_info("get ksufile sid err %d\n", err);
|
||||||
}
|
}
|
||||||
return ksu_file_sid;
|
return ksu_file_sid;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_KSU_SUSFS
|
#ifdef CONFIG_KSU_SUSFS
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
#ifndef __KSU_H_SELINUX
|
#ifndef __KSU_H_SELINUX
|
||||||
#define __KSU_H_SELINUX
|
#define __KSU_H_SELINUX
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include "linux/types.h"
|
||||||
#include <linux/version.h>
|
#include "linux/version.h"
|
||||||
#include "linux/sched.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
|
#define KSU_COMPAT_USE_SELINUX_STATE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -15,13 +16,13 @@ void setenforce(bool);
|
|||||||
|
|
||||||
bool getenforce(void);
|
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_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);
|
void apply_kernelsu_rules(void);
|
||||||
|
|
||||||
@@ -42,4 +43,4 @@ bool susfs_is_current_init_domain(void);
|
|||||||
void susfs_set_priv_app_sid(void);
|
void susfs_set_priv_app_sid(void);
|
||||||
#endif // #ifdef CONFIG_KSU_SUSFS
|
#endif // #ifdef CONFIG_KSU_SUSFS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -12,25 +12,31 @@
|
|||||||
|
|
||||||
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
|
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
|
||||||
#ifdef KSU_COMPAT_USE_SELINUX_STATE
|
#ifdef KSU_COMPAT_USE_SELINUX_STATE
|
||||||
#define is_selinux_disabled() (selinux_state.disabled)
|
#define is_selinux_disabled() (selinux_state.disabled)
|
||||||
#else
|
#else
|
||||||
#define is_selinux_disabled() (selinux_disabled)
|
#define is_selinux_disabled() (selinux_disabled)
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
#define is_selinux_disabled() (0)
|
#define is_selinux_disabled() (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
|
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
|
||||||
#ifdef KSU_COMPAT_USE_SELINUX_STATE
|
#ifdef KSU_COMPAT_USE_SELINUX_STATE
|
||||||
#define __is_selinux_enforcing() (selinux_state.enforcing)
|
#define __is_selinux_enforcing() (selinux_state.enforcing)
|
||||||
#define __setenforce(val) selinux_state.enforcing = val
|
#define __setenforce(val) selinux_state.enforcing = val
|
||||||
#elif defined(SAMSUNG_SELINUX_PORTING) || !defined(KSU_COMPAT_USE_SELINUX_STATE)
|
#elif defined(SAMSUNG_SELINUX_PORTING) || !defined(KSU_COMPAT_USE_SELINUX_STATE)
|
||||||
#define __is_selinux_enforcing() (selinux_enforcing)
|
#define __is_selinux_enforcing() (selinux_enforcing)
|
||||||
#define __setenforce(val) selinux_enforcing = val
|
#define __setenforce(val) selinux_enforcing = val
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
#define __is_selinux_enforcing() (1)
|
#define __is_selinux_enforcing() (1)
|
||||||
#define __setenforce(val)
|
#define __setenforce(val)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef KSU_OPTIONAL_SELINUX_CRED
|
||||||
|
#define __selinux_cred(cred) (selinux_cred(cred))
|
||||||
|
#else
|
||||||
|
#define __selinux_cred(cred) (cred->security)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,12 @@
|
|||||||
#include <linux/compiler.h>
|
#include <linux/compiler.h>
|
||||||
|
#include <linux/version.h>
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
||||||
#include <linux/sched/signal.h>
|
#include <linux/sched/signal.h>
|
||||||
|
#endif
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/task_work.h>
|
#include <linux/task_work.h>
|
||||||
#include <linux/thread_info.h>
|
#include <linux/thread_info.h>
|
||||||
#include <linux/seccomp.h>
|
#include <linux/seccomp.h>
|
||||||
#include <linux/bpf.h>
|
|
||||||
#include <linux/capability.h>
|
#include <linux/capability.h>
|
||||||
#include <linux/cred.h>
|
#include <linux/cred.h>
|
||||||
#include <linux/dcache.h>
|
#include <linux/dcache.h>
|
||||||
@@ -12,7 +14,6 @@
|
|||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/init_task.h>
|
#include <linux/init_task.h>
|
||||||
#include <linux/kallsyms.h>
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/kprobes.h>
|
#include <linux/kprobes.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
@@ -22,34 +23,20 @@
|
|||||||
#include <linux/path.h>
|
#include <linux/path.h>
|
||||||
#include <linux/printk.h>
|
#include <linux/printk.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/security.h>
|
|
||||||
#include <linux/stddef.h>
|
#include <linux/stddef.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
#include <linux/uidgid.h>
|
#include <linux/uidgid.h>
|
||||||
#include <linux/version.h>
|
|
||||||
#include <linux/binfmts.h>
|
|
||||||
#include <linux/tty.h>
|
|
||||||
|
|
||||||
#ifdef CONFIG_KSU_SUSFS
|
#ifdef CONFIG_KSU_SUSFS
|
||||||
#include <linux/susfs.h>
|
#include <linux/susfs.h>
|
||||||
#endif // #ifdef CONFIG_KSU_SUSFS
|
#endif // #ifdef CONFIG_KSU_SUSFS
|
||||||
|
|
||||||
#ifdef MODULE
|
|
||||||
#include <linux/list.h>
|
|
||||||
#include <linux/irqflags.h>
|
|
||||||
#include <linux/mm_types.h>
|
|
||||||
#include <linux/rcupdate.h>
|
|
||||||
#include <linux/vmalloc.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "allowlist.h"
|
#include "allowlist.h"
|
||||||
#include "setuid_hook.h"
|
#include "setuid_hook.h"
|
||||||
#include "feature.h"
|
#include "feature.h"
|
||||||
#include "klog.h" // IWYU pragma: keep
|
#include "klog.h" // IWYU pragma: keep
|
||||||
#include "kernel_compat.h"
|
|
||||||
#include "ksu.h"
|
|
||||||
#include "manager.h"
|
#include "manager.h"
|
||||||
#include "selinux/selinux.h"
|
#include "selinux/selinux.h"
|
||||||
#include "seccomp_cache.h"
|
#include "seccomp_cache.h"
|
||||||
@@ -58,8 +45,6 @@
|
|||||||
#include "syscall_hook_manager.h"
|
#include "syscall_hook_manager.h"
|
||||||
#endif
|
#endif
|
||||||
#include "kernel_umount.h"
|
#include "kernel_umount.h"
|
||||||
#include "app_profile.h"
|
|
||||||
|
|
||||||
#include "sulog.h"
|
#include "sulog.h"
|
||||||
|
|
||||||
#ifdef CONFIG_KSU_SUSFS
|
#ifdef CONFIG_KSU_SUSFS
|
||||||
@@ -100,97 +85,113 @@ static bool ksu_enhanced_security_enabled = false;
|
|||||||
|
|
||||||
static int enhanced_security_feature_get(u64 *value)
|
static int enhanced_security_feature_get(u64 *value)
|
||||||
{
|
{
|
||||||
*value = ksu_enhanced_security_enabled ? 1 : 0;
|
*value = ksu_enhanced_security_enabled ? 1 : 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int enhanced_security_feature_set(u64 value)
|
static int enhanced_security_feature_set(u64 value)
|
||||||
{
|
{
|
||||||
bool enable = value != 0;
|
bool enable = value != 0;
|
||||||
ksu_enhanced_security_enabled = enable;
|
ksu_enhanced_security_enabled = enable;
|
||||||
pr_info("enhanced_security: set to %d\n", enable);
|
pr_info("enhanced_security: set to %d\n", enable);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct ksu_feature_handler enhanced_security_handler = {
|
static const struct ksu_feature_handler enhanced_security_handler = {
|
||||||
.feature_id = KSU_FEATURE_ENHANCED_SECURITY,
|
.feature_id = KSU_FEATURE_ENHANCED_SECURITY,
|
||||||
.name = "enhanced_security",
|
.name = "enhanced_security",
|
||||||
.get_handler = enhanced_security_feature_get,
|
.get_handler = enhanced_security_feature_get,
|
||||||
.set_handler = enhanced_security_feature_set,
|
.set_handler = enhanced_security_feature_set,
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline bool is_allow_su(void)
|
static inline bool is_allow_su(void)
|
||||||
{
|
{
|
||||||
if (is_manager()) {
|
if (is_manager()) {
|
||||||
// we are manager, allow!
|
// we are manager, allow!
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return ksu_is_allow_uid_for_current(current_uid().val);
|
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
|
#ifndef CONFIG_KSU_SUSFS
|
||||||
int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid)
|
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;
|
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 != new_uid)
|
||||||
if (old_uid != 0 && ksu_enhanced_security_enabled) {
|
pr_info("handle_setresuid from %d to %d\n", old_uid, new_uid);
|
||||||
// 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 on private space, see if its possibly the manager
|
// if old process is root, ignore it.
|
||||||
if (new_uid > PER_USER_RANGE && new_uid % PER_USER_RANGE == ksu_get_manager_uid()) {
|
if (old_uid != 0 && ksu_enhanced_security_enabled) {
|
||||||
ksu_set_manager_uid(new_uid);
|
// 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 LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
||||||
if (ksu_get_manager_uid() == new_uid) {
|
if (ksu_get_manager_uid() == new_uid) {
|
||||||
pr_info("install fd for manager: %d\n", new_uid);
|
pr_info("install fd for ksu manager(uid=%d)\n", new_uid);
|
||||||
ksu_install_fd();
|
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)) {
|
|
||||||
spin_lock_irq(¤t->sighand->siglock);
|
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);
|
spin_unlock_irq(¤t->sighand->siglock);
|
||||||
|
|
||||||
if (ksu_get_manager_uid() == new_uid) {
|
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
|
#endif
|
||||||
|
|
||||||
// Handle kernel umount
|
// Handle kernel umount
|
||||||
ksu_handle_umount(old_uid, new_uid);
|
ksu_handle_umount(old_uid, new_uid);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
extern bool ksu_kernel_umount_enabled;
|
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()) {
|
if (!is_ksu_domain()) {
|
||||||
pr_warn("find suspicious EoP: %d %s, from %d to %d\n",
|
pr_warn("find suspicious EoP: %d %s, from %d to %d\n",
|
||||||
current->pid, current->comm, old_uid, new_uid);
|
current->pid, current->comm, old_uid, new_uid);
|
||||||
ksu_force_sig(SIGKILL);
|
__force_sig(SIGKILL);
|
||||||
return 0;
|
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)) {
|
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",
|
pr_warn("find suspicious EoP: %d %s, from %d to %d\n",
|
||||||
current->pid, current->comm, old_uid, new_uid);
|
current->pid, current->comm, old_uid, new_uid);
|
||||||
ksu_force_sig(SIGKILL);
|
__force_sig(SIGKILL);
|
||||||
return 0;
|
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
|
// will always return true, that's why we need to explicitly check if new_uid belongs to
|
||||||
// ksu manager
|
// ksu manager
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
||||||
if (ksu_get_manager_uid() == new_uid % 100000) {
|
if (ksu_get_manager_uid() == new_uid) {
|
||||||
pr_info("install fd for manager: %d\n", new_uid);
|
pr_info("install fd for ksu manager(uid=%d)\n", new_uid);
|
||||||
ksu_install_fd();
|
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)) {
|
|
||||||
spin_lock_irq(¤t->sighand->siglock);
|
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);
|
spin_unlock_irq(¤t->sighand->siglock);
|
||||||
|
|
||||||
if (ksu_get_manager_uid() == new_uid) {
|
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)) {
|
if (unlikely(is_some_system_uid(new_uid) && susfs_is_umount_for_zygote_system_process_enabled)) {
|
||||||
goto do_umount;
|
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;
|
return 0;
|
||||||
|
|
||||||
@@ -341,15 +344,15 @@ skip_try_umount:
|
|||||||
|
|
||||||
void ksu_setuid_hook_init(void)
|
void ksu_setuid_hook_init(void)
|
||||||
{
|
{
|
||||||
ksu_kernel_umount_init();
|
ksu_kernel_umount_init();
|
||||||
if (ksu_register_feature_handler(&enhanced_security_handler)) {
|
if (ksu_register_feature_handler(&enhanced_security_handler)) {
|
||||||
pr_err("Failed to register enhanced security feature handler\n");
|
pr_err("Failed to register enhanced security feature handler\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ksu_setuid_hook_exit(void)
|
void ksu_setuid_hook_exit(void)
|
||||||
{
|
{
|
||||||
pr_info("ksu_core_exit\n");
|
pr_info("ksu_core_exit\n");
|
||||||
ksu_kernel_umount_exit();
|
ksu_kernel_umount_exit();
|
||||||
ksu_unregister_feature_handler(KSU_FEATURE_ENHANCED_SECURITY);
|
ksu_unregister_feature_handler(KSU_FEATURE_ENHANCED_SECURITY);
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,12 @@
|
|||||||
#ifndef __KSU_H_KSU_CORE
|
#ifndef __KSU_H_KSU_SETUID_HOOK
|
||||||
#define __KSU_H_KSU_CORE
|
#define __KSU_H_KSU_SETUID_HOOK
|
||||||
|
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include "apk_sign.h"
|
|
||||||
#include <linux/thread_info.h>
|
|
||||||
|
|
||||||
void ksu_setuid_hook_init(void);
|
void ksu_setuid_hook_init(void);
|
||||||
void ksu_setuid_hook_exit(void);
|
void ksu_setuid_hook_exit(void);
|
||||||
|
|
||||||
int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid);
|
int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -13,8 +13,9 @@
|
|||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
|
|
||||||
#include "klog.h"
|
|
||||||
#include "sulog.h"
|
#include "sulog.h"
|
||||||
|
#include "klog.h"
|
||||||
|
#include "kernel_compat.h"
|
||||||
#include "ksu.h"
|
#include "ksu.h"
|
||||||
#include "feature.h"
|
#include "feature.h"
|
||||||
|
|
||||||
@@ -164,7 +165,7 @@ static void sulog_work_handler(struct work_struct *work)
|
|||||||
if (list_empty(&local_queue))
|
if (list_empty(&local_queue))
|
||||||
return;
|
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)) {
|
if (IS_ERR(fp)) {
|
||||||
pr_err("sulog: failed to open log file: %ld\n", PTR_ERR(fp));
|
pr_err("sulog: failed to open log file: %ld\n", PTR_ERR(fp));
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@@ -179,7 +180,7 @@ static void sulog_work_handler(struct work_struct *work)
|
|||||||
}
|
}
|
||||||
|
|
||||||
list_for_each_entry(entry, &local_queue, list)
|
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);
|
vfs_fsync(fp, 0);
|
||||||
filp_close(fp, 0);
|
filp_close(fp, 0);
|
||||||
|
|||||||
@@ -421,64 +421,74 @@ static int do_set_feature(void __user *arg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_get_wrapper_fd(void __user *arg) {
|
// kcompat for older kernel
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)
|
||||||
#define getfd_secure anon_inode_create_getfd
|
#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
|
#define getfd_secure anon_inode_getfd_secure
|
||||||
#else
|
#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
|
#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
|
#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
|
#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);
|
if (sec) {
|
||||||
// copy original inode mode
|
sec->sid = ksu_file_sid;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
fput(pf);
|
fput(pf);
|
||||||
goto put_orig_file;
|
goto put_orig_file;
|
||||||
put_wrapper_data:
|
put_wrapper_data:
|
||||||
ksu_delete_file_wrapper(data);
|
ksu_delete_file_wrapper(data);
|
||||||
put_orig_file:
|
put_orig_file:
|
||||||
fput(f);
|
fput(f);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_manage_mark(void __user *arg)
|
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))) {
|
if (copy_to_user(tw->outp, &fd, sizeof(fd))) {
|
||||||
pr_err("install ksu fd reply err\n");
|
pr_err("install ksu fd reply err\n");
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
do_close_fd(fd);
|
||||||
close_fd(fd);
|
|
||||||
#else
|
|
||||||
__close_fd(current->files, fd);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kfree(tw);
|
kfree(tw);
|
||||||
|
|||||||
@@ -7,8 +7,9 @@
|
|||||||
#include "ksu.h"
|
#include "ksu.h"
|
||||||
|
|
||||||
#include "klog.h"
|
#include "klog.h"
|
||||||
#include "throne_comm.h"
|
|
||||||
#include "ksu.h"
|
#include "ksu.h"
|
||||||
|
#include "kernel_compat.h"
|
||||||
|
#include "throne_comm.h"
|
||||||
|
|
||||||
#define PROC_UID_SCANNER "ksu_uid_scanner"
|
#define PROC_UID_SCANNER "ksu_uid_scanner"
|
||||||
#define UID_SCANNER_STATE_FILE "/data/adb/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';
|
char state_char = ksu_uid_scanner_enabled ? '1' : '0';
|
||||||
loff_t off = 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)) {
|
if (IS_ERR(fp)) {
|
||||||
pr_err("save_throne_state create file failed: %ld\n", PTR_ERR(fp));
|
pr_err("save_throne_state create file failed: %ld\n", PTR_ERR(fp));
|
||||||
return;
|
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");
|
pr_err("save_throne_state write failed\n");
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
@@ -73,14 +74,14 @@ void do_load_throne_state(struct work_struct *work)
|
|||||||
loff_t off = 0;
|
loff_t off = 0;
|
||||||
ssize_t ret;
|
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)) {
|
if (IS_ERR(fp)) {
|
||||||
pr_info("throne state file not found, using default: disabled\n");
|
pr_info("throne state file not found, using default: disabled\n");
|
||||||
ksu_uid_scanner_enabled = false;
|
ksu_uid_scanner_enabled = false;
|
||||||
return;
|
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)) {
|
if (ret != sizeof(state_char)) {
|
||||||
pr_err("load_throne_state read err: %zd\n", ret);
|
pr_err("load_throne_state read err: %zd\n", ret);
|
||||||
ksu_uid_scanner_enabled = false;
|
ksu_uid_scanner_enabled = false;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "manager.h"
|
#include "manager.h"
|
||||||
#include "throne_tracker.h"
|
#include "throne_tracker.h"
|
||||||
#include "apk_sign.h"
|
#include "apk_sign.h"
|
||||||
|
#include "kernel_compat.h"
|
||||||
#include "dynamic_manager.h"
|
#include "dynamic_manager.h"
|
||||||
#include "throne_comm.h"
|
#include "throne_comm.h"
|
||||||
|
|
||||||
@@ -38,7 +39,7 @@ static int uid_from_um_list(struct list_head *uid_list)
|
|||||||
ssize_t nr;
|
ssize_t nr;
|
||||||
int cnt = 0;
|
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))
|
if (IS_ERR(fp))
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
@@ -55,7 +56,7 @@ static int uid_from_um_list(struct list_head *uid_list)
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
nr = kernel_read(fp, buf, size, &pos);
|
nr = ksu_kernel_read_compat(fp, buf, size, &pos);
|
||||||
filp_close(fp, NULL);
|
filp_close(fp, NULL);
|
||||||
if (nr != size) {
|
if (nr != size) {
|
||||||
pr_err("uid_list: short read %zd/%lld\n", 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;
|
struct file *file;
|
||||||
|
|
||||||
if (!stop) {
|
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)) {
|
if (IS_ERR(file)) {
|
||||||
pr_err("Failed to open directory: %s, err: %ld\n",
|
pr_err("Failed to open directory: %s, err: %ld\n",
|
||||||
pos->dirpath, PTR_ERR(file));
|
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)) {
|
if (IS_ERR(fp)) {
|
||||||
pr_err("%s: open " SYSTEM_PACKAGES_LIST_PATH " failed: %ld\n", __func__, PTR_ERR(fp));
|
pr_err("%s: open " SYSTEM_PACKAGES_LIST_PATH " failed: %ld\n", __func__, PTR_ERR(fp));
|
||||||
return;
|
return;
|
||||||
@@ -460,13 +461,13 @@ void track_throne(bool prune_only)
|
|||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
ssize_t count =
|
ssize_t count =
|
||||||
kernel_read(fp, &chr, sizeof(chr), &pos);
|
ksu_kernel_read_compat(fp, &chr, sizeof(chr), &pos);
|
||||||
if (count != sizeof(chr))
|
if (count != sizeof(chr))
|
||||||
break;
|
break;
|
||||||
if (chr != '\n')
|
if (chr != '\n')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
count = kernel_read(fp, buf, sizeof(buf),
|
count = ksu_kernel_read_compat(fp, buf, sizeof(buf),
|
||||||
&line_start);
|
&line_start);
|
||||||
struct uid_data *data =
|
struct uid_data *data =
|
||||||
kzalloc(sizeof(struct uid_data), GFP_ATOMIC);
|
kzalloc(sizeof(struct uid_data), GFP_ATOMIC);
|
||||||
|
|||||||
Reference in New Issue
Block a user