2023-01-25 21:53:19 +08:00
|
|
|
#include "linux/delay.h"
|
|
|
|
#include "linux/fs.h"
|
|
|
|
#include "linux/kernel.h"
|
|
|
|
#include "linux/list.h"
|
2023-01-26 08:55:27 +08:00
|
|
|
#include "linux/printk.h"
|
2023-01-25 21:53:19 +08:00
|
|
|
#include "linux/slab.h"
|
2023-02-01 19:48:36 +08:00
|
|
|
#include "linux/version.h"
|
2023-01-25 22:24:00 +08:00
|
|
|
#include "klog.h" // IWYU pragma: keep
|
2023-01-26 11:29:02 +08:00
|
|
|
#include "selinux/selinux.h"
|
2023-02-01 19:48:36 +08:00
|
|
|
#include "kernel_compat.h"
|
2023-01-26 11:29:02 +08:00
|
|
|
|
2022-12-12 11:17:51 +07:00
|
|
|
#define FILE_MAGIC 0x7f4b5355 // ' KSU', u32
|
|
|
|
#define FILE_FORMAT_VERSION 1 // u32
|
2022-12-09 22:03:03 +08:00
|
|
|
|
2023-01-17 12:44:22 +07:00
|
|
|
static DEFINE_MUTEX(allowlist_mutex);
|
|
|
|
|
2022-12-09 22:03:03 +08:00
|
|
|
struct perm_data {
|
2022-12-27 18:21:10 +07:00
|
|
|
struct list_head list;
|
|
|
|
uid_t uid;
|
|
|
|
bool allow;
|
2022-12-09 22:03:03 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct list_head allow_list;
|
|
|
|
|
2023-02-01 05:58:58 -04:00
|
|
|
#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
|
|
|
|
2023-01-26 11:29:02 +08:00
|
|
|
void ksu_show_allow_list(void)
|
|
|
|
{
|
2023-01-26 08:55:27 +08:00
|
|
|
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);
|
|
|
|
pr_info("uid :%d, allow: %d\n", p->uid, p->allow);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ksu_allow_uid(uid_t uid, bool allow, bool persist)
|
2022-12-27 18:21:10 +07:00
|
|
|
{
|
|
|
|
// find the node first!
|
|
|
|
struct perm_data *p = NULL;
|
|
|
|
struct list_head *pos = NULL;
|
|
|
|
bool result = false;
|
|
|
|
list_for_each (pos, &allow_list) {
|
|
|
|
p = list_entry(pos, struct perm_data, list);
|
|
|
|
if (uid == p->uid) {
|
|
|
|
p->allow = allow;
|
|
|
|
result = true;
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// not found, alloc a new node!
|
|
|
|
p = (struct perm_data *)kmalloc(sizeof(struct perm_data), GFP_KERNEL);
|
|
|
|
if (!p) {
|
|
|
|
pr_err("alloc allow node failed.\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
p->uid = uid;
|
|
|
|
p->allow = allow;
|
|
|
|
|
2023-04-18 13:19:28 +08:00
|
|
|
pr_info("allow_uid: %d, allow: %d", uid, allow);
|
|
|
|
|
2022-12-27 18:21:10 +07:00
|
|
|
list_add_tail(&p->list, &allow_list);
|
|
|
|
result = true;
|
2022-12-09 22:03:03 +08:00
|
|
|
|
|
|
|
exit:
|
2023-01-26 08:55:27 +08:00
|
|
|
if (persist)
|
|
|
|
persistent_allow_list();
|
2022-12-09 22:03:03 +08:00
|
|
|
|
2022-12-27 18:21:10 +07:00
|
|
|
return result;
|
2022-12-09 22:03:03 +08:00
|
|
|
}
|
|
|
|
|
2022-12-27 18:21:10 +07: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);
|
|
|
|
if (uid == p->uid) {
|
|
|
|
return p->allow;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2022-12-09 22:03:03 +08:00
|
|
|
}
|
|
|
|
|
2022-12-27 18:21:10 +07: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);
|
2023-04-18 13:19:28 +08:00
|
|
|
// pr_info("get_allow_list uid: %d allow: %d\n", p->uid, p->allow);
|
2022-12-27 18:21:10 +07:00
|
|
|
if (p->allow == allow) {
|
|
|
|
array[i++] = p->uid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*length = i;
|
|
|
|
|
|
|
|
return true;
|
2022-12-09 22:03:03 +08:00
|
|
|
}
|
|
|
|
|
2022-12-27 18:21:10 +07:00
|
|
|
void do_persistent_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;
|
2023-02-05 07:14:59 +08:00
|
|
|
KWORKER_INSTALL_KEYRING();
|
2022-12-27 18:21:10 +07:00
|
|
|
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));
|
2022-12-27 18:21:10 +07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// store magic and version
|
2023-02-20 18:51:55 +07:00
|
|
|
if (ksu_kernel_write_compat(fp, &magic, sizeof(magic), &off) != sizeof(magic)) {
|
2022-12-27 18:21:10 +07:00
|
|
|
pr_err("save_allow_list write magic failed.\n");
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:51:55 +07:00
|
|
|
if (ksu_kernel_write_compat(fp, &version, sizeof(version), &off) !=
|
2023-01-17 12:44:22 +07:00
|
|
|
sizeof(version)) {
|
2022-12-27 18:21:10 +07:00
|
|
|
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);
|
|
|
|
pr_info("save allow list uid :%d, allow: %d\n", p->uid,
|
|
|
|
p->allow);
|
2023-02-20 18:51:55 +07:00
|
|
|
ksu_kernel_write_compat(fp, &p->uid, sizeof(p->uid), &off);
|
|
|
|
ksu_kernel_write_compat(fp, &p->allow, sizeof(p->allow), &off);
|
2022-12-27 18:21:10 +07:00
|
|
|
}
|
2022-12-09 22:03:03 +08:00
|
|
|
|
2022-12-12 11:17:51 +07:00
|
|
|
exit:
|
2022-12-27 18:21:10 +07:00
|
|
|
filp_close(fp, 0);
|
2022-12-11 21:59:57 +07:00
|
|
|
}
|
2022-12-09 22:03:03 +08:00
|
|
|
|
2022-12-27 18:21:10 +07: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;
|
2023-02-05 07:14:59 +08:00
|
|
|
KWORKER_INSTALL_KEYRING();
|
2022-12-27 18:21:10 +07:00
|
|
|
|
|
|
|
// load allowlist now!
|
|
|
|
fp = filp_open(KERNEL_SU_ALLOWLIST, O_RDONLY, 0);
|
|
|
|
|
|
|
|
if (IS_ERR(fp)) {
|
2023-01-14 21:45:34 +08:00
|
|
|
#ifdef CONFIG_KSU_DEBUG
|
|
|
|
int errno = PTR_ERR(fp);
|
|
|
|
if (errno == -ENOENT) {
|
2023-01-26 11:29:02 +08:00
|
|
|
ksu_allow_uid(2000, true,
|
|
|
|
true); // allow adb shell by default
|
2023-01-14 21:45:34 +08:00
|
|
|
} else {
|
2023-05-22 10:39:54 +08:00
|
|
|
pr_err("load_allow_list open file failed: %ld\n",
|
2023-01-17 12:44:22 +07:00
|
|
|
PTR_ERR(fp));
|
2023-01-14 21:45:34 +08:00
|
|
|
}
|
|
|
|
#else
|
2023-05-22 10:39:54 +08:00
|
|
|
pr_err("load_allow_list open file failed: %ld\n", PTR_ERR(fp));
|
2023-01-14 21:45:34 +08:00
|
|
|
#endif
|
2022-12-27 18:21:10 +07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// verify magic
|
2023-02-20 18:51:55 +07:00
|
|
|
if (ksu_kernel_read_compat(fp, &magic, sizeof(magic), &off) != sizeof(magic) ||
|
2023-01-17 12:44:22 +07:00
|
|
|
magic != FILE_MAGIC) {
|
2022-12-27 18:21:10 +07:00
|
|
|
pr_err("allowlist file invalid: %d!\n", magic);
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:51:55 +07:00
|
|
|
if (ksu_kernel_read_compat(fp, &version, sizeof(version), &off) !=
|
2023-01-17 12:44:22 +07:00
|
|
|
sizeof(version)) {
|
2022-12-27 18:21:10 +07:00
|
|
|
pr_err("allowlist read version: %d failed\n", version);
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_info("allowlist version: %d\n", version);
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
u32 uid;
|
|
|
|
bool allow = false;
|
2023-02-20 18:51:55 +07:00
|
|
|
ret = ksu_kernel_read_compat(fp, &uid, sizeof(uid), &off);
|
2022-12-27 18:21:10 +07:00
|
|
|
if (ret <= 0) {
|
2023-05-22 10:39:54 +08:00
|
|
|
pr_info("load_allow_list read err: %zd\n", ret);
|
2022-12-27 18:21:10 +07:00
|
|
|
break;
|
|
|
|
}
|
2023-02-20 18:51:55 +07:00
|
|
|
ret = ksu_kernel_read_compat(fp, &allow, sizeof(allow), &off);
|
2022-12-27 18:21:10 +07:00
|
|
|
|
|
|
|
pr_info("load_allow_uid: %d, allow: %d\n", uid, allow);
|
|
|
|
|
2023-01-26 08:55:27 +08:00
|
|
|
ksu_allow_uid(uid, allow, false);
|
2022-12-27 18:21:10 +07:00
|
|
|
}
|
2022-12-09 22:03:03 +08:00
|
|
|
|
2022-12-12 11:17:51 +07:00
|
|
|
exit:
|
2023-01-26 08:55:27 +08:00
|
|
|
ksu_show_allow_list();
|
2022-12-27 18:21:10 +07:00
|
|
|
filp_close(fp, 0);
|
2022-12-09 22:03:03 +08:00
|
|
|
}
|
|
|
|
|
2023-01-17 13:49:30 +07:00
|
|
|
void ksu_prune_allowlist(bool (*is_uid_exist)(uid_t, void *), void *data)
|
2023-01-17 12:44:22 +07:00
|
|
|
{
|
|
|
|
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) {
|
|
|
|
uid_t uid = np->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
|
2022-12-27 18:21:10 +07:00
|
|
|
bool persistent_allow_list(void)
|
|
|
|
{
|
2023-01-25 21:53:19 +08:00
|
|
|
return ksu_queue_work(&ksu_save_work);
|
2022-12-09 22:03:03 +08:00
|
|
|
}
|
|
|
|
|
2022-12-27 18:21:10 +07:00
|
|
|
bool ksu_load_allow_list(void)
|
|
|
|
{
|
2023-01-25 21:53:19 +08:00
|
|
|
return ksu_queue_work(&ksu_load_work);
|
2022-12-15 16:06:07 +07:00
|
|
|
}
|
|
|
|
|
2023-01-25 21:53:19 +08:00
|
|
|
void ksu_allowlist_init(void)
|
2022-12-27 18:21:10 +07:00
|
|
|
{
|
|
|
|
INIT_LIST_HEAD(&allow_list);
|
2022-12-09 22:03:03 +08:00
|
|
|
|
2023-01-25 21:53:19 +08:00
|
|
|
INIT_WORK(&ksu_save_work, do_persistent_allow_list);
|
|
|
|
INIT_WORK(&ksu_load_work, do_load_allow_list);
|
2022-12-09 22:03:03 +08:00
|
|
|
}
|
|
|
|
|
2023-01-25 21:53:19 +08:00
|
|
|
void ksu_allowlist_exit(void)
|
2022-12-27 18:21:10 +07:00
|
|
|
{
|
2023-01-25 21:53:19 +08:00
|
|
|
struct perm_data *np = NULL;
|
|
|
|
struct perm_data *n = NULL;
|
|
|
|
|
|
|
|
do_persistent_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
|
|
|
}
|