diff --git a/native/jni/include/magiskpolicy.hpp b/native/jni/include/magiskpolicy.hpp index 9413b2b29..2fa341a5a 100644 --- a/native/jni/include/magiskpolicy.hpp +++ b/native/jni/include/magiskpolicy.hpp @@ -3,38 +3,55 @@ #include #include -#define ALL NULL +#define ALL nullptr -// policydb functions -int load_policydb(const char *file); -int load_split_cil(); -int compile_split_cil(); -int dump_policydb(const char *file); -void destroy_policydb(); +struct policydb; -// Handy functions -int sepol_allow(const char *s, const char *t, const char *c, const char *p); -int sepol_deny(const char *s, const char *t, const char *c, const char *p); -int sepol_auditallow(const char *s, const char *t, const char *c, const char *p); -int sepol_dontaudit(const char *s, const char *t, const char *c, const char *p); -int sepol_typetrans(const char *s, const char *t, const char *c, const char *d); -int sepol_typechange(const char *s, const char *t, const char *c, const char *d); -int sepol_typemember(const char *s, const char *t, const char *c, const char *d); -int sepol_nametrans(const char *s, const char *t, const char *c, const char *d, const char *o); -int sepol_allowxperm(const char *s, const char *t, const char *c, const char *range); -int sepol_auditallowxperm(const char *s, const char *t, const char *c, const char *range); -int sepol_dontauditxperm(const char *s, const char *t, const char *c, const char *range); -int sepol_create(const char *s); -int sepol_permissive(const char *s); -int sepol_enforce(const char *s); -int sepol_attradd(const char *s, const char *a); -int sepol_genfscon(const char *name, const char *path, const char *context); -int sepol_exists(const char *source); +class sepolicy { +public: + typedef const char * c_str; + ~sepolicy(); -// Built in rules -void sepol_magisk_rules(); + // Public static factory functions + static sepolicy *from_file(c_str file); + static sepolicy *from_split(); + static sepolicy *compile_split(); -// Statement parsing -void parse_statement(const char *statement); -void load_rule_file(const char *file); -void statement_help(); + // External APIs + int to_file(c_str file); + void parse_statement(c_str stmt); + void load_rule_file(c_str file); + + // Operation on types + int create(c_str type); + int permissive(c_str type); + int enforce(c_str type); + int typeattribute(c_str type, c_str attr); + int exists(c_str type); + + // Access vector rules + int allow(c_str src, c_str tgt, c_str cls, c_str perm); + int deny(c_str src, c_str tgt, c_str cls, c_str perm); + int auditallow(c_str src, c_str tgt, c_str cls, c_str perm); + int dontaudit(c_str src, c_str tgt, c_str cls, c_str perm); + + // Extended permissions access vector rules + int allowxperm(c_str src, c_str tgt, c_str cls, c_str range); + int auditallowxperm(c_str src, c_str tgt, c_str cls, c_str range); + int dontauditxperm(c_str src, c_str tgt, c_str cls, c_str range); + + // Type rules + int type_transition(c_str src, c_str tgt, c_str cls, c_str def, c_str obj = nullptr); + int type_change(c_str src, c_str tgt, c_str cls, c_str def); + int type_member(c_str src, c_str tgt, c_str cls, c_str def); + + // File system labeling + int genfscon(c_str fs_name, c_str path, c_str ctx); + + // Magisk + void magisk_rules(); + void allow_su_client(c_str type); + +private: + policydb *db; +}; diff --git a/native/jni/init/rootdir.cpp b/native/jni/init/rootdir.cpp index 4db563ac7..0144f09d0 100644 --- a/native/jni/init/rootdir.cpp +++ b/native/jni/init/rootdir.cpp @@ -129,13 +129,14 @@ void RootFSInit::setup_rootfs() { bool MagiskInit::patch_sepolicy(const char *file) { bool patch_init = false; + sepolicy *sepol = nullptr; if (access(SPLIT_PLAT_CIL, R_OK) == 0) { LOGD("sepol: split policy\n"); patch_init = true; } else if (access("/sepolicy", R_OK) == 0) { LOGD("sepol: monolithic policy\n"); - load_policydb("/sepolicy"); + sepol = sepolicy::from_file("/sepolicy"); } else { LOGD("sepol: no selinux\n"); return false; @@ -148,10 +149,10 @@ bool MagiskInit::patch_sepolicy(const char *file) { } if (patch_init) - load_split_cil(); + sepol = sepolicy::from_split(); - sepol_magisk_rules(); - sepol_allow(SEPOL_PROC_DOMAIN, ALL, ALL, ALL); + sepol->magisk_rules(); + sepol->allow(SEPOL_PROC_DOMAIN, ALL, ALL, ALL); // Custom rules if (auto dir = open_dir(persist_dir.data()); dir) { @@ -159,13 +160,13 @@ bool MagiskInit::patch_sepolicy(const char *file) { auto rule = persist_dir + "/" + entry->d_name + "/sepolicy.rule"; if (access(rule.data(), R_OK) == 0) { LOGD("Loading custom sepolicy patch: %s\n", rule.data()); - load_rule_file(rule.data()); + sepol->load_rule_file(rule.data()); } } } - dump_policydb(file); - destroy_policydb(); + sepol->to_file(file); + delete sepol; // Remove OnePlus stupid debug sepolicy and use our own if (access("/sepolicy_debug", F_OK) == 0) { diff --git a/native/jni/magiskpolicy/api.cpp b/native/jni/magiskpolicy/api.cpp index 5faf555db..7e2240dc0 100644 --- a/native/jni/magiskpolicy/api.cpp +++ b/native/jni/magiskpolicy/api.cpp @@ -5,86 +5,86 @@ //#define vprint(fmt, ...) printf(fmt, __VA_ARGS__) #define vprint(...) -int sepol_allow(const char *s, const char *t, const char *c, const char *p) { +int sepolicy::allow(const char *s, const char *t, const char *c, const char *p) { vprint("allow %s %s %s %s\n", s, t, c, p); - return add_rule(s, t, c, p, AVTAB_ALLOWED, 0); + return add_rule(db, s, t, c, p, AVTAB_ALLOWED, 0); } -int sepol_deny(const char *s, const char *t, const char *c, const char *p) { +int sepolicy::deny(const char *s, const char *t, const char *c, const char *p) { vprint("deny %s %s %s %s\n", s, t, c, p); - return add_rule(s, t, c, p, AVTAB_ALLOWED, 1); + return add_rule(db, s, t, c, p, AVTAB_ALLOWED, 1); } -int sepol_auditallow(const char *s, const char *t, const char *c, const char *p) { +int sepolicy::auditallow(const char *s, const char *t, const char *c, const char *p) { vprint("auditallow %s %s %s %s\n", s, t, c, p); - return add_rule(s, t, c, p, AVTAB_AUDITALLOW, 0); + return add_rule(db, s, t, c, p, AVTAB_AUDITALLOW, 0); } -int sepol_dontaudit(const char *s, const char *t, const char *c, const char *p) { +int sepolicy::dontaudit(const char *s, const char *t, const char *c, const char *p) { vprint("dontaudit %s %s %s %s\n", s, t, c, p); - return add_rule(s, t, c, p, AVTAB_AUDITDENY, 1); + return add_rule(db, s, t, c, p, AVTAB_AUDITDENY, 1); } -int sepol_allowxperm(const char *s, const char *t, const char *c, const char *range) { +int sepolicy::allowxperm(const char *s, const char *t, const char *c, const char *range) { vprint("allowxperm %s %s %s %s\n", s, t, c, range); - return add_xperm_rule(s, t, c, range, AVTAB_XPERMS_ALLOWED, 0); + return add_xperm_rule(db, s, t, c, range, AVTAB_XPERMS_ALLOWED, 0); } -int sepol_auditallowxperm(const char *s, const char *t, const char *c, const char *range) { +int sepolicy::auditallowxperm(const char *s, const char *t, const char *c, const char *range) { vprint("auditallowxperm %s %s %s %s\n", s, t, c, range); - return add_xperm_rule(s, t, c, range, AVTAB_XPERMS_AUDITALLOW, 0); + return add_xperm_rule(db, s, t, c, range, AVTAB_XPERMS_AUDITALLOW, 0); } -int sepol_dontauditxperm(const char *s, const char *t, const char *c, const char *range) { +int sepolicy::dontauditxperm(const char *s, const char *t, const char *c, const char *range) { vprint("dontauditxperm %s %s %s %s\n", s, t, c, range); - return add_xperm_rule(s, t, c, range, AVTAB_XPERMS_DONTAUDIT, 0); + return add_xperm_rule(db, s, t, c, range, AVTAB_XPERMS_DONTAUDIT, 0); } -int sepol_typetrans(const char *s, const char *t, const char *c, const char *d) { - vprint("type_transition %s %s %s %s\n", s, t, c, d); - return add_type_rule(s, t, c, d, AVTAB_TRANSITION); -} - -int sepol_typechange(const char *s, const char *t, const char *c, const char *d) { +int sepolicy::type_change(const char *s, const char *t, const char *c, const char *d) { vprint("type_change %s %s %s %s\n", s, t, c, d); - return add_type_rule(s, t, c, d, AVTAB_CHANGE); + return add_type_rule(db, s, t, c, d, AVTAB_CHANGE); } -int sepol_typemember(const char *s, const char *t, const char *c, const char *d) { +int sepolicy::type_member(const char *s, const char *t, const char *c, const char *d) { vprint("type_member %s %s %s %s\n", s, t, c, d); - return add_type_rule(s, t, c, d, AVTAB_MEMBER); + return add_type_rule(db, s, t, c, d, AVTAB_MEMBER); } -int sepol_nametrans(const char *s, const char *t, const char *c, const char *d, const char *o) { - vprint("name_trans %s %s %s %s %s\n", s, t, c, d, o); - return add_filename_trans(s, t, c, d, o); +int sepolicy::type_transition(const char *src, const char *tgt, const char *cls, const char *def, const char *obj) { + if (obj) { + vprint("type_transition %s %s %s %s\n", src, tgt, cls, def); + return add_type_rule(db, src, tgt, cls, def, AVTAB_TRANSITION); + } else { + vprint("type_transition %s %s %s %s %s\n", src, tgt, cls, def, obj); + return add_filename_trans(db, src, tgt, cls, def, obj); + } } -int sepol_permissive(const char *s) { +int sepolicy::permissive(const char *s) { vprint("permissive %s\n", s); - return set_domain_state(s, 1); + return set_domain_state(db, s, 1); } -int sepol_enforce(const char *s) { +int sepolicy::enforce(const char *s) { vprint("enforce %s\n", s); - return set_domain_state(s, 0); + return set_domain_state(db, s, 0); } -int sepol_create(const char *s) { +int sepolicy::create(const char *s) { vprint("create %s\n", s); - return create_domain(s); + return create_domain(db, s); } -int sepol_attradd(const char *s, const char *a) { - vprint("attradd %s %s\n", s, a); - return add_typeattribute(s, a); +int sepolicy::typeattribute(const char *type, const char *attr) { + vprint("typeattribute %s %s\n", type, attr); + return add_typeattribute(db, type, attr); } -int sepol_genfscon(const char *name, const char *path, const char *context) { - vprint("genfscon %s %s %s\n", name, path, context); - return add_genfscon(name, path, context); +int sepolicy::genfscon(const char *fs_name, const char *path, const char *ctx) { + vprint("genfscon %s %s %s\n", fs_name, path, ctx); + return add_genfscon(db, fs_name, path, ctx); } -int sepol_exists(const char *source) { - return hashtab_search(magisk_policydb->p_types.table, source) != nullptr; +int sepolicy::exists(const char *source) { + return hashtab_search(db->p_types.table, source) != nullptr; } diff --git a/native/jni/magiskpolicy/magiskpolicy.cpp b/native/jni/magiskpolicy/magiskpolicy.cpp index e9be0b011..baa59e32f 100644 --- a/native/jni/magiskpolicy/magiskpolicy.cpp +++ b/native/jni/magiskpolicy/magiskpolicy.cpp @@ -40,6 +40,7 @@ int magiskpolicy_main(int argc, char *argv[]) { cmdline_logging(); const char *out_file = nullptr; const char *rule_file = nullptr; + sepolicy *sepol = nullptr; bool magisk = false; bool live = false; @@ -56,18 +57,21 @@ int magiskpolicy_main(int argc, char *argv[]) { else if (option == "load"sv) { if (argv[i + 1] == nullptr) usage(argv[0]); - if (load_policydb(argv[i + 1])) { + sepol = sepolicy::from_file(argv[i + 1]); + if (!sepol) { fprintf(stderr, "Cannot load policy from %s\n", argv[i + 1]); return 1; } ++i; } else if (option == "load-split"sv) { - if (load_split_cil()) { + sepol = sepolicy::from_split(); + if (!sepol) { fprintf(stderr, "Cannot load split cil\n"); return 1; } } else if (option == "compile-split"sv) { - if (compile_split_cil()) { + sepol = sepolicy::compile_split(); + if (!sepol) { fprintf(stderr, "Cannot compile split cil\n"); return 1; } @@ -92,30 +96,30 @@ int magiskpolicy_main(int argc, char *argv[]) { } // Use current policy if nothing is loaded - if (magisk_policydb == nullptr && load_policydb(SELINUX_POLICY)) { + if (sepol == nullptr && !(sepol = sepolicy::from_file(SELINUX_POLICY))) { fprintf(stderr, "Cannot load policy from " SELINUX_POLICY "\n"); return 1; } if (magisk) - sepol_magisk_rules(); + sepol->magisk_rules(); if (rule_file) - load_rule_file(rule_file); + sepol->load_rule_file(rule_file); for (; i < argc; ++i) - parse_statement(argv[i]); + sepol->parse_statement(argv[i]); - if (live && dump_policydb(SELINUX_LOAD)) { + if (live && sepol->to_file(SELINUX_LOAD)) { fprintf(stderr, "Cannot apply policy\n"); return 1; } - if (out_file && dump_policydb(out_file)) { + if (out_file && sepol->to_file(out_file)) { fprintf(stderr, "Cannot dump policy to %s\n", out_file); return 1; } - destroy_policydb(); + delete sepol; return 0; } diff --git a/native/jni/magiskpolicy/policydb.cpp b/native/jni/magiskpolicy/policydb.cpp index ffd3f1a38..e6652cd82 100644 --- a/native/jni/magiskpolicy/policydb.cpp +++ b/native/jni/magiskpolicy/policydb.cpp @@ -12,26 +12,6 @@ #include "sepolicy.h" -int load_policydb(const char *file) { - LOGD("Load policy from: %s\n", file); - if (magisk_policydb) - destroy_policydb(); - - struct policy_file pf; - policy_file_init(&pf); - pf.fp = xfopen(file, "re"); - pf.type = PF_USE_STDIO; - - magisk_policydb = static_cast(xmalloc(sizeof(policydb_t))); - if (policydb_init(magisk_policydb) || policydb_read(magisk_policydb, &pf, 0)) { - LOGE("Fail to load policy from %s\n", file); - return 1; - } - - fclose(pf.fp); - return 0; -} - #define SHALEN 64 static bool cmp_sha256(const char *a, const char *b) { char id_a[SHALEN] = {0}; @@ -94,17 +74,6 @@ static bool check_precompiled(const char *precompiled) { return ok; } -int load_split_cil() { - const char *odm_pre = ODM_POLICY_DIR "precompiled_sepolicy"; - const char *vend_pre = VEND_POLICY_DIR "precompiled_sepolicy"; - if (access(odm_pre, R_OK) == 0 && check_precompiled(odm_pre)) - return load_policydb(odm_pre); - else if (access(vend_pre, R_OK) == 0 && check_precompiled(vend_pre)) - return load_policydb(vend_pre); - else - return compile_split_cil(); -} - static void load_cil(struct cil_db *db, const char *file) { char *addr; size_t size; @@ -114,15 +83,37 @@ static void load_cil(struct cil_db *db, const char *file) { munmap(addr, size); } -int compile_split_cil() { +sepolicy *sepolicy::from_file(const char *file) { + LOGD("Load policy from: %s\n", file); + + policy_file_t pf; + policy_file_init(&pf); + auto fp = xopen_file(file, "re"); + pf.fp = fp.get(); + pf.type = PF_USE_STDIO; + + auto db = static_cast(xmalloc(sizeof(policydb_t))); + if (policydb_init(db) || policydb_read(db, &pf, 0)) { + LOGE("Fail to load policy from %s\n", file); + free(db); + return nullptr; + } + + auto sepol = new sepolicy(); + sepol->db = db; + return sepol; +} + +sepolicy *sepolicy::compile_split() { char path[128], plat_ver[10]; - struct cil_db *db = nullptr; + cil_db_t *db = nullptr; sepol_policydb_t *pdb = nullptr; FILE *f; int policy_ver; const char *cil_file; cil_db_init(&db); + run_finally fin([db_ptr = &db]{ cil_db_destroy(db_ptr); }); cil_set_mls(db, 1); cil_set_multiple_decls(db, 1); cil_set_disable_neverallow(db, 1); @@ -173,29 +164,48 @@ int compile_split_cil() { load_cil(db, cil_file); if (cil_compile(db)) - return 1; + return nullptr; if (cil_build_policydb(db, &pdb)) - return 1; + return nullptr; - cil_db_destroy(&db); - magisk_policydb = &pdb->p; - return 0; + auto sepol = new sepolicy(); + sepol->db = &pdb->p; + return sepol; } -int dump_policydb(const char *file) { +sepolicy *sepolicy::from_split() { + const char *odm_pre = ODM_POLICY_DIR "precompiled_sepolicy"; + const char *vend_pre = VEND_POLICY_DIR "precompiled_sepolicy"; + if (access(odm_pre, R_OK) == 0 && check_precompiled(odm_pre)) + return sepolicy::from_file(odm_pre); + else if (access(vend_pre, R_OK) == 0 && check_precompiled(vend_pre)) + return sepolicy::from_file(vend_pre); + else + return sepolicy::compile_split(); +} + +sepolicy::~sepolicy() { + policydb_destroy(db); + free(db); +} + +int sepolicy::to_file(const char *file) { uint8_t *data; size_t len; - { - auto fp = make_stream_fp(data, len); - struct policy_file pf; - policy_file_init(&pf); - pf.type = PF_USE_STDIO; - pf.fp = fp.get(); - if (policydb_write(magisk_policydb, &pf)) { - LOGE("Fail to create policy image\n"); - return 1; - } + /* No partial writes are allowed to /sys/fs/selinux/load, thus the reason why we + * first dump everything into memory, then directly call write system call */ + + auto fp = make_stream_fp(data, len); + run_finally fin([=]{ free(data); }); + + policy_file_t pf; + policy_file_init(&pf); + pf.type = PF_USE_STDIO; + pf.fp = fp.get(); + if (policydb_write(db, &pf)) { + LOGE("Fail to create policy image\n"); + return 1; } int fd = xopen(file, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644); @@ -204,14 +214,5 @@ int dump_policydb(const char *file) { xwrite(fd, data, len); close(fd); - free(data); return 0; } - -void destroy_policydb() { - if (magisk_policydb) { - policydb_destroy(magisk_policydb); - free(magisk_policydb); - magisk_policydb = nullptr; - } -} diff --git a/native/jni/magiskpolicy/rules.cpp b/native/jni/magiskpolicy/rules.cpp index 6b5613490..f9196b51a 100644 --- a/native/jni/magiskpolicy/rules.cpp +++ b/native/jni/magiskpolicy/rules.cpp @@ -4,202 +4,202 @@ #include "sepolicy.h" -static void allowSuClient(const char *target) { - if (!sepol_exists(target)) +void sepolicy::allow_su_client(const char *type) { + if (!exists(type)) return; - sepol_allow(target, SEPOL_PROC_DOMAIN, "unix_stream_socket", "connectto"); - sepol_allow(target, SEPOL_PROC_DOMAIN, "unix_stream_socket", "getopt"); - sepol_allow(SEPOL_PROC_DOMAIN, target, "fd", "use"); - sepol_allow(SEPOL_PROC_DOMAIN, target, "fifo_file", ALL); + allow(type, SEPOL_PROC_DOMAIN, "unix_stream_socket", "connectto"); + allow(type, SEPOL_PROC_DOMAIN, "unix_stream_socket", "getopt"); + allow(SEPOL_PROC_DOMAIN, type, "fd", "use"); + allow(SEPOL_PROC_DOMAIN, type, "fifo_file", ALL); // Allow binder service - sepol_allow(target, SEPOL_PROC_DOMAIN, "binder", "call"); - sepol_allow(target, SEPOL_PROC_DOMAIN, "binder", "transfer"); + allow(type, SEPOL_PROC_DOMAIN, "binder", "call"); + allow(type, SEPOL_PROC_DOMAIN, "binder", "transfer"); // Allow termios ioctl - sepol_allow(target, "devpts", "chr_file", "ioctl"); - sepol_allow(target, "untrusted_app_devpts", "chr_file", "ioctl"); - sepol_allow(target, "untrusted_app_25_devpts", "chr_file", "ioctl"); - sepol_allow(target, "untrusted_app_all_devpts", "chr_file", "ioctl"); - if (magisk_policydb->policyvers >= POLICYDB_VERSION_XPERMS_IOCTL) { - sepol_allowxperm(target, "devpts", "chr_file", "0x5400-0x54FF"); - sepol_allowxperm(target, "untrusted_app_devpts", "chr_file", "0x5400-0x54FF"); - sepol_allowxperm(target, "untrusted_app_25_devpts", "chr_file", "0x5400-0x54FF"); - sepol_allowxperm(target, "untrusted_app_all_devpts", "chr_file", "0x5400-0x54FF"); + allow(type, "devpts", "chr_file", "ioctl"); + allow(type, "untrusted_app_devpts", "chr_file", "ioctl"); + allow(type, "untrusted_app_25_devpts", "chr_file", "ioctl"); + allow(type, "untrusted_app_all_devpts", "chr_file", "ioctl"); + if (db->policyvers >= POLICYDB_VERSION_XPERMS_IOCTL) { + allowxperm(type, "devpts", "chr_file", "0x5400-0x54FF"); + allowxperm(type, "untrusted_app_devpts", "chr_file", "0x5400-0x54FF"); + allowxperm(type, "untrusted_app_25_devpts", "chr_file", "0x5400-0x54FF"); + allowxperm(type, "untrusted_app_all_devpts", "chr_file", "0x5400-0x54FF"); } } -void sepol_magisk_rules() { +void sepolicy::magisk_rules() { // Temp suppress warnings auto bak = log_cb.w; log_cb.w = nop_log; // First prevent anything to change sepolicy except ourselves - sepol_deny(ALL, "kernel", "security", "load_policy"); + deny(ALL, "kernel", "security", "load_policy"); - if (!sepol_exists(SEPOL_PROC_DOMAIN)) - sepol_create(SEPOL_PROC_DOMAIN); - if (!sepol_exists(SEPOL_FILE_DOMAIN)) - sepol_create(SEPOL_FILE_DOMAIN); - sepol_permissive(SEPOL_PROC_DOMAIN); + if (!exists(SEPOL_PROC_DOMAIN)) + create(SEPOL_PROC_DOMAIN); + if (!exists(SEPOL_FILE_DOMAIN)) + create(SEPOL_FILE_DOMAIN); + permissive(SEPOL_PROC_DOMAIN); - sepol_attradd(SEPOL_PROC_DOMAIN, "mlstrustedsubject"); - sepol_attradd(SEPOL_PROC_DOMAIN, "netdomain"); - sepol_attradd(SEPOL_PROC_DOMAIN, "bluetoothdomain"); - sepol_attradd(SEPOL_FILE_DOMAIN, "mlstrustedobject"); + typeattribute(SEPOL_PROC_DOMAIN, "mlstrustedsubject"); + typeattribute(SEPOL_PROC_DOMAIN, "netdomain"); + typeattribute(SEPOL_PROC_DOMAIN, "bluetoothdomain"); + typeattribute(SEPOL_FILE_DOMAIN, "mlstrustedobject"); // Let everyone access tmpfs files (for SAR sbin overlay) - sepol_allow(ALL, "tmpfs", "file", ALL); + allow(ALL, "tmpfs", "file", ALL); // For normal rootfs file/directory operations when rw (for SAR / overlay) - sepol_allow("rootfs", "labeledfs", "filesystem", "associate"); + allow("rootfs", "labeledfs", "filesystem", "associate"); // Let init transit to SEPOL_PROC_DOMAIN - sepol_allow("kernel", "kernel", "process", "setcurrent"); - sepol_allow("kernel", SEPOL_PROC_DOMAIN, "process", "dyntransition"); + allow("kernel", "kernel", "process", "setcurrent"); + allow("kernel", SEPOL_PROC_DOMAIN, "process", "dyntransition"); // Let init run stuffs - sepol_allow("kernel", SEPOL_PROC_DOMAIN, "fd", "use"); - sepol_allow("init", SEPOL_PROC_DOMAIN, "process", ALL); - sepol_allow("init", "tmpfs", "file", "getattr"); - sepol_allow("init", "tmpfs", "file", "execute"); + allow("kernel", SEPOL_PROC_DOMAIN, "fd", "use"); + allow("init", SEPOL_PROC_DOMAIN, "process", ALL); + allow("init", "tmpfs", "file", "getattr"); + allow("init", "tmpfs", "file", "execute"); // Shell, properties, logs - if (sepol_exists("default_prop")) - sepol_allow(SEPOL_PROC_DOMAIN, "default_prop", "property_service", "set"); - sepol_allow(SEPOL_PROC_DOMAIN, "init", "unix_stream_socket", "connectto"); - sepol_allow(SEPOL_PROC_DOMAIN, "rootfs", "filesystem", "remount"); - if (sepol_exists("logd")) - sepol_allow(SEPOL_PROC_DOMAIN, "logd", "unix_stream_socket", "connectto"); - sepol_allow(SEPOL_PROC_DOMAIN, SEPOL_PROC_DOMAIN, ALL, ALL); + if (exists("default_prop")) + allow(SEPOL_PROC_DOMAIN, "default_prop", "property_service", "set"); + allow(SEPOL_PROC_DOMAIN, "init", "unix_stream_socket", "connectto"); + allow(SEPOL_PROC_DOMAIN, "rootfs", "filesystem", "remount"); + if (exists("logd")) + allow(SEPOL_PROC_DOMAIN, "logd", "unix_stream_socket", "connectto"); + allow(SEPOL_PROC_DOMAIN, SEPOL_PROC_DOMAIN, ALL, ALL); // For sepolicy live patching - sepol_allow(SEPOL_PROC_DOMAIN, "kernel", "security", "read_policy"); - sepol_allow(SEPOL_PROC_DOMAIN, "kernel", "security", "load_policy"); + allow(SEPOL_PROC_DOMAIN, "kernel", "security", "read_policy"); + allow(SEPOL_PROC_DOMAIN, "kernel", "security", "load_policy"); // Allow these processes to access MagiskSU - allowSuClient("init"); - allowSuClient("shell"); - allowSuClient("system_app"); - allowSuClient("priv_app"); - allowSuClient("platform_app"); - allowSuClient("untrusted_app"); - allowSuClient("untrusted_app_25"); - allowSuClient("untrusted_app_27"); - allowSuClient("untrusted_app_29"); - allowSuClient("update_engine"); + allow_su_client("init"); + allow_su_client("shell"); + allow_su_client("system_app"); + allow_su_client("priv_app"); + allow_su_client("platform_app"); + allow_su_client("untrusted_app"); + allow_su_client("untrusted_app_25"); + allow_su_client("untrusted_app_27"); + allow_su_client("untrusted_app_29"); + allow_su_client("update_engine"); // suRights - sepol_allow("servicemanager", SEPOL_PROC_DOMAIN, "dir", "search"); - sepol_allow("servicemanager", SEPOL_PROC_DOMAIN, "dir", "read"); - sepol_allow("servicemanager", SEPOL_PROC_DOMAIN, "file", "open"); - sepol_allow("servicemanager", SEPOL_PROC_DOMAIN, "file", "read"); - sepol_allow("servicemanager", SEPOL_PROC_DOMAIN, "process", "getattr"); - sepol_allow("servicemanager", SEPOL_PROC_DOMAIN, "binder", "transfer"); - sepol_allow(SEPOL_PROC_DOMAIN, "servicemanager", "dir", "search"); - sepol_allow(SEPOL_PROC_DOMAIN, "servicemanager", "dir", "read"); - sepol_allow(SEPOL_PROC_DOMAIN, "servicemanager", "file", "open"); - sepol_allow(SEPOL_PROC_DOMAIN, "servicemanager", "file", "read"); - sepol_allow(SEPOL_PROC_DOMAIN, "servicemanager", "process", "getattr"); - sepol_allow(SEPOL_PROC_DOMAIN, "servicemanager", "binder", "transfer"); - sepol_allow(SEPOL_PROC_DOMAIN, "servicemanager", "binder", "call"); - sepol_allow(ALL, SEPOL_PROC_DOMAIN, "process", "sigchld"); + allow("servicemanager", SEPOL_PROC_DOMAIN, "dir", "search"); + allow("servicemanager", SEPOL_PROC_DOMAIN, "dir", "read"); + allow("servicemanager", SEPOL_PROC_DOMAIN, "file", "open"); + allow("servicemanager", SEPOL_PROC_DOMAIN, "file", "read"); + allow("servicemanager", SEPOL_PROC_DOMAIN, "process", "getattr"); + allow("servicemanager", SEPOL_PROC_DOMAIN, "binder", "transfer"); + allow(SEPOL_PROC_DOMAIN, "servicemanager", "dir", "search"); + allow(SEPOL_PROC_DOMAIN, "servicemanager", "dir", "read"); + allow(SEPOL_PROC_DOMAIN, "servicemanager", "file", "open"); + allow(SEPOL_PROC_DOMAIN, "servicemanager", "file", "read"); + allow(SEPOL_PROC_DOMAIN, "servicemanager", "process", "getattr"); + allow(SEPOL_PROC_DOMAIN, "servicemanager", "binder", "transfer"); + allow(SEPOL_PROC_DOMAIN, "servicemanager", "binder", "call"); + allow(ALL, SEPOL_PROC_DOMAIN, "process", "sigchld"); // allowLog - sepol_allow("logd", SEPOL_PROC_DOMAIN, "dir", "search"); - sepol_allow("logd", SEPOL_PROC_DOMAIN, "file", "read"); - sepol_allow("logd", SEPOL_PROC_DOMAIN, "file", "open"); - sepol_allow("logd", SEPOL_PROC_DOMAIN, "file", "getattr"); + allow("logd", SEPOL_PROC_DOMAIN, "dir", "search"); + allow("logd", SEPOL_PROC_DOMAIN, "file", "read"); + allow("logd", SEPOL_PROC_DOMAIN, "file", "open"); + allow("logd", SEPOL_PROC_DOMAIN, "file", "getattr"); // suBackL0 - sepol_allow("system_server", SEPOL_PROC_DOMAIN, "binder", "call"); - sepol_allow("system_server", SEPOL_PROC_DOMAIN, "binder", "transfer"); - sepol_allow(SEPOL_PROC_DOMAIN, "system_server", "binder", "call"); - sepol_allow(SEPOL_PROC_DOMAIN, "system_server", "binder", "transfer"); + allow("system_server", SEPOL_PROC_DOMAIN, "binder", "call"); + allow("system_server", SEPOL_PROC_DOMAIN, "binder", "transfer"); + allow(SEPOL_PROC_DOMAIN, "system_server", "binder", "call"); + allow(SEPOL_PROC_DOMAIN, "system_server", "binder", "transfer"); // suBackL6 - sepol_allow("surfaceflinger", "app_data_file", "dir", ALL); - sepol_allow("surfaceflinger", "app_data_file", "file", ALL); - sepol_allow("surfaceflinger", "app_data_file", "lnk_file", ALL); - sepol_attradd("surfaceflinger", "mlstrustedsubject"); + allow("surfaceflinger", "app_data_file", "dir", ALL); + allow("surfaceflinger", "app_data_file", "file", ALL); + allow("surfaceflinger", "app_data_file", "lnk_file", ALL); + typeattribute("surfaceflinger", "mlstrustedsubject"); // suMiscL6 - if (sepol_exists("audioserver")) - sepol_allow("audioserver", "audioserver", "process", "execmem"); + if (exists("audioserver")) + allow("audioserver", "audioserver", "process", "execmem"); // Liveboot - sepol_allow("surfaceflinger", SEPOL_PROC_DOMAIN, "process", "ptrace"); - sepol_allow("surfaceflinger", SEPOL_PROC_DOMAIN, "binder", "transfer"); - sepol_allow("surfaceflinger", SEPOL_PROC_DOMAIN, "binder", "call"); - sepol_allow("surfaceflinger", SEPOL_PROC_DOMAIN, "fd", "use"); - sepol_allow("debuggerd", SEPOL_PROC_DOMAIN, "process", "ptrace"); + allow("surfaceflinger", SEPOL_PROC_DOMAIN, "process", "ptrace"); + allow("surfaceflinger", SEPOL_PROC_DOMAIN, "binder", "transfer"); + allow("surfaceflinger", SEPOL_PROC_DOMAIN, "binder", "call"); + allow("surfaceflinger", SEPOL_PROC_DOMAIN, "fd", "use"); + allow("debuggerd", SEPOL_PROC_DOMAIN, "process", "ptrace"); // dumpsys - sepol_allow(ALL, SEPOL_PROC_DOMAIN, "fd", "use"); - sepol_allow(ALL, SEPOL_PROC_DOMAIN, "fifo_file", "write"); - sepol_allow(ALL, SEPOL_PROC_DOMAIN, "fifo_file", "read"); - sepol_allow(ALL, SEPOL_PROC_DOMAIN, "fifo_file", "open"); - sepol_allow(ALL, SEPOL_PROC_DOMAIN, "fifo_file", "getattr"); + allow(ALL, SEPOL_PROC_DOMAIN, "fd", "use"); + allow(ALL, SEPOL_PROC_DOMAIN, "fifo_file", "write"); + allow(ALL, SEPOL_PROC_DOMAIN, "fifo_file", "read"); + allow(ALL, SEPOL_PROC_DOMAIN, "fifo_file", "open"); + allow(ALL, SEPOL_PROC_DOMAIN, "fifo_file", "getattr"); // bootctl - sepol_allow("hwservicemanager", SEPOL_PROC_DOMAIN, "dir", "search"); - sepol_allow("hwservicemanager", SEPOL_PROC_DOMAIN, "file", "read"); - sepol_allow("hwservicemanager", SEPOL_PROC_DOMAIN, "file", "open"); - sepol_allow("hwservicemanager", SEPOL_PROC_DOMAIN, "process", "getattr"); - sepol_allow("hwservicemanager", SEPOL_PROC_DOMAIN, "binder", "transfer"); + allow("hwservicemanager", SEPOL_PROC_DOMAIN, "dir", "search"); + allow("hwservicemanager", SEPOL_PROC_DOMAIN, "file", "read"); + allow("hwservicemanager", SEPOL_PROC_DOMAIN, "file", "open"); + allow("hwservicemanager", SEPOL_PROC_DOMAIN, "process", "getattr"); + allow("hwservicemanager", SEPOL_PROC_DOMAIN, "binder", "transfer"); // For mounting loop devices, mirrors, tmpfs - sepol_allow(SEPOL_PROC_DOMAIN, "kernel", "process", "setsched"); - sepol_allow(SEPOL_PROC_DOMAIN, "labeledfs", "filesystem", "mount"); - sepol_allow(SEPOL_PROC_DOMAIN, "labeledfs", "filesystem", "unmount"); - sepol_allow(SEPOL_PROC_DOMAIN, "tmpfs", "filesystem", "mount"); - sepol_allow(SEPOL_PROC_DOMAIN, "tmpfs", "filesystem", "unmount"); - sepol_allow("kernel", ALL, "file", "read"); - sepol_allow("kernel", ALL, "file", "write"); + allow(SEPOL_PROC_DOMAIN, "kernel", "process", "setsched"); + allow(SEPOL_PROC_DOMAIN, "labeledfs", "filesystem", "mount"); + allow(SEPOL_PROC_DOMAIN, "labeledfs", "filesystem", "unmount"); + allow(SEPOL_PROC_DOMAIN, "tmpfs", "filesystem", "mount"); + allow(SEPOL_PROC_DOMAIN, "tmpfs", "filesystem", "unmount"); + allow("kernel", ALL, "file", "read"); + allow("kernel", ALL, "file", "write"); // Allow us to do anything to any files/dir/links - sepol_allow(SEPOL_PROC_DOMAIN, ALL, "file", ALL); - sepol_allow(SEPOL_PROC_DOMAIN, ALL, "dir", ALL); - sepol_allow(SEPOL_PROC_DOMAIN, ALL, "lnk_file", ALL); - sepol_allow(SEPOL_PROC_DOMAIN, ALL, "blk_file", ALL); - sepol_allow(SEPOL_PROC_DOMAIN, ALL, "sock_file", ALL); - sepol_allow(SEPOL_PROC_DOMAIN, ALL, "chr_file", ALL); - sepol_allow(SEPOL_PROC_DOMAIN, ALL, "fifo_file", ALL); + allow(SEPOL_PROC_DOMAIN, ALL, "file", ALL); + allow(SEPOL_PROC_DOMAIN, ALL, "dir", ALL); + allow(SEPOL_PROC_DOMAIN, ALL, "lnk_file", ALL); + allow(SEPOL_PROC_DOMAIN, ALL, "blk_file", ALL); + allow(SEPOL_PROC_DOMAIN, ALL, "sock_file", ALL); + allow(SEPOL_PROC_DOMAIN, ALL, "chr_file", ALL); + allow(SEPOL_PROC_DOMAIN, ALL, "fifo_file", ALL); // Allow us to do any ioctl on all block devices - if (magisk_policydb->policyvers >= POLICYDB_VERSION_XPERMS_IOCTL) - sepol_allowxperm(SEPOL_PROC_DOMAIN, ALL, "blk_file", "0x0000-0xFFFF"); + if (db->policyvers >= POLICYDB_VERSION_XPERMS_IOCTL) + allowxperm(SEPOL_PROC_DOMAIN, ALL, "blk_file", "0x0000-0xFFFF"); // Allow all binder transactions - sepol_allow(ALL, SEPOL_PROC_DOMAIN, "binder", ALL); + allow(ALL, SEPOL_PROC_DOMAIN, "binder", ALL); // Super files - sepol_allow(ALL, SEPOL_FILE_DOMAIN, "file", ALL); - sepol_allow(ALL, SEPOL_FILE_DOMAIN, "dir", ALL); - sepol_allow(ALL, SEPOL_FILE_DOMAIN, "fifo_file", ALL); - sepol_allow(ALL, SEPOL_FILE_DOMAIN, "chr_file", ALL); - sepol_allow(SEPOL_FILE_DOMAIN, ALL, "filesystem", "associate"); + allow(ALL, SEPOL_FILE_DOMAIN, "file", ALL); + allow(ALL, SEPOL_FILE_DOMAIN, "dir", ALL); + allow(ALL, SEPOL_FILE_DOMAIN, "fifo_file", ALL); + allow(ALL, SEPOL_FILE_DOMAIN, "chr_file", ALL); + allow(SEPOL_FILE_DOMAIN, ALL, "filesystem", "associate"); // For changing attributes - sepol_allow("rootfs", "tmpfs", "filesystem", "associate"); + allow("rootfs", "tmpfs", "filesystem", "associate"); // Xposed - sepol_allow("untrusted_app", "untrusted_app", "capability", "setgid"); - sepol_allow("system_server", "dex2oat_exec", "file", ALL); + allow("untrusted_app", "untrusted_app", "capability", "setgid"); + allow("system_server", "dex2oat_exec", "file", ALL); // Support deodexed ROM on Oreo - sepol_allow("zygote", "dalvikcache_data_file", "file", "execute"); + allow("zygote", "dalvikcache_data_file", "file", "execute"); // Support deodexed ROM on Pie (Samsung) - sepol_allow("system_server", "dalvikcache_data_file", "file", "write"); - sepol_allow("system_server", "dalvikcache_data_file", "file", "execute"); + allow("system_server", "dalvikcache_data_file", "file", "write"); + allow("system_server", "dalvikcache_data_file", "file", "execute"); // Allow update_engine/addon.d-v2 to run permissive on all ROMs - sepol_permissive("update_engine"); + permissive("update_engine"); #if 0 // Remove all dontaudit in debug mode - strip_dontaudit(); + strip_dontaudit(db); #endif log_cb.w = bak; diff --git a/native/jni/magiskpolicy/sepolicy.c b/native/jni/magiskpolicy/sepolicy.c index a688b24aa..f0c44d9b9 100644 --- a/native/jni/magiskpolicy/sepolicy.c +++ b/native/jni/magiskpolicy/sepolicy.c @@ -5,9 +5,6 @@ #include "sepolicy.h" -policydb_t *magisk_policydb = NULL; -#define mpdb magisk_policydb - extern void *xmalloc(size_t size); extern void *xcalloc(size_t nmemb, size_t size); extern void *xrealloc(void *ptr, size_t size); @@ -39,20 +36,20 @@ hash_for_each(htable, size, hashtab, block) #define avtab_for_each(avtab, block) \ hash_for_each(htable, nslot, avtab, block) -static int set_attr(const char *type, int value) { - type_datum_t *attr = hashtab_search(mpdb->p_types.table, type); +static int set_attr(policydb_t *db, const char *type, int value) { + type_datum_t *attr = hashtab_search(db->p_types.table, type); if (!attr || attr->flavor != TYPE_ATTRIB) return -1; - if (ebitmap_set_bit(&mpdb->type_attr_map[value - 1], attr->s.value - 1, 1)) + if (ebitmap_set_bit(&db->type_attr_map[value - 1], attr->s.value - 1, 1)) return -1; - if (ebitmap_set_bit(&mpdb->attr_type_map[attr->s.value - 1], value - 1, 1)) + if (ebitmap_set_bit(&db->attr_type_map[attr->s.value - 1], value - 1, 1)) return -1; return attr->s.value; } -static void check_avtab_node(avtab_ptr_t node) { +static void check_avtab_node(policydb_t *db, avtab_ptr_t node) { int redundant = 0; if (node->key.specified == AVTAB_AUDITDENY) redundant = node->datum.data == ~0U; @@ -61,17 +58,17 @@ static void check_avtab_node(avtab_ptr_t node) { else redundant = node->datum.data == 0U; if (redundant) - avtab_remove_node(&mpdb->te_avtab, node); + avtab_remove_node(&db->te_avtab, node); } -static avtab_ptr_t get_avtab_node(avtab_key_t *key, avtab_extended_perms_t *xperms) { +static avtab_ptr_t get_avtab_node(policydb_t *db, avtab_key_t *key, avtab_extended_perms_t *xperms) { avtab_ptr_t node; avtab_datum_t avdatum; int match = 0; /* AVTAB_XPERMS entries are not necessarily unique */ if (key->specified & AVTAB_XPERMS) { - node = avtab_search_node(&mpdb->te_avtab, key); + node = avtab_search_node(&db->te_avtab, key); while (node) { if ((node->datum.xperms->specified == xperms->specified) && (node->datum.xperms->driver == xperms->driver)) { @@ -83,7 +80,7 @@ static avtab_ptr_t get_avtab_node(avtab_key_t *key, avtab_extended_perms_t *xper if (!match) node = NULL; } else { - node = avtab_search_node(&mpdb->te_avtab, key); + node = avtab_search_node(&db->te_avtab, key); } if (!node) { @@ -94,14 +91,14 @@ static avtab_ptr_t get_avtab_node(avtab_key_t *key, avtab_extended_perms_t *xper */ avdatum.data = key->specified == AVTAB_AUDITDENY ? ~0U : 0U; /* this is used to get the node - insertion is actually unique */ - node = avtab_insert_nonunique(&mpdb->te_avtab, key, &avdatum); + node = avtab_insert_nonunique(&db->te_avtab, key, &avdatum); } return node; } -static int add_avrule(avtab_key_t *key, int val, int not) { - avtab_ptr_t node = get_avtab_node(key, NULL); +static int add_avrule(policydb_t *db, avtab_key_t *key, int val, int not) { + avtab_ptr_t node = get_avtab_node(NULL, key, NULL); if (not) { if (val < 0) @@ -115,36 +112,36 @@ static int add_avrule(avtab_key_t *key, int val, int not) { node->datum.data |= 1U << (val - 1); } - check_avtab_node(node); + check_avtab_node(db, node); return 0; } -static int add_rule_auto(type_datum_t *src, type_datum_t *tgt, class_datum_t *cls, +static int add_rule_auto(policydb_t *db, type_datum_t *src, type_datum_t *tgt, class_datum_t *cls, perm_datum_t *perm, int effect, int not) { avtab_key_t key; int ret = 0; if (src == NULL) { - hashtab_for_each(mpdb->p_types.table, { + hashtab_for_each(db->p_types.table, { src = node->datum; - ret |= add_rule_auto(src, tgt, cls, perm, effect, not); + ret |= add_rule_auto(db, src, tgt, cls, perm, effect, not); }) } else if (tgt == NULL) { - hashtab_for_each(mpdb->p_types.table, { + hashtab_for_each(db->p_types.table, { tgt = node->datum; - ret |= add_rule_auto(src, tgt, cls, perm, effect, not); + ret |= add_rule_auto(db, src, tgt, cls, perm, effect, not); }) } else if (cls == NULL) { - hashtab_for_each(mpdb->p_classes.table, { + hashtab_for_each(db->p_classes.table, { cls = node->datum; - ret |= add_rule_auto(src, tgt, cls, perm, effect, not); + ret |= add_rule_auto(db, src, tgt, cls, perm, effect, not); }) } else { key.source_type = src->s.value; key.target_type = tgt->s.value; key.target_class = cls->s.value; key.specified = effect; - return add_avrule(&key, perm ? perm->s.value : -1, not); + return add_avrule(db, &key, perm ? perm->s.value : -1, not); } return ret; } @@ -152,7 +149,7 @@ static int add_rule_auto(type_datum_t *src, type_datum_t *tgt, class_datum_t *cl #define ioctl_driver(x) (x>>8 & 0xFF) #define ioctl_func(x) (x & 0xFF) -static int add_avxrule(avtab_key_t *key, uint16_t low, uint16_t high, int not) { +static int add_avxrule(policydb_t *db, avtab_key_t *key, uint16_t low, uint16_t high, int not) { avtab_datum_t *datum; avtab_extended_perms_t xperms; @@ -181,7 +178,7 @@ static int add_avxrule(avtab_key_t *key, uint16_t low, uint16_t high, int not) { } } - datum = &get_avtab_node(key, &xperms)->datum; + datum = &get_avtab_node(db, key, &xperms)->datum; if (datum->xperms == NULL) datum->xperms = xmalloc(sizeof(xperms)); @@ -190,38 +187,38 @@ static int add_avxrule(avtab_key_t *key, uint16_t low, uint16_t high, int not) { return 0; } -static int add_xperm_rule_auto(type_datum_t *src, type_datum_t *tgt, class_datum_t *cls, - uint16_t low, uint16_t high, int effect, int not) { +static int add_xperm_rule_auto(policydb_t *db, type_datum_t *src, type_datum_t *tgt, + class_datum_t *cls, uint16_t low, uint16_t high, int effect, int not) { avtab_key_t key; int ret = 0; if (src == NULL) { - hashtab_for_each(mpdb->p_types.table, { + hashtab_for_each(db->p_types.table, { src = node->datum; - ret |= add_xperm_rule_auto(src, tgt, cls, low, high, effect, not); + ret |= add_xperm_rule_auto(db, src, tgt, cls, low, high, effect, not); }) } else if (tgt == NULL) { - hashtab_for_each(mpdb->p_types.table, { + hashtab_for_each(db->p_types.table, { tgt = node->datum; - ret |= add_xperm_rule_auto(src, tgt, cls, low, high, effect, not); + ret |= add_xperm_rule_auto(db, src, tgt, cls, low, high, effect, not); }) } else if (cls == NULL) { - hashtab_for_each(mpdb->p_classes.table, { + hashtab_for_each(db->p_classes.table, { cls = node->datum; - ret |= add_xperm_rule_auto(src, tgt, cls, low, high, effect, not); + ret |= add_xperm_rule_auto(db, src, tgt, cls, low, high, effect, not); }) } else { key.source_type = src->s.value; key.target_type = tgt->s.value; key.target_class = cls->s.value; key.specified = effect; - return add_avxrule(&key, low, high, not); + return add_avxrule(db, &key, low, high, not); } return ret; } -int create_domain(const char *d) { - symtab_datum_t *src = hashtab_search(mpdb->p_types.table, d); +int create_domain(policydb_t *db, const char *d) { + symtab_datum_t *src = hashtab_search(db->p_types.table, d); if (src) { LOGW("Domain %s already exists\n", d); return 0; @@ -233,60 +230,60 @@ int create_domain(const char *d) { typedatum->flavor = TYPE_TYPE; uint32_t value = 0; - symtab_insert(mpdb, SYM_TYPES, strdup(d), typedatum, SCOPE_DECL, 1, &value); + symtab_insert(db, SYM_TYPES, strdup(d), typedatum, SCOPE_DECL, 1, &value); typedatum->s.value = value; - if (ebitmap_set_bit(&mpdb->global->branch_list->declared.scope[SYM_TYPES], value - 1, 1)) { + if (ebitmap_set_bit(&db->global->branch_list->declared.scope[SYM_TYPES], value - 1, 1)) { return 1; } - mpdb->type_attr_map = xrealloc(mpdb->type_attr_map, sizeof(ebitmap_t) * mpdb->p_types.nprim); - mpdb->attr_type_map = xrealloc(mpdb->attr_type_map, sizeof(ebitmap_t) * mpdb->p_types.nprim); - ebitmap_init(&mpdb->type_attr_map[value-1]); - ebitmap_init(&mpdb->attr_type_map[value-1]); - ebitmap_set_bit(&mpdb->type_attr_map[value-1], value-1, 1); + db->type_attr_map = xrealloc(db->type_attr_map, sizeof(ebitmap_t) * db->p_types.nprim); + db->attr_type_map = xrealloc(db->attr_type_map, sizeof(ebitmap_t) * db->p_types.nprim); + ebitmap_init(&db->type_attr_map[value-1]); + ebitmap_init(&db->attr_type_map[value-1]); + ebitmap_set_bit(&db->type_attr_map[value-1], value-1, 1); - src = hashtab_search(mpdb->p_types.table, d); - if(!src) + src = hashtab_search(db->p_types.table, d); + if (!src) return 1; - if(policydb_index_decls(NULL, mpdb)) + if (policydb_index_decls(NULL, db)) return 1; - if(policydb_index_classes(mpdb)) + if (policydb_index_classes(db)) return 1; - if(policydb_index_others(NULL, mpdb, 0)) + if (policydb_index_others(NULL, db, 0)) return 1; - //Add the domain to all roles - for(unsigned i = 0; i < mpdb->p_roles.nprim; ++i) { - //Not sure all those three calls are needed - ebitmap_set_bit(&mpdb->role_val_to_struct[i]->types.negset, value - 1, 0); - ebitmap_set_bit(&mpdb->role_val_to_struct[i]->types.types, value - 1, 1); - type_set_expand(&mpdb->role_val_to_struct[i]->types, &mpdb->role_val_to_struct[i]->cache, mpdb, 0); + // Add the domain to all roles + for (unsigned i = 0; i < db->p_roles.nprim; ++i) { + // Not sure all those three calls are needed + ebitmap_set_bit(&db->role_val_to_struct[i]->types.negset, value - 1, 0); + ebitmap_set_bit(&db->role_val_to_struct[i]->types.types, value - 1, 1); + type_set_expand(&db->role_val_to_struct[i]->types, &db->role_val_to_struct[i]->cache, db, 0); } - return set_attr("domain", value); + return set_attr(db, "domain", value); } -int set_domain_state(const char *s, int state) { +int set_domain_state(policydb_t *db, const char *s, int state) { type_datum_t *type; if (s == NULL) { - hashtab_for_each(mpdb->p_types.table, { + hashtab_for_each(db->p_types.table, { type = node->datum; - if (ebitmap_set_bit(&mpdb->permissive_map, type->s.value, state)) { + if (ebitmap_set_bit(&db->permissive_map, type->s.value, state)) { LOGW("Could not set bit in permissive map\n"); return 1; } }) } else { - type = hashtab_search(mpdb->p_types.table, s); + type = hashtab_search(db->p_types.table, s); if (type == NULL) { LOGW("type %s does not exist\n", s); return 1; } - if (ebitmap_set_bit(&mpdb->permissive_map, type->s.value, state)) { + if (ebitmap_set_bit(&db->permissive_map, type->s.value, state)) { LOGW("Could not set bit in permissive map\n"); return 1; } @@ -295,26 +292,27 @@ int set_domain_state(const char *s, int state) { return 0; } -int add_filename_trans(const char *s, const char *t, const char *c, const char *d, const char *o) { +int add_filename_trans(policydb_t *db, const char *s, const char *t, const char *c, const char *d, + const char *o) { type_datum_t *src, *tgt, *def; class_datum_t *cls; - src = hashtab_search(mpdb->p_types.table, s); + src = hashtab_search(db->p_types.table, s); if (src == NULL) { LOGW("source type %s does not exist\n", s); return 1; } - tgt = hashtab_search(mpdb->p_types.table, t); + tgt = hashtab_search(db->p_types.table, t); if (tgt == NULL) { LOGW("target type %s does not exist\n", t); return 1; } - cls = hashtab_search(mpdb->p_classes.table, c); + cls = hashtab_search(db->p_classes.table, c); if (cls == NULL) { LOGW("class %s does not exist\n", c); return 1; } - def = hashtab_search(mpdb->p_types.table, d); + def = hashtab_search(db->p_types.table, d); if (def == NULL) { LOGW("default type %s does not exist\n", d); return 1; @@ -327,11 +325,11 @@ int add_filename_trans(const char *s, const char *t, const char *c, const char * trans_key.name = (char *) o; filename_trans_datum_t *trans_datum; - trans_datum = hashtab_search(mpdb->filename_trans, (hashtab_key_t) &trans_key); + trans_datum = hashtab_search(db->filename_trans, (hashtab_key_t) &trans_key); if (trans_datum == NULL) { trans_datum = xcalloc(sizeof(*trans_datum), 1); - hashtab_insert(mpdb->filename_trans, (hashtab_key_t) &trans_key, trans_datum); + hashtab_insert(db->filename_trans, (hashtab_key_t) &trans_key, trans_datum); } // Overwrite existing @@ -339,18 +337,18 @@ int add_filename_trans(const char *s, const char *t, const char *c, const char * return 0; } -int add_typeattribute(const char *type, const char *attr) { - type_datum_t *domain = hashtab_search(mpdb->p_types.table, type); +int add_typeattribute(policydb_t *db, const char *type, const char *attr) { + type_datum_t *domain = hashtab_search(db->p_types.table, type); if (domain == NULL) { LOGW("type %s does not exist\n", type); return 1; } - int attr_id = set_attr(attr, domain->s.value); + int attr_id = set_attr(db, attr, domain->s.value); if (attr_id < 0) return 1; - hashtab_for_each(mpdb->p_classes.table, { + hashtab_for_each(db->p_classes.table, { class_datum_t *cls = node->datum; for (constraint_node_t *n = cls->constraints; n ; n = n->next) { for (constraint_expr_t *e = n->expr; e; e = e->next) { @@ -365,13 +363,14 @@ int add_typeattribute(const char *type, const char *attr) { return 0; } -int add_rule(const char *s, const char *t, const char *c, const char *p, int effect, int n) { +int add_rule(policydb_t *db, + const char *s, const char *t, const char *c, const char *p, int effect, int n) { type_datum_t *src = NULL, *tgt = NULL; class_datum_t *cls = NULL; perm_datum_t *perm = NULL; if (s) { - src = hashtab_search(mpdb->p_types.table, s); + src = hashtab_search(db->p_types.table, s); if (src == NULL) { LOGW("source type %s does not exist\n", s); return 1; @@ -379,7 +378,7 @@ int add_rule(const char *s, const char *t, const char *c, const char *p, int eff } if (t) { - tgt = hashtab_search(mpdb->p_types.table, t); + tgt = hashtab_search(db->p_types.table, t); if (tgt == NULL) { LOGW("target type %s does not exist\n", t); return 1; @@ -387,7 +386,7 @@ int add_rule(const char *s, const char *t, const char *c, const char *p, int eff } if (c) { - cls = hashtab_search(mpdb->p_classes.table, c); + cls = hashtab_search(db->p_classes.table, c); if (cls == NULL) { LOGW("class %s does not exist\n", c); return 1; @@ -409,16 +408,16 @@ int add_rule(const char *s, const char *t, const char *c, const char *p, int eff return 1; } } - return add_rule_auto(src, tgt, cls, perm, effect, n); + return add_rule_auto(db, src, tgt, cls, perm, effect, n); } -int add_xperm_rule(const char *s, const char *t, const char *c, const char *range, int effect, - int n) { +int add_xperm_rule(policydb_t *db, const char *s, const char *t, const char *c, const char *range, + int effect, int n) { type_datum_t *src = NULL, *tgt = NULL; class_datum_t *cls = NULL; if (s) { - src = hashtab_search(mpdb->p_types.table, s); + src = hashtab_search(db->p_types.table, s); if (src == NULL) { LOGW("source type %s does not exist\n", s); return 1; @@ -426,7 +425,7 @@ int add_xperm_rule(const char *s, const char *t, const char *c, const char *rang } if (t) { - tgt = hashtab_search(mpdb->p_types.table, t); + tgt = hashtab_search(db->p_types.table, t); if (tgt == NULL) { LOGW("target type %s does not exist\n", t); return 1; @@ -434,7 +433,7 @@ int add_xperm_rule(const char *s, const char *t, const char *c, const char *rang } if (c) { - cls = hashtab_search(mpdb->p_classes.table, c); + cls = hashtab_search(db->p_classes.table, c); if (cls == NULL) { LOGW("class %s does not exist\n", c); return 1; @@ -455,29 +454,30 @@ int add_xperm_rule(const char *s, const char *t, const char *c, const char *rang high = 0xFFFF; } - return add_xperm_rule_auto(src, tgt, cls, low, high, effect, n); + return add_xperm_rule_auto(db, src, tgt, cls, low, high, effect, n); } -int add_type_rule(const char *s, const char *t, const char *c, const char *d, int effect) { +int add_type_rule(policydb_t *db, + const char *s, const char *t, const char *c, const char *d, int effect) { type_datum_t *src, *tgt, *def; class_datum_t *cls; - src = hashtab_search(mpdb->p_types.table, s); + src = hashtab_search(db->p_types.table, s); if (src == NULL) { LOGW("source type %s does not exist\n", s); return 1; } - tgt = hashtab_search(mpdb->p_types.table, t); + tgt = hashtab_search(db->p_types.table, t); if (tgt == NULL) { LOGW("target type %s does not exist\n", t); return 1; } - cls = hashtab_search(mpdb->p_classes.table, c); + cls = hashtab_search(db->p_classes.table, c); if (cls == NULL) { LOGW("class %s does not exist\n", c); return 1; } - def = hashtab_search(mpdb->p_types.table, d); + def = hashtab_search(db->p_types.table, d); if (def == NULL) { LOGW("default type %s does not exist\n", d); return 1; @@ -489,16 +489,16 @@ int add_type_rule(const char *s, const char *t, const char *c, const char *d, in key.target_class = cls->s.value; key.specified = effect; - avtab_ptr_t node = get_avtab_node(&key, NULL); + avtab_ptr_t node = get_avtab_node(db, &key, NULL); node->datum.data = def->s.value; return 0; } -int add_genfscon(const char *name, const char *path, const char *context) { +int add_genfscon(policydb_t *db, const char *name, const char *path, const char *context) { // First try to create context context_struct_t *ctx; - if (context_from_string(NULL, mpdb, &ctx, context, strlen(context))) { + if (context_from_string(NULL, db, &ctx, context, strlen(context))) { LOGW("Failed to create context from string [%s]\n", context); return 1; } @@ -512,7 +512,7 @@ int add_genfscon(const char *name, const char *path, const char *context) { // Find or allocate genfs genfs_t *last_gen = NULL; genfs_t *newfs = NULL; - for (genfs_t *node = mpdb->genfs; node; node = node->next) { + for (genfs_t *node = db->genfs; node; node = node->next) { if (strcmp(node->fstype, name) == 0) { newfs = node; break; @@ -526,7 +526,7 @@ int add_genfscon(const char *name, const char *path, const char *context) { if (last_gen) last_gen->next = newfs; else - mpdb->genfs = newfs; + db->genfs = newfs; } // Insert or replace genfs context @@ -555,9 +555,9 @@ int add_genfscon(const char *name, const char *path, const char *context) { return 0; } -void strip_dontaudit() { - avtab_for_each(&mpdb->te_avtab, { +void strip_dontaudit(policydb_t *db) { + avtab_for_each(&db->te_avtab, { if (node->key.specified == AVTAB_AUDITDENY || node->key.specified == AVTAB_XPERMS_DONTAUDIT) - avtab_remove_node(&magisk_policydb->te_avtab, node); + avtab_remove_node(&db->te_avtab, node); }) } diff --git a/native/jni/magiskpolicy/sepolicy.h b/native/jni/magiskpolicy/sepolicy.h index 7d6859c73..6aaa9d913 100644 --- a/native/jni/magiskpolicy/sepolicy.h +++ b/native/jni/magiskpolicy/sepolicy.h @@ -4,17 +4,21 @@ __BEGIN_DECLS -// Global policydb -extern policydb_t *magisk_policydb; +// Internal C APIs, do not use directly +int create_domain(policydb_t *db, const char *d); +int set_domain_state(policydb_t *db, const char *s, int state); +int add_typeattribute(policydb_t *db, const char *type, const char *attr); +int add_rule(policydb_t *db, const char *s, const char *t, const char *c, const char *p, int effect, + int n); +int add_xperm_rule(policydb_t *db, const char *s, const char *t, const char *c, const char *range, + int effect, int n); +int add_type_rule(policydb_t *db, const char *s, const char *t, const char *c, const char *d, + int effect); +int add_filename_trans(policydb_t *db, const char *s, const char *t, const char *c, const char *d, + const char *o); +int add_genfscon(policydb_t *db, const char *name, const char *path, const char *context); +void strip_dontaudit(policydb_t *db); -int create_domain(const char *d); -int set_domain_state(const char *s, int state); -int add_typeattribute(const char *type, const char *attr); -int add_rule(const char *s, const char *t, const char *c, const char *p, int effect, int n); -int add_xperm_rule(const char *s, const char *t, const char *c, const char *range, int effect, int n); -int add_type_rule(const char *s, const char *t, const char *c, const char *d, int effect); -int add_filename_trans(const char *s, const char *t, const char *c, const char *d, const char *o); -int add_genfscon(const char *name, const char *path, const char *context); -void strip_dontaudit(); +void statement_help(); __END_DECLS diff --git a/native/jni/magiskpolicy/statement.cpp b/native/jni/magiskpolicy/statement.cpp index 6583f83e6..466e539a6 100644 --- a/native/jni/magiskpolicy/statement.cpp +++ b/native/jni/magiskpolicy/statement.cpp @@ -6,42 +6,45 @@ #include #include +#include "sepolicy.h" + using namespace std; static const char *type_msg_1 = R"EOF(Type 1: -" source_type target_type class perm_set" +" ^source_type ^target_type ^class ^perm_set" Rules: allow, deny, auditallow, dontaudit )EOF"; static const char *type_msg_2 = R"EOF(Type 2: -" source_type target_type class operation xperm_set" +" ^source_type ^target_type ^class operation xperm_set" Rules: allowxperm, auditallowxperm, dontauditxperm -* The only supported operation is ioctl -* The only supported xperm_set format is range ([low-high]) +- The only supported operation is ioctl +- The only supported xperm_set format is range ([low-high]) )EOF"; static const char *type_msg_3 = R"EOF(Type 3: -" class" +" type" Rules: create, permissive, enforcing )EOF"; static const char *type_msg_4 = R"EOF(Type 4: -"attradd class attribute" +"typeattribute type attribute" )EOF"; static const char *type_msg_5 = R"EOF(Type 5: " source_type target_type class default_type" -Rules: type_transition, type_change, type_member +Rules: type_change, type_member )EOF"; static const char *type_msg_6 = R"EOF(Type 6: -"name_transition source_type target_type class default_type object_name" +"type_transition source_type target_type class default_type (object_name)" +- Entry 'object_name' is optional )EOF"; static const char *type_msg_7 = @@ -52,13 +55,22 @@ R"EOF(Type 7: void statement_help() { fprintf(stderr, R"EOF(One policy statement should be treated as one parameter; -this means a full policy statement should be enclosed in quotes. +this means each policy statement should be enclosed in quotes. Multiple policy statements can be provided in a single command. -The statements has a format of " [args...]" -Multiple types and permissions can be grouped into collections -wrapped in curly brackets. -'*' represents a collection containing all valid matches. +Statements has a format of " [args...]". +Arguments labeled with (^) can accept one or more entries. Multiple +entries consist of a space separated list enclosed in braces ({}). +For args that support multiple entries, (*) can be used to +represent all valid matches. + +Example: "allow { s1 s2 } { t1 t2 } class *" +Will be expanded to: + +allow s1 t1 class { all-permissions-of-class } +allow s1 t2 class { all-permissions-of-class } +allow s2 t1 class { all-permissions-of-class } +allow s2 t2 class { all-permissions-of-class } Supported policy statements: @@ -69,388 +81,193 @@ Supported policy statements: %s %s %s -Notes: -* Type 4 - 7 does not support collections -* Object classes cannot be collections -* source_type and target_type can also be attributes - -Example: allow { s1 s2 } { t1 t2 } class * -Will be expanded to: - -allow s1 t1 class { all-permissions } -allow s1 t2 class { all-permissions } -allow s2 t1 class { all-permissions } -allow s2 t2 class { all-permissions } - )EOF", type_msg_1, type_msg_2, type_msg_3, type_msg_4, type_msg_5, type_msg_6, type_msg_7); exit(0); } -static int parse_bracket(char *tok, char *&stmt, vector &vec) { - if (tok == nullptr || tok[0] != '{') { - // Not in a bracket - vec.push_back(tok); - } else { - if (stmt) - stmt[-1] = ' '; - tok = strchr(tok, '{') + 1; - char *end = strchr(tok, '}'); - if (end == nullptr) // Bracket not closed - return 1; - *end = '\0'; - char *cur; - while ((cur = strtok_r(nullptr, " ", &tok)) != nullptr) - vec.push_back(cur); - stmt = end + 1; +static bool tokenize_string(char *stmt, vector> &arr) { + // cur is the pointer to where the top level is parsing + char *cur = stmt; + for (char *tok; (tok = strtok_r(nullptr, " ", &cur)) != nullptr;) { + vector token; + if (tok[0] == '{') { + // cur could point to somewhere in the braces, restore the string + cur[-1] = ' '; + ++tok; + char *end = strchr(tok, '}'); + if (end == nullptr) { + // Bracket not closed, syntax error + LOGE("Unclosed bracket detected\n"); + return false; + } + *end = '\0'; + for (char *sub_tok; (sub_tok = strtok_r(nullptr, " ", &tok)) != nullptr;) + token.push_back(sub_tok); + cur = end + 1; + } else if (tok[0] == '*') { + token.push_back(nullptr); + } else { + token.push_back(tok); + } + arr.push_back(std::move(token)); } - return 0; + return true; } -// Pattern 1: action { source } { target } class { permission } -static int parse_pattern_1(int action, const char *action_str, char *stmt) { - int (*action_func)(const char*, const char*, const char*, const char*); - switch (action) { - case 0: - action_func = sepol_allow; - break; - case 1: - action_func = sepol_deny; - break; - case 2: - action_func = sepol_auditallow; - break; - case 3: - action_func = sepol_dontaudit; - break; - default: - return 1; - } - - int state = 0; - char *cur, *cls; - vector source, target, permission; - while ((cur = strtok_r(nullptr, " ", &stmt)) != nullptr) { - if (cur[0] == '*') cur = ALL; - vector *vec; - switch (state) { - case 0: - vec = &source; - break; - case 1: - vec = ⌖ - break; - case 2: - vec = nullptr; - cls = cur; - break; - case 3: - vec = &permission; - break; - default: - return 1; - } - - if (vec && parse_bracket(cur, stmt, *vec)) - return 1; - ++state; - } - if (state != 4 || source.empty() || target.empty() || permission.empty()) - return 1; - - for (auto src : source) - for (auto tgt : target) - for (auto perm : permission) - if (action_func(src, tgt, cls, perm)) - LOGW("Error in: %s %s %s %s %s\n", action_str, src, tgt, cls, perm); - - return 0; +// Pattern 1: action { source } { target } { class } { permission } +template +static bool parse_pattern_1(Func fn, const char *action, char *stmt) { + vector> arr; + if (!tokenize_string(stmt, arr)) + return false; + if (arr.size() != 4) + return false; + for (char *src : arr[0]) + for (char *tgt : arr[1]) + for (char *cls : arr[2]) + for (char *perm : arr[3]) + if (fn(src, tgt, cls, perm)) + LOGW("Error in: %s %s %s %s %s\n", action, src, tgt, cls, perm); + return true; } // Pattern 2: action { source } { target } { class } ioctl range -static int parse_pattern_2(int action, const char *action_str, char *stmt) { - int (*action_func)(const char*, const char*, const char*, const char*); - switch (action) { - case 0: - action_func = sepol_allowxperm; - break; - case 1: - action_func = sepol_auditallowxperm; - break; - case 2: - action_func = sepol_dontauditxperm; - break; - default: - return 1; - } - - int state = 0; - char *cur, *range; - vector source, target, classes; - while ((cur = strtok_r(nullptr, " ", &stmt)) != nullptr) { - if (cur[0] == '*') cur = ALL; - vector *vec; - switch (state) { - case 0: - vec = &source; - break; - case 1: - vec = ⌖ - break; - case 2: - vec = &classes; - break; - case 3: - // Currently only support ioctl - if (strcmp(cur, "ioctl") != 0) - return 1; - vec = nullptr; - break; - case 4: - vec = nullptr; - range = cur; - break; - default: - return 1; - } - - if (vec && parse_bracket(cur, stmt, *vec)) - return 1; - ++state; - } - if (state != 5 || source.empty() || target.empty() || classes.empty()) - return 1; - - for (auto src : source) - for (auto tgt : target) - for (auto cls : classes) - if (action_func(src, tgt, cls, range)) - LOGW("Error in: %s %s %s %s %s\n", action_str, src, tgt, cls, range); - - return 0; +template +static bool parse_pattern_2(Func fn, const char *action, char *stmt) { + vector> arr; + if (!tokenize_string(stmt, arr)) + return false; + if (arr.size() != 5 || arr[3].size() != 1 || arr[3][0] != "ioctl"sv || arr[4].size() != 1) + return false; + char *range = arr[4][0]; + for (char *src : arr[0]) + for (char *tgt : arr[1]) + for (char *cls : arr[2]) + if (fn(src, tgt, cls, range)) + LOGW("Error in: %s %s %s %s ioctl %s\n", action, src, tgt, cls, range); + return true; } // Pattern 3: action { type } -static int parse_pattern_3(int action, const char *action_str, char* stmt) { - int (*action_func)(const char*); - switch (action) { - case 0: - action_func = sepol_create; - break; - case 1: - action_func = sepol_permissive; - break; - case 2: - action_func = sepol_enforce; - break; - default: - return 1; - } - - char *cur; - vector domains; - while ((cur = strtok_r(nullptr, " {}", &stmt)) != nullptr) { - if (cur[0] == '*') cur = ALL; - domains.push_back(cur); - } - - if (domains.empty()) - return 1; - - for (auto dom : domains) - if (action_func(dom)) - LOGW("Error in: %s %s\n", action_str, dom); - - return 0; +template +static bool parse_pattern_3(Func fn, const char *action, char *stmt) { + vector> arr; + if (!tokenize_string(stmt, arr)) + return false; + if (arr.size() != 1) + return false; + for (char *type : arr[0]) + if (fn(type)) + LOGW("Error in: %s %s\n", action, type); + return true; } -// Pattern 4: action { class } { attribute } -static int parse_pattern_4(int action, const char *action_str, char *stmt) { - int (*action_func)(const char*, const char*); - switch (action) { - case 0: - action_func = sepol_attradd; - break; - default: - return 1; - } - - int state = 0; - char *cur; - vector classes, attribute; - while ((cur = strtok_r(nullptr, " ", &stmt)) != nullptr) { - if (cur[0] == '*') cur = ALL; - vector *vec; - switch (state) { - case 0: - vec = &classes; - break; - case 1: - vec = &attribute; - break; - default: - return 1; - } - - if (parse_bracket(cur, stmt, *vec)) - return 1; - ++state; - } - if (state != 2 || classes.empty() || attribute.empty()) - return 1; - - for (auto cls : classes) - for (auto attr : attribute) - if (action_func(cls, attr)) - LOGW("Error in: %s %s %s\n", action_str, cls, attr); - - return 0; +// Pattern 4: action { type } { attribute } +template +static bool parse_pattern_4(Func fn, const char *action, char *stmt) { + vector> arr; + if (!tokenize_string(stmt, arr)) + return false; + if (arr.size() != 2) + return false; + for (char *type : arr[0]) + for (char *attr : arr[1]) + if (fn(type, attr)) + LOGW("Error in: %s %s %s\n", action, type, attr); + return true; } // Pattern 5: action source target class default -static int parse_pattern_5(int action, const char *action_str, char *stmt) { - int (*action_func)(const char*, const char*, const char*, const char*); - switch (action) { - case 0: - action_func = sepol_typetrans; - break; - case 1: - action_func = sepol_typechange; - break; - case 2: - action_func = sepol_typemember; - break; - default: - return 1; - } - int state = 0; - char *cur; - char *source, *target, *cls, *def; - while ((cur = strtok_r(nullptr, " ", &stmt)) != nullptr) { - switch(state) { - case 0: - source = cur; - break; - case 1: - target = cur; - break; - case 2: - cls = cur; - break; - case 3: - def = cur; - break; - default: - return 1; - } - ++state; - } - if (state < 4) return 1; - if (action_func(source, target, cls, def)) - LOGW("Error in: %s %s %s %s %s\n", action_str, source, target, cls, def); - return 0; +template +static bool parse_pattern_5(Func fn, const char *action, char *stmt) { + vector> arr; + if (!tokenize_string(stmt, arr)) + return false; + if (arr.size() != 4 || + arr[0].size() != 1 || arr[1].size() != 1 || arr[2].size() != 1 || arr[3].size() != 1) + return false; + if (fn(arr[0][0], arr[1][0], arr[2][0], arr[3][0])) + LOGW("Error in: %s %s %s %s %s\n", action, arr[0][0], arr[1][0], arr[2][0], arr[3][0]); + return true; } -// Pattern 6: action source target class default filename -static int parse_pattern_6(int action, const char *action_str, char *stmt) { - int state = 0; - char *cur; - char *source, *target, *cls, *def, *filename; - while ((cur = strtok_r(nullptr, " ", &stmt)) != nullptr) { - switch(state) { - case 0: - source = cur; - break; - case 1: - target = cur; - break; - case 2: - cls = cur; - break; - case 3: - def = cur; - break; - case 4: - filename = cur; - break; - default: - return 1; - } - ++state; - } - if (state < 5) return 1; - if (sepol_nametrans(source, target, cls, def, filename)) - LOGW("Error in: %s %s %s %s %s %s\n", action_str, source, target, cls, def, filename); - return 0; +// Pattern 6: action source target class default (filename) +template +static bool parse_pattern_6(Func fn, const char *action, char *stmt) { + vector> arr; + if (!tokenize_string(stmt, arr)) + return false; + if (arr.size() == 4) + arr.emplace_back(initializer_list{nullptr}); + if (arr.size() != 5 || + arr[0].size() != 1 || arr[1].size() != 1 || arr[2].size() != 1 || + arr[3].size() != 1 || arr[4].size() != 1) + return false; + if (fn(arr[0][0], arr[1][0], arr[2][0], arr[3][0], arr[4][0])) + LOGW("Error in: %s %s %s %s %s %s\n", action, + arr[0][0], arr[1][0], arr[2][0], arr[3][0], arr[4][0] ? arr[4][0] : ""); + return true; } // Pattern 7: action name path context -static int parse_pattern_7(int action, const char *action_str, char *stmt) { - int state = 0; - char *cur; - char *name, *path, *context; - while ((cur = strtok_r(nullptr, " ", &stmt)) != nullptr) { - switch(state) { - case 0: - name = cur; - break; - case 1: - path = cur; - break; - case 2: - context = cur; - break; - default: - return 1; - } - ++state; - } - if (state < 3) return 1; - if (sepol_genfscon(name, path, context)) - LOGW("Error in: %s %s %s %s\n", action_str, name, path, context); - return 0; +template +static bool parse_pattern_7(Func fn, const char *action, char *stmt) { + vector> arr; + if (!tokenize_string(stmt, arr)) + return false; + if (arr.size() != 3 || arr[0].size() != 1 || arr[1].size() != 1 || arr[2].size() != 1) + return false; + if (fn(arr[0][0], arr[1][0], arr[2][0])) + LOGW("Error in: %s %s %s %s\n", action, arr[0][0], arr[1][0], arr[2][0]); + return true; } -#define add_action(name, type, num) \ +#define add_action_func(name, type, fn) \ else if (strcmp(name, action) == 0) { \ - if (parse_pattern_##type(num, name, remain)) \ - LOGW("Syntax error in '%s'\n\n%s\n", statement, type_msg_##type); \ + auto __fn = [=](auto && ...args){ return (fn)(args...); };\ + if (!parse_pattern_##type(__fn, name, remain)) \ + LOGW("Syntax error in '%s'\n\n%s\n", stmt, type_msg_##type); \ } -void parse_statement(const char *statement) { - char *action, *remain; +#define add_action(act, type) add_action_func(#act, type, act) - // strtok will modify strings, duplicate the statement - string stmt(statement); - - action = strtok_r(stmt.data(), " ", &remain); +void sepolicy::parse_statement(const char *stmt) { + // strtok modify strings, create a copy + string cpy(stmt); + char *remain; + char *action = strtok_r(cpy.data(), " ", &remain); if (remain == nullptr) { - LOGE("Syntax error in '%s'\n\n", statement); + LOGW("Syntax error in '%s'\n\n", stmt); return; } if (0) {} - add_action("allow", 1, 0) - add_action("deny", 1, 1) - add_action("auditallow", 1, 2) - add_action("dontaudit", 1, 3) - add_action("allowxperm", 2, 0) - add_action("auditallowxperm", 2, 1) - add_action("dontauditxperm", 2, 2) - add_action("create", 3, 0) - add_action("permissive", 3, 1) - add_action("enforce", 3, 2) - add_action("attradd", 4, 0) - add_action("type_transition", 5, 0) - add_action("type_change", 5, 1) - add_action("type_member", 5, 2) - add_action("name_transition", 6, 0) - add_action("genfscon", 7, 0) - else { LOGW("Unknown statement: '%s'\n\n", statement); } + add_action(allow, 1) + add_action(deny, 1) + add_action(auditallow, 1) + add_action(dontaudit, 1) + add_action(allowxperm, 2) + add_action(auditallowxperm, 2) + add_action(dontauditxperm, 2) + add_action(create, 3) + add_action(permissive, 3) + add_action(enforce, 3) + add_action(typeattribute, 4) + add_action(type_change, 5) + add_action(type_member, 5) + add_action(type_transition, 6) + add_action(genfscon, 7) + + // Backwards compatible syntax + add_action_func("attradd", 4, typeattribute) + add_action_func("name_transition", 6, type_transition) + + else { LOGW("Syntax error in '%s'\n\n", stmt); } } -void load_rule_file(const char *file) { - file_readline(true, file, [](string_view line) -> bool { +void sepolicy::load_rule_file(const char *file) { + file_readline(true, file, [=](string_view line) -> bool { if (line.empty() || line[0] == '#') return true; parse_statement(line.data());