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 <selinux.hpp>
#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;
};

View File

@ -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) {

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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<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
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<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];
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<byte_stream>(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<byte_stream>(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;
}
}

View File

@ -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;

View File

@ -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);
})
}

View File

@ -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

View File

@ -6,42 +6,45 @@
#include <logging.hpp>
#include <utils.hpp>
#include "sepolicy.h"
using namespace std;
static const char *type_msg_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
)EOF";
static const char *type_msg_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
* 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:
"<rule_name> class"
"<rule_name> 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:
"<rule_name> 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 "<rule_name> [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 "<rule_name> [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<const char *> &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<vector<char *>> &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<char *> 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<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 1: action { source } { target } { class } { permission }
template <typename Func>
static bool parse_pattern_1(Func fn, const char *action, char *stmt) {
vector<vector<char *>> 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<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;
template <typename Func>
static bool parse_pattern_2(Func fn, const char *action, char *stmt) {
vector<vector<char *>> 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<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;
template <typename Func>
static bool parse_pattern_3(Func fn, const char *action, char *stmt) {
vector<vector<char *>> 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<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 4: action { type } { attribute }
template <typename Func>
static bool parse_pattern_4(Func fn, const char *action, char *stmt) {
vector<vector<char *>> 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 <typename Func>
static bool parse_pattern_5(Func fn, const char *action, char *stmt) {
vector<vector<char *>> 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 <typename Func>
static bool parse_pattern_6(Func fn, const char *action, char *stmt) {
vector<vector<char *>> arr;
if (!tokenize_string(stmt, arr))
return false;
if (arr.size() == 4)
arr.emplace_back(initializer_list<char*>{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 <typename Func>
static bool parse_pattern_7(Func fn, const char *action, char *stmt) {
vector<vector<char *>> 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());