Commit d4baae41 authored by topjohnwu's avatar topjohnwu

Modernize magiskpolicy

parent e02e46d0
...@@ -3,38 +3,55 @@ ...@@ -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(); class sepolicy {
int compile_split_cil(); public:
int dump_policydb(const char *file); typedef const char * c_str;
void destroy_policydb(); ~sepolicy();
// Handy functions // Public static factory functions
int sepol_allow(const char *s, const char *t, const char *c, const char *p); static sepolicy *from_file(c_str file);
int sepol_deny(const char *s, const char *t, const char *c, const char *p); static sepolicy *from_split();
int sepol_auditallow(const char *s, const char *t, const char *c, const char *p); static sepolicy *compile_split();
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); // External APIs
int sepol_typechange(const char *s, const char *t, const char *c, const char *d); int to_file(c_str file);
int sepol_typemember(const char *s, const char *t, const char *c, const char *d); void parse_statement(c_str stmt);
int sepol_nametrans(const char *s, const char *t, const char *c, const char *d, const char *o); void load_rule_file(c_str file);
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); // Operation on types
int sepol_dontauditxperm(const char *s, const char *t, const char *c, const char *range); int create(c_str type);
int sepol_create(const char *s); int permissive(c_str type);
int sepol_permissive(const char *s); int enforce(c_str type);
int sepol_enforce(const char *s); int typeattribute(c_str type, c_str attr);
int sepol_attradd(const char *s, const char *a); int exists(c_str type);
int sepol_genfscon(const char *name, const char *path, const char *context);
int sepol_exists(const char *source); // Access vector rules
int allow(c_str src, c_str tgt, c_str cls, c_str perm);
// Built in rules int deny(c_str src, c_str tgt, c_str cls, c_str perm);
void sepol_magisk_rules(); 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);
// Statement parsing
void parse_statement(const char *statement); // Extended permissions access vector rules
void load_rule_file(const char *file); int allowxperm(c_str src, c_str tgt, c_str cls, c_str range);
void statement_help(); 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;
};
...@@ -129,13 +129,14 @@ void RootFSInit::setup_rootfs() { ...@@ -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) { ...@@ -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) { ...@@ -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) {
......
...@@ -5,86 +5,86 @@ ...@@ -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;
} }
...@@ -40,6 +40,7 @@ int magiskpolicy_main(int argc, char *argv[]) { ...@@ -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[]) { ...@@ -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[]) { ...@@ -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;
} }
...@@ -12,26 +12,6 @@ ...@@ -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) { ...@@ -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) { ...@@ -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() { ...@@ -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;
}
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 dump_policydb(const char *file) { 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) { ...@@ -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;
}
}
This diff is collapsed.
This diff is collapsed.
...@@ -4,17 +4,21 @@ ...@@ -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
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment