Modernize magiskpolicy

This commit is contained in:
topjohnwu 2020-05-21 06:48:02 -07:00
parent e02e46d0fc
commit d4baae411b
9 changed files with 583 additions and 739 deletions

View File

@ -3,38 +3,55 @@
#include <stdlib.h> #include <stdlib.h>
#include <selinux.hpp> #include <selinux.hpp>
#define ALL NULL #define ALL nullptr
// policydb functions struct policydb;
int load_policydb(const char *file);
int load_split_cil();
int compile_split_cil();
int dump_policydb(const char *file);
void destroy_policydb();
// Handy functions class sepolicy {
int sepol_allow(const char *s, const char *t, const char *c, const char *p); public:
int sepol_deny(const char *s, const char *t, const char *c, const char *p); typedef const char * c_str;
int sepol_auditallow(const char *s, const char *t, const char *c, const char *p); ~sepolicy();
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);
// Built in rules // Public static factory functions
void sepol_magisk_rules(); static sepolicy *from_file(c_str file);
static sepolicy *from_split();
static sepolicy *compile_split();
// Statement parsing // External APIs
void parse_statement(const char *statement); int to_file(c_str file);
void load_rule_file(const char *file); void parse_statement(c_str stmt);
void statement_help(); 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;
};

View File

@ -129,13 +129,14 @@ void RootFSInit::setup_rootfs() {
bool MagiskInit::patch_sepolicy(const char *file) { bool MagiskInit::patch_sepolicy(const char *file) {
bool patch_init = false; bool patch_init = false;
sepolicy *sepol = nullptr;
if (access(SPLIT_PLAT_CIL, R_OK) == 0) { if (access(SPLIT_PLAT_CIL, R_OK) == 0) {
LOGD("sepol: split policy\n"); LOGD("sepol: split policy\n");
patch_init = true; patch_init = true;
} else if (access("/sepolicy", R_OK) == 0) { } else if (access("/sepolicy", R_OK) == 0) {
LOGD("sepol: monolithic policy\n"); LOGD("sepol: monolithic policy\n");
load_policydb("/sepolicy"); sepol = sepolicy::from_file("/sepolicy");
} else { } else {
LOGD("sepol: no selinux\n"); LOGD("sepol: no selinux\n");
return false; return false;
@ -148,10 +149,10 @@ bool MagiskInit::patch_sepolicy(const char *file) {
} }
if (patch_init) if (patch_init)
load_split_cil(); sepol = sepolicy::from_split();
sepol_magisk_rules(); sepol->magisk_rules();
sepol_allow(SEPOL_PROC_DOMAIN, ALL, ALL, ALL); sepol->allow(SEPOL_PROC_DOMAIN, ALL, ALL, ALL);
// Custom rules // Custom rules
if (auto dir = open_dir(persist_dir.data()); dir) { 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"; auto rule = persist_dir + "/" + entry->d_name + "/sepolicy.rule";
if (access(rule.data(), R_OK) == 0) { if (access(rule.data(), R_OK) == 0) {
LOGD("Loading custom sepolicy patch: %s\n", rule.data()); LOGD("Loading custom sepolicy patch: %s\n", rule.data());
load_rule_file(rule.data()); sepol->load_rule_file(rule.data());
} }
} }
} }
dump_policydb(file); sepol->to_file(file);
destroy_policydb(); delete sepol;
// Remove OnePlus stupid debug sepolicy and use our own // Remove OnePlus stupid debug sepolicy and use our own
if (access("/sepolicy_debug", F_OK) == 0) { if (access("/sepolicy_debug", F_OK) == 0) {

View File

@ -5,86 +5,86 @@
//#define vprint(fmt, ...) printf(fmt, __VA_ARGS__) //#define vprint(fmt, ...) printf(fmt, __VA_ARGS__)
#define vprint(...) #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); 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); 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); 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); 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); 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); 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); 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) { int sepolicy::type_change(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) {
vprint("type_change %s %s %s %s\n", s, t, c, 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); 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) { int sepolicy::type_transition(const char *src, const char *tgt, const char *cls, const char *def, const char *obj) {
vprint("name_trans %s %s %s %s %s\n", s, t, c, d, o); if (obj) {
return add_filename_trans(s, t, c, d, o); 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); 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); 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); vprint("create %s\n", s);
return create_domain(s); return create_domain(db, s);
} }
int sepol_attradd(const char *s, const char *a) { int sepolicy::typeattribute(const char *type, const char *attr) {
vprint("attradd %s %s\n", s, a); vprint("typeattribute %s %s\n", type, attr);
return add_typeattribute(s, a); return add_typeattribute(db, type, attr);
} }
int sepol_genfscon(const char *name, const char *path, const char *context) { int sepolicy::genfscon(const char *fs_name, const char *path, const char *ctx) {
vprint("genfscon %s %s %s\n", name, path, context); vprint("genfscon %s %s %s\n", fs_name, path, ctx);
return add_genfscon(name, path, context); return add_genfscon(db, fs_name, path, ctx);
} }
int sepol_exists(const char *source) { int sepolicy::exists(const char *source) {
return hashtab_search(magisk_policydb->p_types.table, source) != nullptr; return hashtab_search(db->p_types.table, source) != nullptr;
} }

View File

@ -40,6 +40,7 @@ int magiskpolicy_main(int argc, char *argv[]) {
cmdline_logging(); cmdline_logging();
const char *out_file = nullptr; const char *out_file = nullptr;
const char *rule_file = nullptr; const char *rule_file = nullptr;
sepolicy *sepol = nullptr;
bool magisk = false; bool magisk = false;
bool live = false; bool live = false;
@ -56,18 +57,21 @@ int magiskpolicy_main(int argc, char *argv[]) {
else if (option == "load"sv) { else if (option == "load"sv) {
if (argv[i + 1] == nullptr) if (argv[i + 1] == nullptr)
usage(argv[0]); 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]); fprintf(stderr, "Cannot load policy from %s\n", argv[i + 1]);
return 1; return 1;
} }
++i; ++i;
} else if (option == "load-split"sv) { } else if (option == "load-split"sv) {
if (load_split_cil()) { sepol = sepolicy::from_split();
if (!sepol) {
fprintf(stderr, "Cannot load split cil\n"); fprintf(stderr, "Cannot load split cil\n");
return 1; return 1;
} }
} else if (option == "compile-split"sv) { } else if (option == "compile-split"sv) {
if (compile_split_cil()) { sepol = sepolicy::compile_split();
if (!sepol) {
fprintf(stderr, "Cannot compile split cil\n"); fprintf(stderr, "Cannot compile split cil\n");
return 1; return 1;
} }
@ -92,30 +96,30 @@ int magiskpolicy_main(int argc, char *argv[]) {
} }
// Use current policy if nothing is loaded // 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"); fprintf(stderr, "Cannot load policy from " SELINUX_POLICY "\n");
return 1; return 1;
} }
if (magisk) if (magisk)
sepol_magisk_rules(); sepol->magisk_rules();
if (rule_file) if (rule_file)
load_rule_file(rule_file); sepol->load_rule_file(rule_file);
for (; i < argc; ++i) 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"); fprintf(stderr, "Cannot apply policy\n");
return 1; 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); fprintf(stderr, "Cannot dump policy to %s\n", out_file);
return 1; return 1;
} }
destroy_policydb(); delete sepol;
return 0; return 0;
} }

View File

@ -12,26 +12,6 @@
#include "sepolicy.h" #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<policydb_t *>(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 #define SHALEN 64
static bool cmp_sha256(const char *a, const char *b) { static bool cmp_sha256(const char *a, const char *b) {
char id_a[SHALEN] = {0}; char id_a[SHALEN] = {0};
@ -94,17 +74,6 @@ static bool check_precompiled(const char *precompiled) {
return ok; 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) { static void load_cil(struct cil_db *db, const char *file) {
char *addr; char *addr;
size_t size; size_t size;
@ -114,15 +83,37 @@ static void load_cil(struct cil_db *db, const char *file) {
munmap(addr, size); 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<policydb_t *>(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]; char path[128], plat_ver[10];
struct cil_db *db = nullptr; cil_db_t *db = nullptr;
sepol_policydb_t *pdb = nullptr; sepol_policydb_t *pdb = nullptr;
FILE *f; FILE *f;
int policy_ver; int policy_ver;
const char *cil_file; const char *cil_file;
cil_db_init(&db); cil_db_init(&db);
run_finally fin([db_ptr = &db]{ cil_db_destroy(db_ptr); });
cil_set_mls(db, 1); cil_set_mls(db, 1);
cil_set_multiple_decls(db, 1); cil_set_multiple_decls(db, 1);
cil_set_disable_neverallow(db, 1); cil_set_disable_neverallow(db, 1);
@ -173,29 +164,48 @@ int compile_split_cil() {
load_cil(db, cil_file); load_cil(db, cil_file);
if (cil_compile(db)) if (cil_compile(db))
return 1; return nullptr;
if (cil_build_policydb(db, &pdb)) if (cil_build_policydb(db, &pdb))
return 1; return nullptr;
cil_db_destroy(&db); auto sepol = new sepolicy();
magisk_policydb = &pdb->p; sepol->db = &pdb->p;
return 0; 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; uint8_t *data;
size_t len; size_t len;
{ /* No partial writes are allowed to /sys/fs/selinux/load, thus the reason why we
auto fp = make_stream_fp<byte_stream>(data, len); * first dump everything into memory, then directly call write system call */
struct policy_file pf;
policy_file_init(&pf); auto fp = make_stream_fp<byte_stream>(data, len);
pf.type = PF_USE_STDIO; run_finally fin([=]{ free(data); });
pf.fp = fp.get();
if (policydb_write(magisk_policydb, &pf)) { policy_file_t pf;
LOGE("Fail to create policy image\n"); policy_file_init(&pf);
return 1; 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); 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); xwrite(fd, data, len);
close(fd); close(fd);
free(data);
return 0; return 0;
} }
void destroy_policydb() {
if (magisk_policydb) {
policydb_destroy(magisk_policydb);
free(magisk_policydb);
magisk_policydb = nullptr;
}
}

View File

@ -4,202 +4,202 @@
#include "sepolicy.h" #include "sepolicy.h"
static void allowSuClient(const char *target) { void sepolicy::allow_su_client(const char *type) {
if (!sepol_exists(target)) if (!exists(type))
return; return;
sepol_allow(target, SEPOL_PROC_DOMAIN, "unix_stream_socket", "connectto"); allow(type, SEPOL_PROC_DOMAIN, "unix_stream_socket", "connectto");
sepol_allow(target, SEPOL_PROC_DOMAIN, "unix_stream_socket", "getopt"); allow(type, SEPOL_PROC_DOMAIN, "unix_stream_socket", "getopt");
sepol_allow(SEPOL_PROC_DOMAIN, target, "fd", "use"); allow(SEPOL_PROC_DOMAIN, type, "fd", "use");
sepol_allow(SEPOL_PROC_DOMAIN, target, "fifo_file", ALL); allow(SEPOL_PROC_DOMAIN, type, "fifo_file", ALL);
// Allow binder service // Allow binder service
sepol_allow(target, SEPOL_PROC_DOMAIN, "binder", "call"); allow(type, SEPOL_PROC_DOMAIN, "binder", "call");
sepol_allow(target, SEPOL_PROC_DOMAIN, "binder", "transfer"); allow(type, SEPOL_PROC_DOMAIN, "binder", "transfer");
// Allow termios ioctl // Allow termios ioctl
sepol_allow(target, "devpts", "chr_file", "ioctl"); allow(type, "devpts", "chr_file", "ioctl");
sepol_allow(target, "untrusted_app_devpts", "chr_file", "ioctl"); allow(type, "untrusted_app_devpts", "chr_file", "ioctl");
sepol_allow(target, "untrusted_app_25_devpts", "chr_file", "ioctl"); allow(type, "untrusted_app_25_devpts", "chr_file", "ioctl");
sepol_allow(target, "untrusted_app_all_devpts", "chr_file", "ioctl"); allow(type, "untrusted_app_all_devpts", "chr_file", "ioctl");
if (magisk_policydb->policyvers >= POLICYDB_VERSION_XPERMS_IOCTL) { if (db->policyvers >= POLICYDB_VERSION_XPERMS_IOCTL) {
sepol_allowxperm(target, "devpts", "chr_file", "0x5400-0x54FF"); allowxperm(type, "devpts", "chr_file", "0x5400-0x54FF");
sepol_allowxperm(target, "untrusted_app_devpts", "chr_file", "0x5400-0x54FF"); allowxperm(type, "untrusted_app_devpts", "chr_file", "0x5400-0x54FF");
sepol_allowxperm(target, "untrusted_app_25_devpts", "chr_file", "0x5400-0x54FF"); allowxperm(type, "untrusted_app_25_devpts", "chr_file", "0x5400-0x54FF");
sepol_allowxperm(target, "untrusted_app_all_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 // Temp suppress warnings
auto bak = log_cb.w; auto bak = log_cb.w;
log_cb.w = nop_log; log_cb.w = nop_log;
// First prevent anything to change sepolicy except ourselves // 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)) if (!exists(SEPOL_PROC_DOMAIN))
sepol_create(SEPOL_PROC_DOMAIN); create(SEPOL_PROC_DOMAIN);
if (!sepol_exists(SEPOL_FILE_DOMAIN)) if (!exists(SEPOL_FILE_DOMAIN))
sepol_create(SEPOL_FILE_DOMAIN); create(SEPOL_FILE_DOMAIN);
sepol_permissive(SEPOL_PROC_DOMAIN); permissive(SEPOL_PROC_DOMAIN);
sepol_attradd(SEPOL_PROC_DOMAIN, "mlstrustedsubject"); typeattribute(SEPOL_PROC_DOMAIN, "mlstrustedsubject");
sepol_attradd(SEPOL_PROC_DOMAIN, "netdomain"); typeattribute(SEPOL_PROC_DOMAIN, "netdomain");
sepol_attradd(SEPOL_PROC_DOMAIN, "bluetoothdomain"); typeattribute(SEPOL_PROC_DOMAIN, "bluetoothdomain");
sepol_attradd(SEPOL_FILE_DOMAIN, "mlstrustedobject"); typeattribute(SEPOL_FILE_DOMAIN, "mlstrustedobject");
// Let everyone access tmpfs files (for SAR sbin overlay) // 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) // 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 // Let init transit to SEPOL_PROC_DOMAIN
sepol_allow("kernel", "kernel", "process", "setcurrent"); allow("kernel", "kernel", "process", "setcurrent");
sepol_allow("kernel", SEPOL_PROC_DOMAIN, "process", "dyntransition"); allow("kernel", SEPOL_PROC_DOMAIN, "process", "dyntransition");
// Let init run stuffs // Let init run stuffs
sepol_allow("kernel", SEPOL_PROC_DOMAIN, "fd", "use"); allow("kernel", SEPOL_PROC_DOMAIN, "fd", "use");
sepol_allow("init", SEPOL_PROC_DOMAIN, "process", ALL); allow("init", SEPOL_PROC_DOMAIN, "process", ALL);
sepol_allow("init", "tmpfs", "file", "getattr"); allow("init", "tmpfs", "file", "getattr");
sepol_allow("init", "tmpfs", "file", "execute"); allow("init", "tmpfs", "file", "execute");
// Shell, properties, logs // Shell, properties, logs
if (sepol_exists("default_prop")) if (exists("default_prop"))
sepol_allow(SEPOL_PROC_DOMAIN, "default_prop", "property_service", "set"); allow(SEPOL_PROC_DOMAIN, "default_prop", "property_service", "set");
sepol_allow(SEPOL_PROC_DOMAIN, "init", "unix_stream_socket", "connectto"); allow(SEPOL_PROC_DOMAIN, "init", "unix_stream_socket", "connectto");
sepol_allow(SEPOL_PROC_DOMAIN, "rootfs", "filesystem", "remount"); allow(SEPOL_PROC_DOMAIN, "rootfs", "filesystem", "remount");
if (sepol_exists("logd")) if (exists("logd"))
sepol_allow(SEPOL_PROC_DOMAIN, "logd", "unix_stream_socket", "connectto"); allow(SEPOL_PROC_DOMAIN, "logd", "unix_stream_socket", "connectto");
sepol_allow(SEPOL_PROC_DOMAIN, SEPOL_PROC_DOMAIN, ALL, ALL); allow(SEPOL_PROC_DOMAIN, SEPOL_PROC_DOMAIN, ALL, ALL);
// For sepolicy live patching // For sepolicy live patching
sepol_allow(SEPOL_PROC_DOMAIN, "kernel", "security", "read_policy"); allow(SEPOL_PROC_DOMAIN, "kernel", "security", "read_policy");
sepol_allow(SEPOL_PROC_DOMAIN, "kernel", "security", "load_policy"); allow(SEPOL_PROC_DOMAIN, "kernel", "security", "load_policy");
// Allow these processes to access MagiskSU // Allow these processes to access MagiskSU
allowSuClient("init"); allow_su_client("init");
allowSuClient("shell"); allow_su_client("shell");
allowSuClient("system_app"); allow_su_client("system_app");
allowSuClient("priv_app"); allow_su_client("priv_app");
allowSuClient("platform_app"); allow_su_client("platform_app");
allowSuClient("untrusted_app"); allow_su_client("untrusted_app");
allowSuClient("untrusted_app_25"); allow_su_client("untrusted_app_25");
allowSuClient("untrusted_app_27"); allow_su_client("untrusted_app_27");
allowSuClient("untrusted_app_29"); allow_su_client("untrusted_app_29");
allowSuClient("update_engine"); allow_su_client("update_engine");
// suRights // suRights
sepol_allow("servicemanager", SEPOL_PROC_DOMAIN, "dir", "search"); allow("servicemanager", SEPOL_PROC_DOMAIN, "dir", "search");
sepol_allow("servicemanager", SEPOL_PROC_DOMAIN, "dir", "read"); allow("servicemanager", SEPOL_PROC_DOMAIN, "dir", "read");
sepol_allow("servicemanager", SEPOL_PROC_DOMAIN, "file", "open"); allow("servicemanager", SEPOL_PROC_DOMAIN, "file", "open");
sepol_allow("servicemanager", SEPOL_PROC_DOMAIN, "file", "read"); allow("servicemanager", SEPOL_PROC_DOMAIN, "file", "read");
sepol_allow("servicemanager", SEPOL_PROC_DOMAIN, "process", "getattr"); allow("servicemanager", SEPOL_PROC_DOMAIN, "process", "getattr");
sepol_allow("servicemanager", SEPOL_PROC_DOMAIN, "binder", "transfer"); allow("servicemanager", SEPOL_PROC_DOMAIN, "binder", "transfer");
sepol_allow(SEPOL_PROC_DOMAIN, "servicemanager", "dir", "search"); allow(SEPOL_PROC_DOMAIN, "servicemanager", "dir", "search");
sepol_allow(SEPOL_PROC_DOMAIN, "servicemanager", "dir", "read"); allow(SEPOL_PROC_DOMAIN, "servicemanager", "dir", "read");
sepol_allow(SEPOL_PROC_DOMAIN, "servicemanager", "file", "open"); allow(SEPOL_PROC_DOMAIN, "servicemanager", "file", "open");
sepol_allow(SEPOL_PROC_DOMAIN, "servicemanager", "file", "read"); allow(SEPOL_PROC_DOMAIN, "servicemanager", "file", "read");
sepol_allow(SEPOL_PROC_DOMAIN, "servicemanager", "process", "getattr"); allow(SEPOL_PROC_DOMAIN, "servicemanager", "process", "getattr");
sepol_allow(SEPOL_PROC_DOMAIN, "servicemanager", "binder", "transfer"); allow(SEPOL_PROC_DOMAIN, "servicemanager", "binder", "transfer");
sepol_allow(SEPOL_PROC_DOMAIN, "servicemanager", "binder", "call"); allow(SEPOL_PROC_DOMAIN, "servicemanager", "binder", "call");
sepol_allow(ALL, SEPOL_PROC_DOMAIN, "process", "sigchld"); allow(ALL, SEPOL_PROC_DOMAIN, "process", "sigchld");
// allowLog // allowLog
sepol_allow("logd", SEPOL_PROC_DOMAIN, "dir", "search"); allow("logd", SEPOL_PROC_DOMAIN, "dir", "search");
sepol_allow("logd", SEPOL_PROC_DOMAIN, "file", "read"); allow("logd", SEPOL_PROC_DOMAIN, "file", "read");
sepol_allow("logd", SEPOL_PROC_DOMAIN, "file", "open"); allow("logd", SEPOL_PROC_DOMAIN, "file", "open");
sepol_allow("logd", SEPOL_PROC_DOMAIN, "file", "getattr"); allow("logd", SEPOL_PROC_DOMAIN, "file", "getattr");
// suBackL0 // suBackL0
sepol_allow("system_server", SEPOL_PROC_DOMAIN, "binder", "call"); allow("system_server", SEPOL_PROC_DOMAIN, "binder", "call");
sepol_allow("system_server", SEPOL_PROC_DOMAIN, "binder", "transfer"); allow("system_server", SEPOL_PROC_DOMAIN, "binder", "transfer");
sepol_allow(SEPOL_PROC_DOMAIN, "system_server", "binder", "call"); allow(SEPOL_PROC_DOMAIN, "system_server", "binder", "call");
sepol_allow(SEPOL_PROC_DOMAIN, "system_server", "binder", "transfer"); allow(SEPOL_PROC_DOMAIN, "system_server", "binder", "transfer");
// suBackL6 // suBackL6
sepol_allow("surfaceflinger", "app_data_file", "dir", ALL); allow("surfaceflinger", "app_data_file", "dir", ALL);
sepol_allow("surfaceflinger", "app_data_file", "file", ALL); allow("surfaceflinger", "app_data_file", "file", ALL);
sepol_allow("surfaceflinger", "app_data_file", "lnk_file", ALL); allow("surfaceflinger", "app_data_file", "lnk_file", ALL);
sepol_attradd("surfaceflinger", "mlstrustedsubject"); typeattribute("surfaceflinger", "mlstrustedsubject");
// suMiscL6 // suMiscL6
if (sepol_exists("audioserver")) if (exists("audioserver"))
sepol_allow("audioserver", "audioserver", "process", "execmem"); allow("audioserver", "audioserver", "process", "execmem");
// Liveboot // Liveboot
sepol_allow("surfaceflinger", SEPOL_PROC_DOMAIN, "process", "ptrace"); allow("surfaceflinger", SEPOL_PROC_DOMAIN, "process", "ptrace");
sepol_allow("surfaceflinger", SEPOL_PROC_DOMAIN, "binder", "transfer"); allow("surfaceflinger", SEPOL_PROC_DOMAIN, "binder", "transfer");
sepol_allow("surfaceflinger", SEPOL_PROC_DOMAIN, "binder", "call"); allow("surfaceflinger", SEPOL_PROC_DOMAIN, "binder", "call");
sepol_allow("surfaceflinger", SEPOL_PROC_DOMAIN, "fd", "use"); allow("surfaceflinger", SEPOL_PROC_DOMAIN, "fd", "use");
sepol_allow("debuggerd", SEPOL_PROC_DOMAIN, "process", "ptrace"); allow("debuggerd", SEPOL_PROC_DOMAIN, "process", "ptrace");
// dumpsys // dumpsys
sepol_allow(ALL, SEPOL_PROC_DOMAIN, "fd", "use"); allow(ALL, SEPOL_PROC_DOMAIN, "fd", "use");
sepol_allow(ALL, SEPOL_PROC_DOMAIN, "fifo_file", "write"); allow(ALL, SEPOL_PROC_DOMAIN, "fifo_file", "write");
sepol_allow(ALL, SEPOL_PROC_DOMAIN, "fifo_file", "read"); allow(ALL, SEPOL_PROC_DOMAIN, "fifo_file", "read");
sepol_allow(ALL, SEPOL_PROC_DOMAIN, "fifo_file", "open"); allow(ALL, SEPOL_PROC_DOMAIN, "fifo_file", "open");
sepol_allow(ALL, SEPOL_PROC_DOMAIN, "fifo_file", "getattr"); allow(ALL, SEPOL_PROC_DOMAIN, "fifo_file", "getattr");
// bootctl // bootctl
sepol_allow("hwservicemanager", SEPOL_PROC_DOMAIN, "dir", "search"); allow("hwservicemanager", SEPOL_PROC_DOMAIN, "dir", "search");
sepol_allow("hwservicemanager", SEPOL_PROC_DOMAIN, "file", "read"); allow("hwservicemanager", SEPOL_PROC_DOMAIN, "file", "read");
sepol_allow("hwservicemanager", SEPOL_PROC_DOMAIN, "file", "open"); allow("hwservicemanager", SEPOL_PROC_DOMAIN, "file", "open");
sepol_allow("hwservicemanager", SEPOL_PROC_DOMAIN, "process", "getattr"); allow("hwservicemanager", SEPOL_PROC_DOMAIN, "process", "getattr");
sepol_allow("hwservicemanager", SEPOL_PROC_DOMAIN, "binder", "transfer"); allow("hwservicemanager", SEPOL_PROC_DOMAIN, "binder", "transfer");
// For mounting loop devices, mirrors, tmpfs // For mounting loop devices, mirrors, tmpfs
sepol_allow(SEPOL_PROC_DOMAIN, "kernel", "process", "setsched"); allow(SEPOL_PROC_DOMAIN, "kernel", "process", "setsched");
sepol_allow(SEPOL_PROC_DOMAIN, "labeledfs", "filesystem", "mount"); allow(SEPOL_PROC_DOMAIN, "labeledfs", "filesystem", "mount");
sepol_allow(SEPOL_PROC_DOMAIN, "labeledfs", "filesystem", "unmount"); allow(SEPOL_PROC_DOMAIN, "labeledfs", "filesystem", "unmount");
sepol_allow(SEPOL_PROC_DOMAIN, "tmpfs", "filesystem", "mount"); allow(SEPOL_PROC_DOMAIN, "tmpfs", "filesystem", "mount");
sepol_allow(SEPOL_PROC_DOMAIN, "tmpfs", "filesystem", "unmount"); allow(SEPOL_PROC_DOMAIN, "tmpfs", "filesystem", "unmount");
sepol_allow("kernel", ALL, "file", "read"); allow("kernel", ALL, "file", "read");
sepol_allow("kernel", ALL, "file", "write"); allow("kernel", ALL, "file", "write");
// Allow us to do anything to any files/dir/links // Allow us to do anything to any files/dir/links
sepol_allow(SEPOL_PROC_DOMAIN, ALL, "file", ALL); allow(SEPOL_PROC_DOMAIN, ALL, "file", ALL);
sepol_allow(SEPOL_PROC_DOMAIN, ALL, "dir", ALL); allow(SEPOL_PROC_DOMAIN, ALL, "dir", ALL);
sepol_allow(SEPOL_PROC_DOMAIN, ALL, "lnk_file", ALL); allow(SEPOL_PROC_DOMAIN, ALL, "lnk_file", ALL);
sepol_allow(SEPOL_PROC_DOMAIN, ALL, "blk_file", ALL); allow(SEPOL_PROC_DOMAIN, ALL, "blk_file", ALL);
sepol_allow(SEPOL_PROC_DOMAIN, ALL, "sock_file", ALL); allow(SEPOL_PROC_DOMAIN, ALL, "sock_file", ALL);
sepol_allow(SEPOL_PROC_DOMAIN, ALL, "chr_file", ALL); allow(SEPOL_PROC_DOMAIN, ALL, "chr_file", ALL);
sepol_allow(SEPOL_PROC_DOMAIN, ALL, "fifo_file", ALL); allow(SEPOL_PROC_DOMAIN, ALL, "fifo_file", ALL);
// Allow us to do any ioctl on all block devices // Allow us to do any ioctl on all block devices
if (magisk_policydb->policyvers >= POLICYDB_VERSION_XPERMS_IOCTL) if (db->policyvers >= POLICYDB_VERSION_XPERMS_IOCTL)
sepol_allowxperm(SEPOL_PROC_DOMAIN, ALL, "blk_file", "0x0000-0xFFFF"); allowxperm(SEPOL_PROC_DOMAIN, ALL, "blk_file", "0x0000-0xFFFF");
// Allow all binder transactions // Allow all binder transactions
sepol_allow(ALL, SEPOL_PROC_DOMAIN, "binder", ALL); allow(ALL, SEPOL_PROC_DOMAIN, "binder", ALL);
// Super files // Super files
sepol_allow(ALL, SEPOL_FILE_DOMAIN, "file", ALL); allow(ALL, SEPOL_FILE_DOMAIN, "file", ALL);
sepol_allow(ALL, SEPOL_FILE_DOMAIN, "dir", ALL); allow(ALL, SEPOL_FILE_DOMAIN, "dir", ALL);
sepol_allow(ALL, SEPOL_FILE_DOMAIN, "fifo_file", ALL); allow(ALL, SEPOL_FILE_DOMAIN, "fifo_file", ALL);
sepol_allow(ALL, SEPOL_FILE_DOMAIN, "chr_file", ALL); allow(ALL, SEPOL_FILE_DOMAIN, "chr_file", ALL);
sepol_allow(SEPOL_FILE_DOMAIN, ALL, "filesystem", "associate"); allow(SEPOL_FILE_DOMAIN, ALL, "filesystem", "associate");
// For changing attributes // For changing attributes
sepol_allow("rootfs", "tmpfs", "filesystem", "associate"); allow("rootfs", "tmpfs", "filesystem", "associate");
// Xposed // Xposed
sepol_allow("untrusted_app", "untrusted_app", "capability", "setgid"); allow("untrusted_app", "untrusted_app", "capability", "setgid");
sepol_allow("system_server", "dex2oat_exec", "file", ALL); allow("system_server", "dex2oat_exec", "file", ALL);
// Support deodexed ROM on Oreo // 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) // Support deodexed ROM on Pie (Samsung)
sepol_allow("system_server", "dalvikcache_data_file", "file", "write"); allow("system_server", "dalvikcache_data_file", "file", "write");
sepol_allow("system_server", "dalvikcache_data_file", "file", "execute"); allow("system_server", "dalvikcache_data_file", "file", "execute");
// Allow update_engine/addon.d-v2 to run permissive on all ROMs // Allow update_engine/addon.d-v2 to run permissive on all ROMs
sepol_permissive("update_engine"); permissive("update_engine");
#if 0 #if 0
// Remove all dontaudit in debug mode // Remove all dontaudit in debug mode
strip_dontaudit(); strip_dontaudit(db);
#endif #endif
log_cb.w = bak; log_cb.w = bak;

View File

@ -5,9 +5,6 @@
#include "sepolicy.h" #include "sepolicy.h"
policydb_t *magisk_policydb = NULL;
#define mpdb magisk_policydb
extern void *xmalloc(size_t size); extern void *xmalloc(size_t size);
extern void *xcalloc(size_t nmemb, size_t size); extern void *xcalloc(size_t nmemb, size_t size);
extern void *xrealloc(void *ptr, 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) \ #define avtab_for_each(avtab, block) \
hash_for_each(htable, nslot, avtab, block) hash_for_each(htable, nslot, avtab, block)
static int set_attr(const char *type, int value) { static int set_attr(policydb_t *db, const char *type, int value) {
type_datum_t *attr = hashtab_search(mpdb->p_types.table, type); type_datum_t *attr = hashtab_search(db->p_types.table, type);
if (!attr || attr->flavor != TYPE_ATTRIB) if (!attr || attr->flavor != TYPE_ATTRIB)
return -1; 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; 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 -1;
return attr->s.value; 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; int redundant = 0;
if (node->key.specified == AVTAB_AUDITDENY) if (node->key.specified == AVTAB_AUDITDENY)
redundant = node->datum.data == ~0U; redundant = node->datum.data == ~0U;
@ -61,17 +58,17 @@ static void check_avtab_node(avtab_ptr_t node) {
else else
redundant = node->datum.data == 0U; redundant = node->datum.data == 0U;
if (redundant) 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_ptr_t node;
avtab_datum_t avdatum; avtab_datum_t avdatum;
int match = 0; int match = 0;
/* AVTAB_XPERMS entries are not necessarily unique */ /* AVTAB_XPERMS entries are not necessarily unique */
if (key->specified & AVTAB_XPERMS) { if (key->specified & AVTAB_XPERMS) {
node = avtab_search_node(&mpdb->te_avtab, key); node = avtab_search_node(&db->te_avtab, key);
while (node) { while (node) {
if ((node->datum.xperms->specified == xperms->specified) && if ((node->datum.xperms->specified == xperms->specified) &&
(node->datum.xperms->driver == xperms->driver)) { (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) if (!match)
node = NULL; node = NULL;
} else { } else {
node = avtab_search_node(&mpdb->te_avtab, key); node = avtab_search_node(&db->te_avtab, key);
} }
if (!node) { 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; avdatum.data = key->specified == AVTAB_AUDITDENY ? ~0U : 0U;
/* this is used to get the node - insertion is actually unique */ /* 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; return node;
} }
static int add_avrule(avtab_key_t *key, int val, int not) { static int add_avrule(policydb_t *db, avtab_key_t *key, int val, int not) {
avtab_ptr_t node = get_avtab_node(key, NULL); avtab_ptr_t node = get_avtab_node(NULL, key, NULL);
if (not) { if (not) {
if (val < 0) 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); node->datum.data |= 1U << (val - 1);
} }
check_avtab_node(node); check_avtab_node(db, node);
return 0; 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) { perm_datum_t *perm, int effect, int not) {
avtab_key_t key; avtab_key_t key;
int ret = 0; int ret = 0;
if (src == NULL) { if (src == NULL) {
hashtab_for_each(mpdb->p_types.table, { hashtab_for_each(db->p_types.table, {
src = node->datum; 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) { } else if (tgt == NULL) {
hashtab_for_each(mpdb->p_types.table, { hashtab_for_each(db->p_types.table, {
tgt = node->datum; 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) { } else if (cls == NULL) {
hashtab_for_each(mpdb->p_classes.table, { hashtab_for_each(db->p_classes.table, {
cls = node->datum; 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 { } else {
key.source_type = src->s.value; key.source_type = src->s.value;
key.target_type = tgt->s.value; key.target_type = tgt->s.value;
key.target_class = cls->s.value; key.target_class = cls->s.value;
key.specified = effect; 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; 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_driver(x) (x>>8 & 0xFF)
#define ioctl_func(x) (x & 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_datum_t *datum;
avtab_extended_perms_t xperms; 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) if (datum->xperms == NULL)
datum->xperms = xmalloc(sizeof(xperms)); 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; return 0;
} }
static int add_xperm_rule_auto(type_datum_t *src, type_datum_t *tgt, class_datum_t *cls, static int add_xperm_rule_auto(policydb_t *db, type_datum_t *src, type_datum_t *tgt,
uint16_t low, uint16_t high, int effect, int not) { class_datum_t *cls, uint16_t low, uint16_t high, int effect, int not) {
avtab_key_t key; avtab_key_t key;
int ret = 0; int ret = 0;
if (src == NULL) { if (src == NULL) {
hashtab_for_each(mpdb->p_types.table, { hashtab_for_each(db->p_types.table, {
src = node->datum; 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) { } else if (tgt == NULL) {
hashtab_for_each(mpdb->p_types.table, { hashtab_for_each(db->p_types.table, {
tgt = node->datum; 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) { } else if (cls == NULL) {
hashtab_for_each(mpdb->p_classes.table, { hashtab_for_each(db->p_classes.table, {
cls = node->datum; 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 { } else {
key.source_type = src->s.value; key.source_type = src->s.value;
key.target_type = tgt->s.value; key.target_type = tgt->s.value;
key.target_class = cls->s.value; key.target_class = cls->s.value;
key.specified = effect; key.specified = effect;
return add_avxrule(&key, low, high, not); return add_avxrule(db, &key, low, high, not);
} }
return ret; return ret;
} }
int create_domain(const char *d) { int create_domain(policydb_t *db, const char *d) {
symtab_datum_t *src = hashtab_search(mpdb->p_types.table, d); symtab_datum_t *src = hashtab_search(db->p_types.table, d);
if (src) { if (src) {
LOGW("Domain %s already exists\n", d); LOGW("Domain %s already exists\n", d);
return 0; return 0;
@ -233,60 +230,60 @@ int create_domain(const char *d) {
typedatum->flavor = TYPE_TYPE; typedatum->flavor = TYPE_TYPE;
uint32_t value = 0; 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; 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; return 1;
} }
mpdb->type_attr_map = xrealloc(mpdb->type_attr_map, sizeof(ebitmap_t) * mpdb->p_types.nprim); db->type_attr_map = xrealloc(db->type_attr_map, sizeof(ebitmap_t) * db->p_types.nprim);
mpdb->attr_type_map = xrealloc(mpdb->attr_type_map, sizeof(ebitmap_t) * mpdb->p_types.nprim); db->attr_type_map = xrealloc(db->attr_type_map, sizeof(ebitmap_t) * db->p_types.nprim);
ebitmap_init(&mpdb->type_attr_map[value-1]); ebitmap_init(&db->type_attr_map[value-1]);
ebitmap_init(&mpdb->attr_type_map[value-1]); ebitmap_init(&db->attr_type_map[value-1]);
ebitmap_set_bit(&mpdb->type_attr_map[value-1], value-1, 1); ebitmap_set_bit(&db->type_attr_map[value-1], value-1, 1);
src = hashtab_search(mpdb->p_types.table, d); src = hashtab_search(db->p_types.table, d);
if(!src) if (!src)
return 1; return 1;
if(policydb_index_decls(NULL, mpdb)) if (policydb_index_decls(NULL, db))
return 1; return 1;
if(policydb_index_classes(mpdb)) if (policydb_index_classes(db))
return 1; return 1;
if(policydb_index_others(NULL, mpdb, 0)) if (policydb_index_others(NULL, db, 0))
return 1; return 1;
//Add the domain to all roles // Add the domain to all roles
for(unsigned i = 0; i < mpdb->p_roles.nprim; ++i) { for (unsigned i = 0; i < db->p_roles.nprim; ++i) {
//Not sure all those three calls are needed // 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(&db->role_val_to_struct[i]->types.negset, value - 1, 0);
ebitmap_set_bit(&mpdb->role_val_to_struct[i]->types.types, value - 1, 1); ebitmap_set_bit(&db->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); 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; type_datum_t *type;
if (s == NULL) { if (s == NULL) {
hashtab_for_each(mpdb->p_types.table, { hashtab_for_each(db->p_types.table, {
type = node->datum; 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"); LOGW("Could not set bit in permissive map\n");
return 1; return 1;
} }
}) })
} else { } else {
type = hashtab_search(mpdb->p_types.table, s); type = hashtab_search(db->p_types.table, s);
if (type == NULL) { if (type == NULL) {
LOGW("type %s does not exist\n", s); LOGW("type %s does not exist\n", s);
return 1; 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"); LOGW("Could not set bit in permissive map\n");
return 1; return 1;
} }
@ -295,26 +292,27 @@ int set_domain_state(const char *s, int state) {
return 0; 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; type_datum_t *src, *tgt, *def;
class_datum_t *cls; class_datum_t *cls;
src = hashtab_search(mpdb->p_types.table, s); src = hashtab_search(db->p_types.table, s);
if (src == NULL) { if (src == NULL) {
LOGW("source type %s does not exist\n", s); LOGW("source type %s does not exist\n", s);
return 1; return 1;
} }
tgt = hashtab_search(mpdb->p_types.table, t); tgt = hashtab_search(db->p_types.table, t);
if (tgt == NULL) { if (tgt == NULL) {
LOGW("target type %s does not exist\n", t); LOGW("target type %s does not exist\n", t);
return 1; return 1;
} }
cls = hashtab_search(mpdb->p_classes.table, c); cls = hashtab_search(db->p_classes.table, c);
if (cls == NULL) { if (cls == NULL) {
LOGW("class %s does not exist\n", c); LOGW("class %s does not exist\n", c);
return 1; return 1;
} }
def = hashtab_search(mpdb->p_types.table, d); def = hashtab_search(db->p_types.table, d);
if (def == NULL) { if (def == NULL) {
LOGW("default type %s does not exist\n", d); LOGW("default type %s does not exist\n", d);
return 1; 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; trans_key.name = (char *) o;
filename_trans_datum_t *trans_datum; 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) { if (trans_datum == NULL) {
trans_datum = xcalloc(sizeof(*trans_datum), 1); 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 // Overwrite existing
@ -339,18 +337,18 @@ int add_filename_trans(const char *s, const char *t, const char *c, const char *
return 0; return 0;
} }
int add_typeattribute(const char *type, const char *attr) { int add_typeattribute(policydb_t *db, const char *type, const char *attr) {
type_datum_t *domain = hashtab_search(mpdb->p_types.table, type); type_datum_t *domain = hashtab_search(db->p_types.table, type);
if (domain == NULL) { if (domain == NULL) {
LOGW("type %s does not exist\n", type); LOGW("type %s does not exist\n", type);
return 1; 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) if (attr_id < 0)
return 1; return 1;
hashtab_for_each(mpdb->p_classes.table, { hashtab_for_each(db->p_classes.table, {
class_datum_t *cls = node->datum; class_datum_t *cls = node->datum;
for (constraint_node_t *n = cls->constraints; n ; n = n->next) { for (constraint_node_t *n = cls->constraints; n ; n = n->next) {
for (constraint_expr_t *e = n->expr; e; e = e->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; 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; type_datum_t *src = NULL, *tgt = NULL;
class_datum_t *cls = NULL; class_datum_t *cls = NULL;
perm_datum_t *perm = NULL; perm_datum_t *perm = NULL;
if (s) { if (s) {
src = hashtab_search(mpdb->p_types.table, s); src = hashtab_search(db->p_types.table, s);
if (src == NULL) { if (src == NULL) {
LOGW("source type %s does not exist\n", s); LOGW("source type %s does not exist\n", s);
return 1; 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) { if (t) {
tgt = hashtab_search(mpdb->p_types.table, t); tgt = hashtab_search(db->p_types.table, t);
if (tgt == NULL) { if (tgt == NULL) {
LOGW("target type %s does not exist\n", t); LOGW("target type %s does not exist\n", t);
return 1; 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) { if (c) {
cls = hashtab_search(mpdb->p_classes.table, c); cls = hashtab_search(db->p_classes.table, c);
if (cls == NULL) { if (cls == NULL) {
LOGW("class %s does not exist\n", c); LOGW("class %s does not exist\n", c);
return 1; 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 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 add_xperm_rule(policydb_t *db, const char *s, const char *t, const char *c, const char *range,
int n) { int effect, int n) {
type_datum_t *src = NULL, *tgt = NULL; type_datum_t *src = NULL, *tgt = NULL;
class_datum_t *cls = NULL; class_datum_t *cls = NULL;
if (s) { if (s) {
src = hashtab_search(mpdb->p_types.table, s); src = hashtab_search(db->p_types.table, s);
if (src == NULL) { if (src == NULL) {
LOGW("source type %s does not exist\n", s); LOGW("source type %s does not exist\n", s);
return 1; return 1;
@ -426,7 +425,7 @@ int add_xperm_rule(const char *s, const char *t, const char *c, const char *rang
} }
if (t) { if (t) {
tgt = hashtab_search(mpdb->p_types.table, t); tgt = hashtab_search(db->p_types.table, t);
if (tgt == NULL) { if (tgt == NULL) {
LOGW("target type %s does not exist\n", t); LOGW("target type %s does not exist\n", t);
return 1; return 1;
@ -434,7 +433,7 @@ int add_xperm_rule(const char *s, const char *t, const char *c, const char *rang
} }
if (c) { if (c) {
cls = hashtab_search(mpdb->p_classes.table, c); cls = hashtab_search(db->p_classes.table, c);
if (cls == NULL) { if (cls == NULL) {
LOGW("class %s does not exist\n", c); LOGW("class %s does not exist\n", c);
return 1; return 1;
@ -455,29 +454,30 @@ int add_xperm_rule(const char *s, const char *t, const char *c, const char *rang
high = 0xFFFF; 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; type_datum_t *src, *tgt, *def;
class_datum_t *cls; class_datum_t *cls;
src = hashtab_search(mpdb->p_types.table, s); src = hashtab_search(db->p_types.table, s);
if (src == NULL) { if (src == NULL) {
LOGW("source type %s does not exist\n", s); LOGW("source type %s does not exist\n", s);
return 1; return 1;
} }
tgt = hashtab_search(mpdb->p_types.table, t); tgt = hashtab_search(db->p_types.table, t);
if (tgt == NULL) { if (tgt == NULL) {
LOGW("target type %s does not exist\n", t); LOGW("target type %s does not exist\n", t);
return 1; return 1;
} }
cls = hashtab_search(mpdb->p_classes.table, c); cls = hashtab_search(db->p_classes.table, c);
if (cls == NULL) { if (cls == NULL) {
LOGW("class %s does not exist\n", c); LOGW("class %s does not exist\n", c);
return 1; return 1;
} }
def = hashtab_search(mpdb->p_types.table, d); def = hashtab_search(db->p_types.table, d);
if (def == NULL) { if (def == NULL) {
LOGW("default type %s does not exist\n", d); LOGW("default type %s does not exist\n", d);
return 1; 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.target_class = cls->s.value;
key.specified = effect; 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; node->datum.data = def->s.value;
return 0; 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 // First try to create context
context_struct_t *ctx; 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); LOGW("Failed to create context from string [%s]\n", context);
return 1; return 1;
} }
@ -512,7 +512,7 @@ int add_genfscon(const char *name, const char *path, const char *context) {
// Find or allocate genfs // Find or allocate genfs
genfs_t *last_gen = NULL; genfs_t *last_gen = NULL;
genfs_t *newfs = 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) { if (strcmp(node->fstype, name) == 0) {
newfs = node; newfs = node;
break; break;
@ -526,7 +526,7 @@ int add_genfscon(const char *name, const char *path, const char *context) {
if (last_gen) if (last_gen)
last_gen->next = newfs; last_gen->next = newfs;
else else
mpdb->genfs = newfs; db->genfs = newfs;
} }
// Insert or replace genfs context // Insert or replace genfs context
@ -555,9 +555,9 @@ int add_genfscon(const char *name, const char *path, const char *context) {
return 0; return 0;
} }
void strip_dontaudit() { void strip_dontaudit(policydb_t *db) {
avtab_for_each(&mpdb->te_avtab, { avtab_for_each(&db->te_avtab, {
if (node->key.specified == AVTAB_AUDITDENY || node->key.specified == AVTAB_XPERMS_DONTAUDIT) 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);
}) })
} }

View File

@ -4,17 +4,21 @@
__BEGIN_DECLS __BEGIN_DECLS
// Global policydb // Internal C APIs, do not use directly
extern policydb_t *magisk_policydb; 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); void statement_help();
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();
__END_DECLS __END_DECLS

View File

@ -6,42 +6,45 @@
#include <logging.hpp> #include <logging.hpp>
#include <utils.hpp> #include <utils.hpp>
#include "sepolicy.h"
using namespace std; using namespace std;
static const char *type_msg_1 = static const char *type_msg_1 =
R"EOF(Type 1: R"EOF(Type 1:
"<rule_name> source_type target_type class perm_set" "<rule_name> ^source_type ^target_type ^class ^perm_set"
Rules: allow, deny, auditallow, dontaudit Rules: allow, deny, auditallow, dontaudit
)EOF"; )EOF";
static const char *type_msg_2 = static const char *type_msg_2 =
R"EOF(Type 2: R"EOF(Type 2:
"<rule_name> source_type target_type class operation xperm_set" "<rule_name> ^source_type ^target_type ^class operation xperm_set"
Rules: allowxperm, auditallowxperm, dontauditxperm Rules: allowxperm, auditallowxperm, dontauditxperm
* The only supported operation is ioctl - The only supported operation is ioctl
* The only supported xperm_set format is range ([low-high]) - The only supported xperm_set format is range ([low-high])
)EOF"; )EOF";
static const char *type_msg_3 = static const char *type_msg_3 =
R"EOF(Type 3: R"EOF(Type 3:
"<rule_name> class" "<rule_name> type"
Rules: create, permissive, enforcing Rules: create, permissive, enforcing
)EOF"; )EOF";
static const char *type_msg_4 = static const char *type_msg_4 =
R"EOF(Type 4: R"EOF(Type 4:
"attradd class attribute" "typeattribute type attribute"
)EOF"; )EOF";
static const char *type_msg_5 = static const char *type_msg_5 =
R"EOF(Type 5: R"EOF(Type 5:
"<rule_name> source_type target_type class default_type" "<rule_name> source_type target_type class default_type"
Rules: type_transition, type_change, type_member Rules: type_change, type_member
)EOF"; )EOF";
static const char *type_msg_6 = static const char *type_msg_6 =
R"EOF(Type 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"; )EOF";
static const char *type_msg_7 = static const char *type_msg_7 =
@ -52,13 +55,22 @@ R"EOF(Type 7:
void statement_help() { void statement_help() {
fprintf(stderr, fprintf(stderr,
R"EOF(One policy statement should be treated as one parameter; 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. Multiple policy statements can be provided in a single command.
The statements has a format of "<rule_name> [args...]" Statements has a format of "<rule_name> [args...]".
Multiple types and permissions can be grouped into collections Arguments labeled with (^) can accept one or more entries. Multiple
wrapped in curly brackets. entries consist of a space separated list enclosed in braces ({}).
'*' represents a collection containing all valid matches. 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: Supported policy statements:
@ -69,388 +81,193 @@ Supported policy statements:
%s %s
%s %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); )EOF", type_msg_1, type_msg_2, type_msg_3, type_msg_4, type_msg_5, type_msg_6, type_msg_7);
exit(0); exit(0);
} }
static int parse_bracket(char *tok, char *&stmt, vector<const char *> &vec) { static bool tokenize_string(char *stmt, vector<vector<char *>> &arr) {
if (tok == nullptr || tok[0] != '{') { // cur is the pointer to where the top level is parsing
// Not in a bracket char *cur = stmt;
vec.push_back(tok); for (char *tok; (tok = strtok_r(nullptr, " ", &cur)) != nullptr;) {
} else { vector<char *> token;
if (stmt) if (tok[0] == '{') {
stmt[-1] = ' '; // cur could point to somewhere in the braces, restore the string
tok = strchr(tok, '{') + 1; cur[-1] = ' ';
char *end = strchr(tok, '}'); ++tok;
if (end == nullptr) // Bracket not closed char *end = strchr(tok, '}');
return 1; if (end == nullptr) {
*end = '\0'; // Bracket not closed, syntax error
char *cur; LOGE("Unclosed bracket detected\n");
while ((cur = strtok_r(nullptr, " ", &tok)) != nullptr) return false;
vec.push_back(cur); }
stmt = end + 1; *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 } // Pattern 1: action { source } { target } { class } { permission }
static int parse_pattern_1(int action, const char *action_str, char *stmt) { template <typename Func>
int (*action_func)(const char*, const char*, const char*, const char*); static bool parse_pattern_1(Func fn, const char *action, char *stmt) {
switch (action) { vector<vector<char *>> arr;
case 0: if (!tokenize_string(stmt, arr))
action_func = sepol_allow; return false;
break; if (arr.size() != 4)
case 1: return false;
action_func = sepol_deny; for (char *src : arr[0])
break; for (char *tgt : arr[1])
case 2: for (char *cls : arr[2])
action_func = sepol_auditallow; for (char *perm : arr[3])
break; if (fn(src, tgt, cls, perm))
case 3: LOGW("Error in: %s %s %s %s %s\n", action, src, tgt, cls, perm);
action_func = sepol_dontaudit; return true;
break;
default:
return 1;
}
int state = 0;
char *cur, *cls;
vector<const char*> source, target, permission;
while ((cur = strtok_r(nullptr, " ", &stmt)) != nullptr) {
if (cur[0] == '*') cur = ALL;
vector<const char *> *vec;
switch (state) {
case 0:
vec = &source;
break;
case 1:
vec = &target;
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 2: action { source } { target } { class } ioctl range // Pattern 2: action { source } { target } { class } ioctl range
static int parse_pattern_2(int action, const char *action_str, char *stmt) { template <typename Func>
int (*action_func)(const char*, const char*, const char*, const char*); static bool parse_pattern_2(Func fn, const char *action, char *stmt) {
switch (action) { vector<vector<char *>> arr;
case 0: if (!tokenize_string(stmt, arr))
action_func = sepol_allowxperm; return false;
break; if (arr.size() != 5 || arr[3].size() != 1 || arr[3][0] != "ioctl"sv || arr[4].size() != 1)
case 1: return false;
action_func = sepol_auditallowxperm; char *range = arr[4][0];
break; for (char *src : arr[0])
case 2: for (char *tgt : arr[1])
action_func = sepol_dontauditxperm; for (char *cls : arr[2])
break; if (fn(src, tgt, cls, range))
default: LOGW("Error in: %s %s %s %s ioctl %s\n", action, src, tgt, cls, range);
return 1; return true;
}
int state = 0;
char *cur, *range;
vector<const char *> source, target, classes;
while ((cur = strtok_r(nullptr, " ", &stmt)) != nullptr) {
if (cur[0] == '*') cur = ALL;
vector<const char *> *vec;
switch (state) {
case 0:
vec = &source;
break;
case 1:
vec = &target;
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;
} }
// Pattern 3: action { type } // Pattern 3: action { type }
static int parse_pattern_3(int action, const char *action_str, char* stmt) { template <typename Func>
int (*action_func)(const char*); static bool parse_pattern_3(Func fn, const char *action, char *stmt) {
switch (action) { vector<vector<char *>> arr;
case 0: if (!tokenize_string(stmt, arr))
action_func = sepol_create; return false;
break; if (arr.size() != 1)
case 1: return false;
action_func = sepol_permissive; for (char *type : arr[0])
break; if (fn(type))
case 2: LOGW("Error in: %s %s\n", action, type);
action_func = sepol_enforce; return true;
break;
default:
return 1;
}
char *cur;
vector<const char *> 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;
} }
// Pattern 4: action { class } { attribute } // Pattern 4: action { type } { attribute }
static int parse_pattern_4(int action, const char *action_str, char *stmt) { template <typename Func>
int (*action_func)(const char*, const char*); static bool parse_pattern_4(Func fn, const char *action, char *stmt) {
switch (action) { vector<vector<char *>> arr;
case 0: if (!tokenize_string(stmt, arr))
action_func = sepol_attradd; return false;
break; if (arr.size() != 2)
default: return false;
return 1; for (char *type : arr[0])
} for (char *attr : arr[1])
if (fn(type, attr))
int state = 0; LOGW("Error in: %s %s %s\n", action, type, attr);
char *cur; return true;
vector<const char *> classes, attribute;
while ((cur = strtok_r(nullptr, " ", &stmt)) != nullptr) {
if (cur[0] == '*') cur = ALL;
vector<const char *> *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 5: action source target class default // Pattern 5: action source target class default
static int parse_pattern_5(int action, const char *action_str, char *stmt) { template <typename Func>
int (*action_func)(const char*, const char*, const char*, const char*); static bool parse_pattern_5(Func fn, const char *action, char *stmt) {
switch (action) { vector<vector<char *>> arr;
case 0: if (!tokenize_string(stmt, arr))
action_func = sepol_typetrans; return false;
break; if (arr.size() != 4 ||
case 1: arr[0].size() != 1 || arr[1].size() != 1 || arr[2].size() != 1 || arr[3].size() != 1)
action_func = sepol_typechange; return false;
break; if (fn(arr[0][0], arr[1][0], arr[2][0], arr[3][0]))
case 2: LOGW("Error in: %s %s %s %s %s\n", action, arr[0][0], arr[1][0], arr[2][0], arr[3][0]);
action_func = sepol_typemember; return true;
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;
} }
// Pattern 6: action source target class default filename // Pattern 6: action source target class default (filename)
static int parse_pattern_6(int action, const char *action_str, char *stmt) { template <typename Func>
int state = 0; static bool parse_pattern_6(Func fn, const char *action, char *stmt) {
char *cur; vector<vector<char *>> arr;
char *source, *target, *cls, *def, *filename; if (!tokenize_string(stmt, arr))
while ((cur = strtok_r(nullptr, " ", &stmt)) != nullptr) { return false;
switch(state) { if (arr.size() == 4)
case 0: arr.emplace_back(initializer_list<char*>{nullptr});
source = cur; if (arr.size() != 5 ||
break; arr[0].size() != 1 || arr[1].size() != 1 || arr[2].size() != 1 ||
case 1: arr[3].size() != 1 || arr[4].size() != 1)
target = cur; return false;
break; if (fn(arr[0][0], arr[1][0], arr[2][0], arr[3][0], arr[4][0]))
case 2: LOGW("Error in: %s %s %s %s %s %s\n", action,
cls = cur; arr[0][0], arr[1][0], arr[2][0], arr[3][0], arr[4][0] ? arr[4][0] : "");
break; return true;
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 7: action name path context // Pattern 7: action name path context
static int parse_pattern_7(int action, const char *action_str, char *stmt) { template <typename Func>
int state = 0; static bool parse_pattern_7(Func fn, const char *action, char *stmt) {
char *cur; vector<vector<char *>> arr;
char *name, *path, *context; if (!tokenize_string(stmt, arr))
while ((cur = strtok_r(nullptr, " ", &stmt)) != nullptr) { return false;
switch(state) { if (arr.size() != 3 || arr[0].size() != 1 || arr[1].size() != 1 || arr[2].size() != 1)
case 0: return false;
name = cur; if (fn(arr[0][0], arr[1][0], arr[2][0]))
break; LOGW("Error in: %s %s %s %s\n", action, arr[0][0], arr[1][0], arr[2][0]);
case 1: return true;
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;
} }
#define add_action(name, type, num) \ #define add_action_func(name, type, fn) \
else if (strcmp(name, action) == 0) { \ else if (strcmp(name, action) == 0) { \
if (parse_pattern_##type(num, name, remain)) \ auto __fn = [=](auto && ...args){ return (fn)(args...); };\
LOGW("Syntax error in '%s'\n\n%s\n", statement, type_msg_##type); \ 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) { #define add_action(act, type) add_action_func(#act, type, act)
char *action, *remain;
// strtok will modify strings, duplicate the statement void sepolicy::parse_statement(const char *stmt) {
string stmt(statement); // strtok modify strings, create a copy
string cpy(stmt);
action = strtok_r(stmt.data(), " ", &remain);
char *remain;
char *action = strtok_r(cpy.data(), " ", &remain);
if (remain == nullptr) { if (remain == nullptr) {
LOGE("Syntax error in '%s'\n\n", statement); LOGW("Syntax error in '%s'\n\n", stmt);
return; return;
} }
if (0) {} if (0) {}
add_action("allow", 1, 0) add_action(allow, 1)
add_action("deny", 1, 1) add_action(deny, 1)
add_action("auditallow", 1, 2) add_action(auditallow, 1)
add_action("dontaudit", 1, 3) add_action(dontaudit, 1)
add_action("allowxperm", 2, 0) add_action(allowxperm, 2)
add_action("auditallowxperm", 2, 1) add_action(auditallowxperm, 2)
add_action("dontauditxperm", 2, 2) add_action(dontauditxperm, 2)
add_action("create", 3, 0) add_action(create, 3)
add_action("permissive", 3, 1) add_action(permissive, 3)
add_action("enforce", 3, 2) add_action(enforce, 3)
add_action("attradd", 4, 0) add_action(typeattribute, 4)
add_action("type_transition", 5, 0) add_action(type_change, 5)
add_action("type_change", 5, 1) add_action(type_member, 5)
add_action("type_member", 5, 2) add_action(type_transition, 6)
add_action("name_transition", 6, 0) add_action(genfscon, 7)
add_action("genfscon", 7, 0)
else { LOGW("Unknown statement: '%s'\n\n", statement); } // 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) { void sepolicy::load_rule_file(const char *file) {
file_readline(true, file, [](string_view line) -> bool { file_readline(true, file, [=](string_view line) -> bool {
if (line.empty() || line[0] == '#') if (line.empty() || line[0] == '#')
return true; return true;
parse_statement(line.data()); parse_statement(line.data());