Support Android Q new split sepolicy setup

This commit is contained in:
topjohnwu
2019-03-15 06:17:37 -04:00
parent e476c18c99
commit f0240b1f06
9 changed files with 289 additions and 230 deletions

View File

@@ -92,8 +92,9 @@ static const char *type_msg_6 =
"Options:\n"
" --help show help message for policy statements\n"
" --load FILE load policies from FILE\n"
" --compile-split compile and load split cil policies\n"
" from system and vendor just like init\n"
" --load-split load from preloaded sepolicy or compile\n"
" split policies\n"
" --compile-split compile split cil policies\n"
" --save FILE save policies to FILE\n"
" --live directly apply sepolicy live\n"
" --magisk inject built-in rules for a minimal\n"
@@ -460,6 +461,11 @@ int magiskpolicy_main(int argc, char *argv[]) {
return 1;
}
++i;
} else if (strcmp(argv[i] + 2, "load-split") == 0) {
if (load_split_cil()) {
fprintf(stderr, "Cannot load split cil\n");
return 1;
}
} else if (strcmp(argv[i] + 2, "compile-split") == 0) {
if (compile_split_cil()) {
fprintf(stderr, "Cannot compile split cil\n");
@@ -486,12 +492,12 @@ int magiskpolicy_main(int argc, char *argv[]) {
return 1;
}
for (; i < argc; ++i)
parse_statement(argv[i]);
if (magisk)
sepol_magisk_rules();
for (; i < argc; ++i)
parse_statement(argv[i]);
if (live && dump_policydb(SELINUX_LOAD)) {
fprintf(stderr, "Cannot apply policy\n");
return 1;

View File

@@ -5,25 +5,19 @@
#define _MAGISKPOLICY_H
#include <stdlib.h>
#include <selinux.h>
#define ALL NULL
// split policy paths
#define PLAT_POLICY_DIR "/system/etc/selinux/"
#define NONPLAT_POLICY_DIR "/vendor/etc/selinux/"
#define SPLIT_PLAT_CIL PLAT_POLICY_DIR "plat_sepolicy.cil"
#define SPLIT_PLAT_MAPPING PLAT_POLICY_DIR "mapping/%s.cil"
#define SPLIT_PRECOMPILE NONPLAT_POLICY_DIR "precompiled_sepolicy"
#define SPLIT_NONPLAT_VER NONPLAT_POLICY_DIR "plat_sepolicy_vers.txt"
#ifdef __cplusplus
extern "C" {
#endif
// policydb functions
int load_policydb(const char *filename);
int load_policydb(const char *file);
int load_split_cil();
int compile_split_cil();
int dump_policydb(const char *filename);
int dump_policydb(const char *file);
void destroy_policydb();
// Handy functions

View File

@@ -0,0 +1,201 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <cil/cil.h>
#include <utils.h>
#include <logging.h>
#include "magiskpolicy.h"
#include "sepolicy.h"
policydb_t *policydb = nullptr;
int load_policydb(const char *file) {
if (policydb)
destroy_policydb();
struct policy_file pf;
policy_file_init(&pf);
pf.fp = xfopen(file, "re");
pf.type = PF_USE_STDIO;
policydb = new policydb_t();
if (policydb_init(policydb) || policydb_read(policydb, &pf, 0))
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};
char id_b[SHALEN] = {0};
if (int fd = xopen(a, O_RDONLY | O_CLOEXEC); fd >= 0) {
xread(fd, id_a, SHALEN);
close(fd);
} else {
return false;
}
if (int fd = xopen(b, O_RDONLY | O_CLOEXEC); fd >= 0) {
xread(fd, id_b, SHALEN);
close(fd);
} else {
return false;
}
LOGD("%s=[%.*s]\n%s=[%.*s]\n", a, SHALEN, id_a, b, SHALEN, id_b);
return memcmp(id_a, id_b, SHALEN) == 0;
}
static bool check_precompiled(const char *precompiled) {
bool ok = false;
const char *actual_sha;
char compiled_sha[128];
actual_sha = PLAT_POLICY_DIR "plat_and_mapping_sepolicy.cil.sha256";
if (access(actual_sha, R_OK) == 0) {
ok = true;
sprintf(compiled_sha, "%s.plat_and_mapping.sha256", precompiled);
if (!cmp_sha256(actual_sha, compiled_sha))
return false;
}
actual_sha = PLAT_POLICY_DIR "plat_sepolicy_and_mapping.sha256";
if (access(actual_sha, R_OK) == 0) {
ok = true;
sprintf(compiled_sha, "%s.plat_sepolicy_and_mapping.sha256", precompiled);
if (!cmp_sha256(actual_sha, compiled_sha))
return false;
}
actual_sha = PROD_POLICY_DIR "product_sepolicy_and_mapping.sha256";
if (access(actual_sha, R_OK) == 0) {
ok = true;
sprintf(compiled_sha, "%s.product_sepolicy_and_mapping.sha256", precompiled);
if (!cmp_sha256(actual_sha, compiled_sha) != 0)
return false;
}
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;
mmap_ro(file, addr, size);
cil_add_file(db, (char *) file, addr, size);
LOGD("cil_add[%s]\n", file);
munmap(addr, size);
}
int compile_split_cil() {
char path[128], plat_ver[10];
struct cil_db *db = nullptr;
sepol_policydb_t *pdb = nullptr;
FILE *f;
int policy_ver;
const char *cil_file;
cil_db_init(&db);
cil_set_mls(db, 1);
cil_set_multiple_decls(db, 1);
cil_set_disable_neverallow(db, 1);
cil_set_target_platform(db, SEPOL_TARGET_SELINUX);
cil_set_attrs_expand_generated(db, 0);
f = xfopen(SELINUX_VERSION, "re");
fscanf(f, "%d", &policy_ver);
fclose(f);
cil_set_policy_version(db, policy_ver);
// Get mapping version
f = xfopen(VEND_POLICY_DIR "plat_sepolicy_vers.txt", "re");
fscanf(f, "%s", plat_ver);
fclose(f);
// plat
load_cil(db, SPLIT_PLAT_CIL);
sprintf(path, PLAT_POLICY_DIR "mapping/%s.cil", plat_ver);
load_cil(db, path);
// product
sprintf(path, PROD_POLICY_DIR "mapping/%s.cil", plat_ver);
if (access(path, R_OK) == 0)
load_cil(db, path);
cil_file = PROD_POLICY_DIR "product_sepolicy.cil";
if (access(cil_file, R_OK) == 0)
load_cil(db, cil_file);
// vendor
cil_file = VEND_POLICY_DIR "nonplat_sepolicy.cil";
if (access(cil_file, R_OK) == 0)
load_cil(db, cil_file);
cil_file = VEND_POLICY_DIR "plat_pub_versioned.cil";
if (access(cil_file, R_OK) == 0)
load_cil(db, cil_file);
cil_file = VEND_POLICY_DIR "vendor_sepolicy.cil";
if (access(cil_file, R_OK) == 0)
load_cil(db, cil_file);
// odm
cil_file = ODM_POLICY_DIR "odm_sepolicy.cil";
if (access(cil_file, R_OK) == 0)
load_cil(db, cil_file);
if (cil_compile(db))
return 1;
if (cil_build_policydb(db, &pdb))
return 1;
cil_db_destroy(&db);
policydb = &pdb->p;
return 0;
}
int dump_policydb(const char *file) {
int fd, ret;
void *data = nullptr;
size_t len;
policydb_to_image(nullptr, policydb, &data, &len);
if (data == nullptr) {
LOGE("Fail to dump policy image!\n");
return 1;
}
fd = xopen(file, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644);
if (fd < 0)
return 1;
ret = xwrite(fd, data, len);
close(fd);
if (ret < 0)
return 1;
return 0;
}
void destroy_policydb() {
if (policydb) {
policydb_destroy(policydb);
delete policydb;
policydb = nullptr;
}
}

View File

@@ -1,23 +1,5 @@
#include <dirent.h>
#include <getopt.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <limits.h>
#include <string.h>
#include <cil/cil.h>
#include <sepol/debug.h>
#include <sepol/policydb/policydb.h>
#include <sepol/policydb/expand.h>
#include <sepol/policydb/link.h>
#include <sepol/policydb/services.h>
#include <sepol/policydb/avrule_block.h>
#include <sepol/policydb/conditional.h>
#include <sepol/policydb/constraint.h>
#include <utils.h>
#include <logging.h>
@@ -25,7 +7,6 @@
#include "magiskpolicy.h"
#include "sepolicy.h"
policydb_t *policydb = NULL;
extern int policydb_index_decls(sepol_handle_t * handle, policydb_t * p);
static int get_attr(const char *type, int value) {
@@ -235,129 +216,6 @@ static int add_xperm_rule_auto(type_datum_t *src, type_datum_t *tgt, class_datum
return ret;
}
int load_policydb(const char *filename) {
struct policy_file pf;
void *map;
size_t size;
int ret;
if (policydb)
destroy_policydb();
policydb = xcalloc(sizeof(*policydb), 1);
mmap_ro(filename, &map, &size);
policy_file_init(&pf);
pf.type = PF_USE_MEMORY;
pf.data = map;
pf.len = size;
if (policydb_init(policydb)) {
LOGE("policydb_init: Out of memory!\n");
return 1;
}
ret = policydb_read(policydb, &pf, 0);
if (ret) {
LOGE("error(s) encountered while parsing configuration\n");
return 1;
}
munmap(map, size);
return 0;
}
int compile_split_cil() {
DIR *dir;
struct dirent *entry;
char path[128];
struct cil_db *db = NULL;
sepol_policydb_t *pdb = NULL;
void *addr;
size_t size;
cil_db_init(&db);
cil_set_mls(db, 1);
cil_set_multiple_decls(db, 1);
cil_set_disable_neverallow(db, 1);
cil_set_target_platform(db, SEPOL_TARGET_SELINUX);
cil_set_policy_version(db, POLICYDB_VERSION_XPERMS_IOCTL);
cil_set_attrs_expand_generated(db, 0);
// plat
mmap_ro(SPLIT_PLAT_CIL, &addr, &size);
if (cil_add_file(db, SPLIT_PLAT_CIL, addr, size))
return 1;
LOGD("cil_add[%s]\n", SPLIT_PLAT_CIL);
munmap(addr, size);
// mapping
char plat[10];
int fd = open(SPLIT_NONPLAT_VER, O_RDONLY | O_CLOEXEC);
plat[read(fd, plat, sizeof(plat)) - 1] = '\0';
sprintf(path, SPLIT_PLAT_MAPPING, plat);
mmap_ro(path, &addr, &size);
if (cil_add_file(db, path, addr, size))
return 1;
LOGD("cil_add[%s]\n", path);
munmap(addr, size);
close(fd);
// nonplat
dir = opendir(NONPLAT_POLICY_DIR);
while ((entry = readdir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
if (strend(entry->d_name, ".cil") == 0) {
sprintf(path, NONPLAT_POLICY_DIR "%s", entry->d_name);
mmap_ro(path, &addr, &size);
if (cil_add_file(db, path, addr, size))
return 1;
LOGD("cil_add[%s]\n", path);
munmap(addr, size);
}
}
closedir(dir);
if (cil_compile(db))
return 1;
if (cil_build_policydb(db, &pdb))
return 1;
cil_db_destroy(&db);
policydb = &pdb->p;
return 0;
}
int dump_policydb(const char *filename) {
int fd, ret;
void *data = NULL;
size_t len;
policydb_to_image(NULL, policydb, &data, &len);
if (data == NULL) {
LOGE("Fail to dump policy image!\n");
return 1;
}
fd = creat(filename, 0644);
if (fd < 0) {
LOGE("Can't open '%s': %s\n", filename, strerror(errno));
return 1;
}
ret = xwrite(fd, data, len);
close(fd);
if (ret < 0)
return 1;
return 0;
}
void destroy_policydb() {
policydb_destroy(policydb);
free(policydb);
policydb = NULL;
}
int create_domain(const char *d) {
symtab_datum_t *src = hashtab_search(policydb->p_types.table, d);
if(src) {