diff --git a/native/jni/include/magiskpolicy.h b/native/jni/include/magiskpolicy.h index c3927bc40..bb484564f 100644 --- a/native/jni/include/magiskpolicy.h +++ b/native/jni/include/magiskpolicy.h @@ -28,6 +28,7 @@ int sepol_create(const char *s); int sepol_permissive(const char *s); int sepol_enforce(const char *s); int sepol_attradd(const char *s, const char *a); +int sepol_genfscon(const char *name, const char *path, const char *context); int sepol_exists(const char *source); // Built in rules diff --git a/native/jni/magiskpolicy/api.cpp b/native/jni/magiskpolicy/api.cpp index e65a238dd..896ee0846 100644 --- a/native/jni/magiskpolicy/api.cpp +++ b/native/jni/magiskpolicy/api.cpp @@ -80,6 +80,11 @@ int sepol_attradd(const char *s, const char *a) { return add_typeattribute(s, a); } +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 sepol_exists(const char *source) { return hashtab_search(magisk_policydb->p_types.table, source) != nullptr; } diff --git a/native/jni/magiskpolicy/sepolicy.c b/native/jni/magiskpolicy/sepolicy.c index 6b9cd6fad..c94a2bae3 100644 --- a/native/jni/magiskpolicy/sepolicy.c +++ b/native/jni/magiskpolicy/sepolicy.c @@ -11,18 +11,25 @@ policydb_t *magisk_policydb = NULL; extern void *xmalloc(size_t size); extern void *xcalloc(size_t nmemb, size_t size); extern void *xrealloc(void *ptr, size_t size); + +// Internal libsepol APIs extern int policydb_index_decls(sepol_handle_t * handle, policydb_t * p); +extern int context_from_string( + sepol_handle_t * handle, + const policydb_t * policydb, + context_struct_t ** cptr, + const char *con_str, size_t con_str_len); // Generic hash table traversal #define hash_for_each(node_ptr, n_slots, table, block) \ - for (int __i = 0; __i < (table)->n_slots; ++__i) { \ - __typeof__(*(table)->node_ptr) node; \ - __typeof__(node) __next; \ - for (node = (table)->node_ptr[__i]; node; node = __next) { \ - __next = node->next; \ - block \ - } \ +for (int __i = 0; __i < (table)->n_slots; ++__i) { \ + __typeof__(*(table)->node_ptr) node; \ + __typeof__(node) __next; \ + for (node = (table)->node_ptr[__i]; node; node = __next) { \ + __next = node->next; \ + block \ } \ +} // hashtab traversal #define hashtab_for_each(hashtab, block) \ @@ -488,6 +495,66 @@ int add_type_rule(const char *s, const char *t, const char *c, const char *d, in return 0; } +int add_genfscon(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))) { + LOGW("Failed to create context from string [%s]\n", context); + return 1; + } + + // Allocate genfs context + ocontext_t *newc = xcalloc(sizeof(*newc), 1); + newc->u.name = strdup(path); + memcpy(&newc->context[0], ctx, sizeof(*ctx)); + free(ctx); + + // Find or allocate genfs + genfs_t *last_gen = NULL; + genfs_t *newfs = NULL; + for (genfs_t *node = mpdb->genfs; node; node = node->next) { + if (strcmp(node->fstype, name) == 0) { + newfs = node; + break; + } + last_gen = node; + } + if (newfs == NULL) { + newfs = xcalloc(sizeof(*newfs), 1); + newfs->fstype = strdup(name); + // Insert + if (last_gen) + last_gen->next = newfs; + else + mpdb->genfs = newfs; + } + + // Insert or replace genfs context + ocontext_t *last_ctx = NULL; + for (ocontext_t *node = newfs->head; node; node = node->next) { + if (strcmp(node->u.name, path) == 0) { + // Unlink + if (last_ctx) + last_ctx->next = node->next; + else + newfs->head = NULL; + // Destroy old node + free(node->u.name); + context_destroy(&node->context[0]); + free(node); + break; + } + last_ctx = node; + } + // Insert + if (last_ctx) + last_ctx->next = newc; + else + newfs->head = newc; + + return 0; +} + void strip_dontaudit() { avtab_for_each(&mpdb->te_avtab, { if (node->key.specified == AVTAB_AUDITDENY || node->key.specified == AVTAB_XPERMS_DONTAUDIT) diff --git a/native/jni/magiskpolicy/sepolicy.h b/native/jni/magiskpolicy/sepolicy.h index ecff77ef0..7d6859c73 100644 --- a/native/jni/magiskpolicy/sepolicy.h +++ b/native/jni/magiskpolicy/sepolicy.h @@ -14,6 +14,7 @@ int add_rule(const char *s, const char *t, const char *c, const char *p, int eff 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 diff --git a/native/jni/magiskpolicy/statement.cpp b/native/jni/magiskpolicy/statement.cpp index 43f8b8bff..cfda7b900 100644 --- a/native/jni/magiskpolicy/statement.cpp +++ b/native/jni/magiskpolicy/statement.cpp @@ -44,6 +44,11 @@ R"EOF(Type 6: "name_transition source_type target_type class default_type object_name" )EOF"; +static const char *type_msg_7 = +R"EOF(Type 7: +"genfscon fs_name partial_path fs_context" +)EOF"; + void statement_help() { fprintf(stderr, R"EOF(One policy statement should be treated as one parameter; @@ -63,8 +68,9 @@ Supported policy statements: %s %s %s +%s Notes: -* Type 4 - 6 does not support collections +* Type 4 - 7 does not support collections * Object classes cannot be collections * source_type and target_type can also be attributes @@ -76,7 +82,7 @@ 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); +)EOF", type_msg_1, type_msg_2, type_msg_3, type_msg_4, type_msg_5, type_msg_6, type_msg_7); exit(0); } @@ -371,12 +377,39 @@ static int parse_pattern_6(int action, const char *action_str, char *stmt) { } ++state; } - if (state < 4) return 1; + if (state < 5) return 1; if (sepol_nametrans(source, target, cls, def, filename)) LOGW("Error in: %s %s %s %s %s %s\n", action_str, source, target, cls, def, filename); return 0; } +// Pattern 7: action name path context +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; +} + #define add_action(name, type, num) \ else if (strcmp(name, action) == 0) { \ if (parse_pattern_##type(num, name, remain)) \ @@ -412,6 +445,7 @@ void parse_statement(const char *statement) { 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); } }