From 342910771b5cfe07ae819582c329def96f694bfe Mon Sep 17 00:00:00 2001 From: weishu Date: Tue, 27 Dec 2022 17:43:58 +0700 Subject: [PATCH] kernel: support xperms for sepolicy --- kernel/selinux/rules.c | 101 ++++++++++++++------------ kernel/selinux/sepolicy.c | 146 +++++++++++++++++++++++++++++++++++--- kernel/selinux/sepolicy.h | 4 +- 3 files changed, 195 insertions(+), 56 deletions(-) diff --git a/kernel/selinux/rules.c b/kernel/selinux/rules.c index 67587da1..bdb80a2b 100644 --- a/kernel/selinux/rules.c +++ b/kernel/selinux/rules.c @@ -6,60 +6,69 @@ void apply_kernelsu_rules() { - struct selinux_policy *policy; - struct policydb *db; + struct selinux_policy *policy; + struct policydb *db; - if (!getenforce()) { - pr_info("SELinux permissive or disabled, don't apply rules."); - return; - } + if (!getenforce()) { + pr_info("SELinux permissive or disabled, don't apply rules."); + return; + } - rcu_read_lock(); - policy = rcu_dereference(selinux_state.policy); - db = &policy->policydb; + rcu_read_lock(); + policy = rcu_dereference(selinux_state.policy); + db = &policy->policydb; - permissive(db, KERNEL_SU_DOMAIN); - typeattribute(db, KERNEL_SU_DOMAIN, "mlstrustedsubject"); - typeattribute(db, KERNEL_SU_DOMAIN, "netdomain"); - typeattribute(db, KERNEL_SU_DOMAIN, "bluetoothdomain"); + permissive(db, KERNEL_SU_DOMAIN); + typeattribute(db, KERNEL_SU_DOMAIN, "mlstrustedsubject"); + typeattribute(db, KERNEL_SU_DOMAIN, "netdomain"); + typeattribute(db, KERNEL_SU_DOMAIN, "bluetoothdomain"); - // allow all! - allow(db, KERNEL_SU_DOMAIN, ALL, ALL, ALL); + // allow all! + allow(db, KERNEL_SU_DOMAIN, ALL, ALL, ALL); + + // allow us do any ioctl + if (db->policyvers >= POLICYDB_VERSION_XPERMS_IOCTL) { + allowxperm(db, KERNEL_SU_DOMAIN, ALL, "blk_file", ALL); + allowxperm(db, KERNEL_SU_DOMAIN, ALL, "fifo_file", ALL); + allowxperm(db, KERNEL_SU_DOMAIN, ALL, "chr_file", ALL); + } + + // we need to save allowlist in /data/adb + allow(db, "kernel", "adb_data_file", "dir", ALL); + allow(db, "kernel", "adb_data_file", "file", ALL); + // we may need to do mount on shell + allow(db, "kernel", "shell_data_file", "file", ALL); - // we need to save allowlist in /data/adb - allow(db, "kernel", "adb_data_file", "dir", ALL); - allow(db, "kernel", "adb_data_file", "file", ALL); + // copied from Magisk rules + // suRights + allow(db, "servicemanager", KERNEL_SU_DOMAIN, "dir", "search"); + allow(db, "servicemanager", KERNEL_SU_DOMAIN, "dir", "read"); + allow(db, "servicemanager", KERNEL_SU_DOMAIN, "file", "open"); + allow(db, "servicemanager", KERNEL_SU_DOMAIN, "file", "read"); + allow(db, "servicemanager", KERNEL_SU_DOMAIN, "process", "getattr"); + allow(db, ALL, KERNEL_SU_DOMAIN, "process", "sigchld"); - // copied from Magisk rules - // suRights - allow(db, "servicemanager", KERNEL_SU_DOMAIN, "dir", "search"); - allow(db, "servicemanager", KERNEL_SU_DOMAIN, "dir", "read"); - allow(db, "servicemanager", KERNEL_SU_DOMAIN, "file", "open"); - allow(db, "servicemanager", KERNEL_SU_DOMAIN, "file", "read"); - allow(db, "servicemanager", KERNEL_SU_DOMAIN, "process", "getattr"); - allow(db, ALL, KERNEL_SU_DOMAIN, "process", "sigchld"); + // allowLog + allow(db, "logd", KERNEL_SU_DOMAIN, "dir", "search"); + allow(db, "logd", KERNEL_SU_DOMAIN, "file", "read"); + allow(db, "logd", KERNEL_SU_DOMAIN, "file", "open"); + allow(db, "logd", KERNEL_SU_DOMAIN, "file", "getattr"); - // allowLog - allow(db, "logd", KERNEL_SU_DOMAIN, "dir", "search"); - allow(db, "logd", KERNEL_SU_DOMAIN, "file", "read"); - allow(db, "logd", KERNEL_SU_DOMAIN, "file", "open"); - allow(db, "logd", KERNEL_SU_DOMAIN, "file", "getattr"); + // dumpsys + allow(db, ALL, KERNEL_SU_DOMAIN, "fd", "use"); + allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "write"); + allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "read"); + allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "open"); + allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "getattr"); - // dumpsys - allow(db, ALL, KERNEL_SU_DOMAIN, "fd", "use"); - allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "write"); - allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "read"); - allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "open"); - allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "getattr"); + // bootctl + allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "dir", "search"); + allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "file", "read"); + allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "file", "open"); + allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "process", "getattr"); - // bootctl - allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "dir", "search"); - allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "file", "read"); - allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "file", "open"); - allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "process", "getattr"); + // Allow all binder transactions + allow(db, ALL, KERNEL_SU_DOMAIN, "binder", ALL); - // Allow all binder transactions - allow(db, ALL, KERNEL_SU_DOMAIN, "binder", ALL); - - rcu_read_unlock(); + rcu_read_unlock(); } \ No newline at end of file diff --git a/kernel/selinux/sepolicy.c b/kernel/selinux/sepolicy.c index afdb9fcc..6682d347 100644 --- a/kernel/selinux/sepolicy.c +++ b/kernel/selinux/sepolicy.c @@ -1,4 +1,5 @@ #include "sepolicy.h" +#include "../klog.h" // Invert is adding rules for auditdeny; in other cases, invert is removing rules #define strip_av(effect, invert) ((effect == AVTAB_AUDITDENY) == !invert) @@ -52,7 +53,11 @@ struct avtab_node* get_avtab_node(struct policydb* db, struct avtab_key *key, st * AUDITDENY, aka DONTAUDIT, are &= assigned, versus |= for * others. Initialize the data accordingly. */ - avdatum.u.data = key->specified == AVTAB_AUDITDENY ? ~0U : 0U; + if (key->specified & AVTAB_XPERMS) { + avdatum.u.xperms = xperms; + } else { + avdatum.u.data = key->specified == AVTAB_AUDITDENY ? ~0U : 0U; + } /* this is used to get the node - insertion is actually unique */ node = avtab_insert_nonunique(&db->te_avtab, key, &avdatum); @@ -174,11 +179,136 @@ void add_rule_raw(struct policydb* db, struct type_datum *src, struct type_datum } } -void add_xperm_rule_raw(struct type_datum *src, struct type_datum *tgt, - struct class_datum *cls, uint16_t low, uint16_t high, int effect, bool invert) { +#define ioctl_driver(x) (x>>8 & 0xFF) +#define ioctl_func(x) (x & 0xFF) + +#define xperm_test(x, p) (1 & (p[x >> 5] >> (x & 0x1f))) +#define xperm_set(x, p) (p[x >> 5] |= (1 << (x & 0x1f))) +#define xperm_clear(x, p) (p[x >> 5] &= ~(1 << (x & 0x1f))) + +void add_xperm_rule_raw(struct policydb* db, struct type_datum *src, struct type_datum *tgt, + struct class_datum *cls, uint16_t low, uint16_t high, int effect, bool invert) { + + if (src == NULL) { + struct hashtab_node* node; + hashtab_for_each(db->p_types.table, node) { + struct type_datum* type = (struct type_datum*)(node->datum); + if (type->attribute) { + add_xperm_rule_raw(db, type, tgt, cls, low, high, effect, invert); + } + }; + } else if (tgt == NULL) { + struct hashtab_node* node; + hashtab_for_each(db->p_types.table, node) { + struct type_datum* type = (struct type_datum*)(node->datum); + if (type->attribute) { + add_xperm_rule_raw(db, src, type, cls, low, high, effect, invert); + } + }; + } else if (cls == NULL) { + struct hashtab_node* node; + hashtab_for_each(db->p_classes.table, node) { + add_xperm_rule_raw(db, src, tgt, (struct class_datum*)(node->datum), low, high, effect, invert); + }; + } else { + struct avtab_key key; + key.source_type = src->value; + key.target_type = tgt->value; + key.target_class = cls->value; + key.specified = effect; + + struct avtab_datum *datum; + struct avtab_node *node; + struct avtab_extended_perms xperms; + + memset(&xperms, 0, sizeof(xperms)); + if (ioctl_driver(low) != ioctl_driver(high)) { + xperms.specified = AVTAB_XPERMS_IOCTLDRIVER; + xperms.driver = 0; + } else { + xperms.specified = AVTAB_XPERMS_IOCTLFUNCTION; + xperms.driver = ioctl_driver(low); + } + + if (xperms.specified == AVTAB_XPERMS_IOCTLDRIVER) { + for (int i = ioctl_driver(low); i <= ioctl_driver(high); ++i) { + if (invert) + xperm_clear(i, xperms.perms.p); + else + xperm_set(i, xperms.perms.p); + } + } else { + for (int i = ioctl_func(low); i <= ioctl_func(high); ++i) { + if (invert) + xperm_clear(i, xperms.perms.p); + else + xperm_set(i, xperms.perms.p); + } + } + + node = get_avtab_node(db, &key, &xperms); + if (!node) { + pr_warn("add_xperm_rule_raw cannot found node!\n"); + return; + } + datum = &node->datum; + + if (datum->u.xperms == NULL) { + datum->u.xperms = (struct avtab_extended_perms*)(kmalloc(sizeof(xperms), GFP_KERNEL)); + if (!datum->u.xperms) { + pr_err("alloc xperms failed\n"); + return; + } + memcpy(datum->u.xperms, &xperms, sizeof(xperms)); + } + + } } -bool add_xperm_rule(const char *s, const char *t, const char *c, const char *range, int effect, bool invert) { - return false; + +bool add_xperm_rule(struct policydb* db, const char *s, const char *t, const char *c, const char *range, int effect, bool invert) { + struct type_datum *src = NULL, *tgt = NULL; + struct class_datum *cls = NULL; + + if (s) { + src = symtab_search(&db->p_types, s); + if (src == NULL) { + pr_info("source type %s does not exist\n", s); + return false; + } + } + + if (t) { + tgt = symtab_search(&db->p_types, t); + if (tgt == NULL) { + pr_info("target type %s does not exist\n", t); + return false; + } + } + + if (c) { + cls = symtab_search(&db->p_classes, c); + if (cls == NULL) { + pr_info("class %s does not exist\n", c); + return false; + } + } + + u16 low, high; + + if (range) { + if (strchr(range, '-')){ + sscanf(range, "%hx-%hx", &low, &high); + } else { + sscanf(range, "%hx", &low); + high = low; + } + } else { + low = 0; + high = 0xFFFF; + } + + add_xperm_rule_raw(db, src, tgt, cls, low, high, effect, invert); + return true; } bool add_type_rule(struct policydb* db, const char *s, const char *t, const char *c, const char *d, int effect) { @@ -338,15 +468,15 @@ bool dontaudit(struct policydb* db, const char* src, const char* tgt, const char // Extended permissions access vector rules bool allowxperm(struct policydb* db, const char* src, const char* tgt, const char* cls, const char* range) { - return add_xperm_rule(src, tgt, cls, range, AVTAB_XPERMS_ALLOWED, false); + return add_xperm_rule(db, src, tgt, cls, range, AVTAB_XPERMS_ALLOWED, false); } bool auditallowxperm(struct policydb* db, const char* src, const char* tgt, const char* cls, const char* range) { - return add_xperm_rule(src, tgt, cls, range, AVTAB_XPERMS_AUDITALLOW, false); + return add_xperm_rule(db, src, tgt, cls, range, AVTAB_XPERMS_AUDITALLOW, false); } bool dontauditxperm(struct policydb* db, const char* src, const char* tgt, const char* cls, const char* range) { - return add_xperm_rule(src, tgt, cls, range, AVTAB_XPERMS_DONTAUDIT, false); + return add_xperm_rule(db, src, tgt, cls, range, AVTAB_XPERMS_DONTAUDIT, false); } // Type rules diff --git a/kernel/selinux/sepolicy.h b/kernel/selinux/sepolicy.h index 2a269a7b..133f8235 100644 --- a/kernel/selinux/sepolicy.h +++ b/kernel/selinux/sepolicy.h @@ -42,9 +42,9 @@ struct avtab_node* get_avtab_node(struct policydb* db, struct avtab_key *key, st bool add_rule(struct policydb* db, const char *s, const char *t, const char *c, const char *p, int effect, bool invert); void add_rule_raw(struct policydb* db, struct type_datum *src, struct type_datum *tgt, struct class_datum *cls, struct perm_datum *perm, int effect, bool invert); -void add_xperm_rule_raw(struct type_datum *src, struct type_datum *tgt, +void add_xperm_rule_raw(struct policydb* db, struct type_datum *src, struct type_datum *tgt, struct class_datum *cls, uint16_t low, uint16_t high, int effect, bool invert); -bool add_xperm_rule(const char *s, const char *t, const char *c, const char *range, int effect, bool invert); +bool add_xperm_rule(struct policydb* db, const char *s, const char *t, const char *c, const char *range, int effect, bool invert); bool add_type_rule(struct policydb* db, const char *s, const char *t, const char *c, const char *d, int effect);