KernelSU/kernel/allowlist.c

330 lines
7.3 KiB
C
Raw Normal View History

2023-06-03 00:00:56 +08:00
#include "ksu.h"
#include "linux/delay.h"
#include "linux/fs.h"
2023-06-03 00:00:56 +08:00
#include "linux/gfp.h"
#include "linux/kernel.h"
#include "linux/list.h"
#include "linux/printk.h"
#include "linux/slab.h"
#include "linux/version.h"
2023-01-25 22:24:00 +08:00
#include "klog.h" // IWYU pragma: keep
#include "selinux/selinux.h"
#include "kernel_compat.h"
2023-06-03 00:00:56 +08:00
#include "allowlist.h"
#define FILE_MAGIC 0x7f4b5355 // ' KSU', u32
2023-06-03 00:00:56 +08:00
#define FILE_FORMAT_VERSION 2 // u32
2022-12-09 22:03:03 +08:00
static DEFINE_MUTEX(allowlist_mutex);
2023-06-03 00:00:56 +08:00
// default root identify
2023-06-03 10:18:11 +08:00
static struct root_profile default_root_profile;
static struct non_root_profile default_non_root_profile;
2023-06-03 00:00:56 +08:00
2023-06-03 10:18:11 +08:00
static void init_default_profiles()
2023-06-03 00:00:56 +08:00
{
2023-06-03 10:18:11 +08:00
default_root_profile.uid = 0;
default_root_profile.gid = 0;
default_root_profile.groups_count = 1;
default_root_profile.groups[0] = 0;
memset(&default_root_profile.capabilities, 0xff,
sizeof(default_root_profile.capabilities));
default_root_profile.namespaces = 0;
strcpy(default_root_profile.selinux_domain, "su");
default_non_root_profile.umount_modules = true;
2023-06-03 00:00:56 +08:00
}
2022-12-09 22:03:03 +08:00
struct perm_data {
struct list_head list;
2023-06-03 00:00:56 +08:00
struct app_profile profile;
2022-12-09 22:03:03 +08:00
};
static struct list_head allow_list;
#define KERNEL_SU_ALLOWLIST "/data/adb/ksu/.allowlist"
2022-12-09 22:03:03 +08:00
static struct work_struct ksu_save_work;
static struct work_struct ksu_load_work;
2022-12-11 21:59:57 +07:00
bool persistent_allow_list(void);
2022-12-09 22:03:03 +08:00
void ksu_show_allow_list(void)
{
struct perm_data *p = NULL;
struct list_head *pos = NULL;
pr_info("ksu_show_allow_list");
list_for_each (pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
2023-06-03 00:00:56 +08:00
pr_info("uid :%d, allow: %d\n", p->profile.current_uid,
p->profile.allow_su);
}
}
#ifdef CONFIG_KSU_DEBUG
2023-06-03 00:00:56 +08:00
static void ksu_grant_root_to_shell()
{
struct app_profile profile = {
.allow_su = true,
.current_uid = 2000,
};
strcpy(profile.key, "com.android.shell");
ksu_set_app_profile(&profile, false);
}
#endif
2023-06-03 00:00:56 +08:00
bool ksu_get_app_profile(struct app_profile *profile)
{
struct perm_data *p = NULL;
struct list_head *pos = NULL;
bool found = false;
list_for_each (pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
if (!strcmp(profile->key, p->profile.key)) {
// found it, override it with ours
memcpy(profile, &p->profile, sizeof(*profile));
found = true;
goto exit;
}
}
2023-06-03 00:00:56 +08:00
exit:
return found;
}
2023-06-03 00:00:56 +08:00
bool ksu_set_app_profile(struct app_profile *profile, bool persist)
{
struct perm_data *p = NULL;
struct list_head *pos = NULL;
bool result = false;
2023-06-03 00:00:56 +08:00
list_for_each (pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
2023-06-03 00:00:56 +08:00
if (!strcmp(profile->key, p->profile.key)) {
// found it, just override it all!
memcpy(&p->profile, profile, sizeof(*profile));
result = true;
goto exit;
}
}
// not found, alloc a new node!
p = (struct perm_data *)kmalloc(sizeof(struct perm_data), GFP_KERNEL);
if (!p) {
2023-06-03 00:00:56 +08:00
pr_err("ksu_set_app_profile alloc failed\n");
return false;
}
2023-06-03 00:00:56 +08:00
memcpy(&p->profile, profile, sizeof(*profile));
pr_info("set app profile, key: %s, uid: %d\n", profile->key,
profile->current_uid);
list_add_tail(&p->list, &allow_list);
result = true;
2022-12-09 22:03:03 +08:00
exit:
if (persist)
persistent_allow_list();
2022-12-09 22:03:03 +08:00
return result;
2022-12-09 22:03:03 +08:00
}
bool ksu_is_allow_uid(uid_t uid)
{
struct perm_data *p = NULL;
struct list_head *pos = NULL;
if (uid == 0) {
// already root, but only allow our domain.
return is_ksu_domain();
}
list_for_each (pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
// pr_info("is_allow_uid uid :%d, allow: %d\n", p->uid, p->allow);
2023-06-03 00:00:56 +08:00
if (uid == p->profile.current_uid) {
return p->profile.allow_su;
}
}
return false;
2022-12-09 22:03:03 +08:00
}
bool ksu_get_allow_list(int *array, int *length, bool allow)
{
struct perm_data *p = NULL;
struct list_head *pos = NULL;
int i = 0;
list_for_each (pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
// pr_info("get_allow_list uid: %d allow: %d\n", p->uid, p->allow);
2023-06-03 00:00:56 +08:00
if (p->profile.allow_su == allow) {
2023-06-03 19:22:59 +08:00
array[i++] = p->profile.current_uid;
}
}
*length = i;
return true;
2022-12-09 22:03:03 +08:00
}
2023-06-03 00:00:56 +08:00
void do_save_allow_list(struct work_struct *work)
{
u32 magic = FILE_MAGIC;
u32 version = FILE_FORMAT_VERSION;
struct perm_data *p = NULL;
struct list_head *pos = NULL;
loff_t off = 0;
KWORKER_INSTALL_KEYRING();
struct file *fp =
filp_open(KERNEL_SU_ALLOWLIST, O_WRONLY | O_CREAT, 0644);
if (IS_ERR(fp)) {
2023-05-22 10:39:54 +08:00
pr_err("save_allow_list creat file failed: %ld\n", PTR_ERR(fp));
return;
}
// store magic and version
2023-06-03 00:00:56 +08:00
if (ksu_kernel_write_compat(fp, &magic, sizeof(magic), &off) !=
sizeof(magic)) {
pr_err("save_allow_list write magic failed.\n");
goto exit;
}
if (ksu_kernel_write_compat(fp, &version, sizeof(version), &off) !=
sizeof(version)) {
pr_err("save_allow_list write version failed.\n");
goto exit;
}
list_for_each (pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
2023-06-03 00:00:56 +08:00
pr_info("save allow list, name: %s uid :%d, allow: %d\n",
p->profile.key, p->profile.current_uid,
p->profile.allow_su);
ksu_kernel_write_compat(fp, &p->profile, sizeof(p->profile),
&off);
}
2022-12-09 22:03:03 +08:00
exit:
filp_close(fp, 0);
2022-12-11 21:59:57 +07:00
}
2022-12-09 22:03:03 +08:00
void do_load_allow_list(struct work_struct *work)
{
loff_t off = 0;
ssize_t ret = 0;
struct file *fp = NULL;
u32 magic;
u32 version;
KWORKER_INSTALL_KEYRING();
2023-06-03 00:00:56 +08:00
#ifdef CONFIG_KSU_DEBUG
// always allow adb shell by default
ksu_grant_root_to_shell();
#endif
// load allowlist now!
fp = filp_open(KERNEL_SU_ALLOWLIST, O_RDONLY, 0);
if (IS_ERR(fp)) {
2023-05-22 10:39:54 +08:00
pr_err("load_allow_list open file failed: %ld\n", PTR_ERR(fp));
return;
}
// verify magic
2023-06-03 00:00:56 +08:00
if (ksu_kernel_read_compat(fp, &magic, sizeof(magic), &off) !=
sizeof(magic) ||
magic != FILE_MAGIC) {
pr_err("allowlist file invalid: %d!\n", magic);
goto exit;
}
if (ksu_kernel_read_compat(fp, &version, sizeof(version), &off) !=
sizeof(version)) {
pr_err("allowlist read version: %d failed\n", version);
goto exit;
}
pr_info("allowlist version: %d\n", version);
while (true) {
2023-06-03 00:00:56 +08:00
struct app_profile profile;
ret = ksu_kernel_read_compat(fp, &profile, sizeof(profile),
&off);
if (ret <= 0) {
2023-05-22 10:39:54 +08:00
pr_info("load_allow_list read err: %zd\n", ret);
break;
}
2023-06-03 00:00:56 +08:00
pr_info("load_allow_uid, name: %s, uid: %d, allow: %d\n",
profile.key, profile.current_uid, profile.allow_su);
ksu_set_app_profile(&profile, false);
}
2022-12-09 22:03:03 +08:00
exit:
ksu_show_allow_list();
filp_close(fp, 0);
2022-12-09 22:03:03 +08:00
}
void ksu_prune_allowlist(bool (*is_uid_exist)(uid_t, void *), void *data)
{
struct perm_data *np = NULL;
struct perm_data *n = NULL;
bool modified = false;
// TODO: use RCU!
mutex_lock(&allowlist_mutex);
list_for_each_entry_safe (np, n, &allow_list, list) {
2023-06-03 00:00:56 +08:00
uid_t uid = np->profile.current_uid;
if (!is_uid_exist(uid, data)) {
modified = true;
pr_info("prune uid: %d\n", uid);
list_del(&np->list);
kfree(np);
}
}
mutex_unlock(&allowlist_mutex);
if (modified) {
persistent_allow_list();
}
}
2022-12-09 22:03:03 +08:00
// make sure allow list works cross boot
bool persistent_allow_list(void)
{
return ksu_queue_work(&ksu_save_work);
2022-12-09 22:03:03 +08:00
}
bool ksu_load_allow_list(void)
{
return ksu_queue_work(&ksu_load_work);
}
void ksu_allowlist_init(void)
{
INIT_LIST_HEAD(&allow_list);
2022-12-09 22:03:03 +08:00
2023-06-03 00:00:56 +08:00
INIT_WORK(&ksu_save_work, do_save_allow_list);
INIT_WORK(&ksu_load_work, do_load_allow_list);
2023-06-03 00:00:56 +08:00
2023-06-03 10:18:11 +08:00
init_default_profiles();
2022-12-09 22:03:03 +08:00
}
void ksu_allowlist_exit(void)
{
struct perm_data *np = NULL;
struct perm_data *n = NULL;
2023-06-03 00:00:56 +08:00
do_save_allow_list(NULL);
// free allowlist
mutex_lock(&allowlist_mutex);
list_for_each_entry_safe (np, n, &allow_list, list) {
list_del(&np->list);
kfree(np);
}
mutex_unlock(&allowlist_mutex);
2022-12-09 22:03:03 +08:00
}