mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-11-24 02:25:28 +00:00
Support new sepolicy rules
Support declare new type with attribute and declare new attributes
This commit is contained in:
parent
cd6eca1dc2
commit
4499cebcd9
@ -23,7 +23,8 @@ public:
|
||||
void load_rule_file(c_str file);
|
||||
|
||||
// Operation on types
|
||||
bool create(c_str type);
|
||||
bool type(c_str name, c_str attr);
|
||||
bool attribute(c_str name);
|
||||
bool permissive(c_str type);
|
||||
bool enforce(c_str type);
|
||||
bool typeattribute(c_str type, c_str attr);
|
||||
@ -51,6 +52,9 @@ public:
|
||||
// Magisk
|
||||
void magisk_rules();
|
||||
|
||||
// Deprecate
|
||||
bool create(c_str name) { return type(name, "domain"); }
|
||||
|
||||
protected:
|
||||
policydb *db;
|
||||
};
|
||||
|
@ -513,7 +513,7 @@ bool sepol_impl::add_genfscon(const char *fs_name, const char *path, const char
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sepol_impl::create_domain(const char *type_name) {
|
||||
bool sepol_impl::add_type(const char *type_name, uint32_t flavor) {
|
||||
type_datum_t *type = hashtab_find(db->p_types.table, type_name);
|
||||
if (type) {
|
||||
LOGW("Type %s already exists\n", type_name);
|
||||
@ -523,7 +523,7 @@ bool sepol_impl::create_domain(const char *type_name) {
|
||||
type = auto_cast(xmalloc(sizeof(type_datum_t)));
|
||||
type_datum_init(type);
|
||||
type->primary = 1;
|
||||
type->flavor = TYPE_TYPE;
|
||||
type->flavor = flavor;
|
||||
|
||||
uint32_t value = 0;
|
||||
if (symtab_insert(db, SYM_TYPES, strdup(type_name), type, SCOPE_DECL, 1, &value))
|
||||
@ -551,22 +551,21 @@ bool sepol_impl::create_domain(const char *type_name) {
|
||||
type_set_expand(&db->role_val_to_struct[i]->types, &db->role_val_to_struct[i]->cache, db, 0);
|
||||
}
|
||||
|
||||
set_attr("domain", value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sepol_impl::set_domain_state(const char *s, bool permissive) {
|
||||
bool sepol_impl::set_type_state(const char *type_name, bool permissive) {
|
||||
type_datum_t *type;
|
||||
if (s == nullptr) {
|
||||
if (type_name == nullptr) {
|
||||
hashtab_for_each(db->p_types.table, [&](hashtab_ptr_t node) {
|
||||
type = auto_cast(node->datum);
|
||||
if (ebitmap_set_bit(&db->permissive_map, type->s.value, permissive))
|
||||
LOGW("Could not set bit in permissive map\n");
|
||||
});
|
||||
} else {
|
||||
type = hashtab_find(db->p_types.table, s);
|
||||
type = hashtab_find(db->p_types.table, type_name);
|
||||
if (type == nullptr) {
|
||||
LOGW("type %s does not exist\n", s);
|
||||
LOGW("type %s does not exist\n", type_name);
|
||||
return false;
|
||||
}
|
||||
if (ebitmap_set_bit(&db->permissive_map, type->s.value, permissive)) {
|
||||
@ -577,28 +576,43 @@ bool sepol_impl::set_domain_state(const char *s, bool permissive) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sepol_impl::add_typeattribute(const char *type, const char *attr) {
|
||||
type_datum_t *domain = hashtab_find(db->p_types.table, type);
|
||||
if (domain == nullptr) {
|
||||
LOGW("type %s does not exist\n", type);
|
||||
return false;
|
||||
}
|
||||
|
||||
int attr_val = set_attr(attr, domain->s.value);
|
||||
if (attr_val < 0)
|
||||
return false;
|
||||
void sepol_impl::add_typeattribute(type_datum_t *type, type_datum_t *attr) {
|
||||
ebitmap_set_bit(&db->type_attr_map[type->s.value - 1], attr->s.value - 1, 1);
|
||||
ebitmap_set_bit(&db->attr_type_map[attr->s.value - 1], type->s.value - 1, 1);
|
||||
|
||||
hashtab_for_each(db->p_classes.table, [&](hashtab_ptr_t node){
|
||||
auto cls = static_cast<class_datum_t *>(node->datum);
|
||||
for (constraint_node_t *n = cls->constraints; n ; n = n->next) {
|
||||
for (constraint_expr_t *e = n->expr; e; e = e->next) {
|
||||
if (e->expr_type == CEXPR_NAMES &&
|
||||
ebitmap_get_bit(&e->type_names->types, attr_val - 1)) {
|
||||
ebitmap_set_bit(&e->names, domain->s.value - 1, 1);
|
||||
ebitmap_get_bit(&e->type_names->types, attr->s.value - 1)) {
|
||||
ebitmap_set_bit(&e->names, type->s.value - 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool sepol_impl::add_typeattribute(const char *type, const char *attr) {
|
||||
type_datum_t *type_d = hashtab_find(db->p_types.table, type);
|
||||
if (type_d == nullptr) {
|
||||
LOGW("type %s does not exist\n", type);
|
||||
return false;
|
||||
} else if (type_d->flavor == TYPE_ATTRIB) {
|
||||
LOGW("type %s is an attribute\n", attr);
|
||||
return false;
|
||||
}
|
||||
|
||||
type_datum *attr_d = hashtab_find(db->p_types.table, attr);
|
||||
if (attr_d == nullptr) {
|
||||
LOGW("attribute %s does not exist\n", type);
|
||||
return false;
|
||||
} else if (attr_d->flavor != TYPE_ATTRIB) {
|
||||
LOGW("type %s is not an attribute \n", attr);
|
||||
return false;
|
||||
}
|
||||
|
||||
add_typeattribute(type_d, attr_d);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -666,17 +680,22 @@ bool sepolicy::type_transition(const char *s, const char *t, const char *c, cons
|
||||
|
||||
bool sepolicy::permissive(const char *s) {
|
||||
dprint(__FUNCTION__, s);
|
||||
return impl->set_domain_state(s, true);
|
||||
return impl->set_type_state(s, true);
|
||||
}
|
||||
|
||||
bool sepolicy::enforce(const char *s) {
|
||||
dprint(__FUNCTION__, s);
|
||||
return impl->set_domain_state(s, false);
|
||||
return impl->set_type_state(s, false);
|
||||
}
|
||||
|
||||
bool sepolicy::create(const char *s) {
|
||||
dprint(__FUNCTION__, s);
|
||||
return impl->create_domain(s);
|
||||
bool sepolicy::type(const char *name, const char *attr) {
|
||||
dprint(__FUNCTION__, name, attr);
|
||||
return impl->add_type(name, TYPE_TYPE) && impl->add_typeattribute(name, attr);
|
||||
}
|
||||
|
||||
bool sepolicy::attribute(const char *name) {
|
||||
dprint(__FUNCTION__, name);
|
||||
return impl->add_type(name, TYPE_ATTRIB);
|
||||
}
|
||||
|
||||
bool sepolicy::typeattribute(const char *type, const char *attr) {
|
||||
|
@ -16,8 +16,9 @@ struct sepol_impl : public sepolicy {
|
||||
bool add_type_rule(const char *s, const char *t, const char *c, const char *d, int effect);
|
||||
bool add_filename_trans(const char *s, const char *t, const char *c, const char *d, const char *o);
|
||||
bool add_genfscon(const char *fs_name, const char *path, const char *context);
|
||||
bool create_domain(const char *type_name);
|
||||
bool set_domain_state(const char *s, bool permissive);
|
||||
bool add_type(const char *type_name, uint32_t flavor);
|
||||
bool set_type_state(const char *type_name, bool permissive);
|
||||
void add_typeattribute(type_datum_t *type, type_datum_t *attr);
|
||||
bool add_typeattribute(const char *type, const char *attr);
|
||||
void strip_dontaudit();
|
||||
void allow_su_client(const char *type);
|
||||
|
@ -11,45 +11,52 @@
|
||||
using namespace std;
|
||||
|
||||
static const char *type_msg_1 =
|
||||
R"EOF(Type 1:
|
||||
"<rule_name> ^source_type ^target_type ^class ^perm_set"
|
||||
Rules: allow, deny, auditallow, dontaudit
|
||||
R"EOF("allow *source_type *target_type *class *perm_set"
|
||||
"deny *source_type *target_type *class *perm_set"
|
||||
"auditallow *source_type *target_type *class *perm_set"
|
||||
"dontaudit *source_type *target_type *class *perm_set"
|
||||
)EOF";
|
||||
|
||||
static const char *type_msg_2 =
|
||||
R"EOF(Type 2:
|
||||
"<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])
|
||||
R"EOF("allowxperm *source_type *target_type *class operation xperm_set"
|
||||
"auditallowxperm *source_type *target_type *class operation xperm_set"
|
||||
"dontauditxperm *source_type *target_type *class operation xperm_set"
|
||||
- The only supported operation is 'ioctl'
|
||||
- xperm_set format is either 'low-high', 'value', or '*'.
|
||||
'*' will be treated as '0x0000-0xFFFF'.
|
||||
All values should be written in hexadecimal.
|
||||
)EOF";
|
||||
|
||||
static const char *type_msg_3 =
|
||||
R"EOF(Type 3:
|
||||
"<rule_name> ^type"
|
||||
Rules: create, permissive, enforcing
|
||||
R"EOF("permissive ^type"
|
||||
"enforce ^type"
|
||||
)EOF";
|
||||
|
||||
static const char *type_msg_4 =
|
||||
R"EOF(Type 4:
|
||||
"typeattribute ^type ^attribute"
|
||||
R"EOF("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_change, type_member
|
||||
R"EOF("type type_name ^(attribute)"
|
||||
- Argument 'attribute' is optional, default to 'domain'
|
||||
)EOF";
|
||||
|
||||
static const char *type_msg_6 =
|
||||
R"EOF(Type 6:
|
||||
"type_transition source_type target_type class default_type (object_name)"
|
||||
- Entry 'object_name' is optional
|
||||
R"EOF("attribute attribute_name"
|
||||
)EOF";
|
||||
|
||||
static const char *type_msg_7 =
|
||||
R"EOF(Type 7:
|
||||
"genfscon fs_name partial_path fs_context"
|
||||
R"EOF("type_transition source_type target_type class default_type (object_name)"
|
||||
- Argument 'object_name' is optional
|
||||
)EOF";
|
||||
|
||||
static const char *type_msg_8 =
|
||||
R"EOF("type_change source_type target_type class default_type"
|
||||
"type_member source_type target_type class default_type"
|
||||
)EOF";
|
||||
|
||||
static const char *type_msg_9 =
|
||||
R"EOF("genfscon fs_name partial_path fs_context"
|
||||
)EOF";
|
||||
|
||||
void statement_help() {
|
||||
@ -61,8 +68,8 @@ Multiple policy statements can be provided in a single command.
|
||||
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.
|
||||
Arguments labeled with (*) are the same as (^), but additionally
|
||||
support the match-all operator (*).
|
||||
|
||||
Example: "allow { s1 s2 } { t1 t2 } class *"
|
||||
Will be expanded to:
|
||||
@ -81,15 +88,20 @@ Supported policy statements:
|
||||
%s
|
||||
%s
|
||||
%s
|
||||
)EOF", type_msg_1, type_msg_2, type_msg_3, type_msg_4, type_msg_5, type_msg_6, type_msg_7);
|
||||
%s
|
||||
%s
|
||||
)EOF", type_msg_1, type_msg_2, type_msg_3, type_msg_4,
|
||||
type_msg_5, type_msg_6, type_msg_7, type_msg_8, type_msg_9);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static bool tokenize_string(char *stmt, vector<vector<char *>> &arr) {
|
||||
using parsed_tokens = vector<vector<const char *>>;
|
||||
|
||||
static bool tokenize_string(char *stmt, parsed_tokens &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;
|
||||
vector<const char *> token;
|
||||
if (tok[0] == '{') {
|
||||
// cur could point to somewhere in the braces, restore the string
|
||||
if (cur)
|
||||
@ -116,7 +128,7 @@ static bool tokenize_string(char *stmt, vector<vector<char *>> &arr) {
|
||||
|
||||
// Check array size and all args listed in 'ones' have size = 1 (no multiple entries)
|
||||
template <int size, int ...ones>
|
||||
static bool check_tokens(vector<vector<char *>> &arr) {
|
||||
static bool check_tokens(parsed_tokens &arr) {
|
||||
if (arr.size() != size)
|
||||
return false;
|
||||
initializer_list<int> list{ones...};
|
||||
@ -127,7 +139,7 @@ static bool check_tokens(vector<vector<char *>> &arr) {
|
||||
}
|
||||
|
||||
template <int size, int ...ones>
|
||||
static bool tokenize_and_check(char *stmt, vector<vector<char *>> &arr) {
|
||||
static bool tokenize_and_check(char *stmt, parsed_tokens &arr) {
|
||||
return tokenize_string(stmt, arr) && check_tokens<size, ones...>(arr);
|
||||
}
|
||||
|
||||
@ -143,85 +155,112 @@ static void run_and_check(const Func &fn, const char *action, Args ...args) {
|
||||
|
||||
#define run_fn(...) run_and_check(fn, action, __VA_ARGS__)
|
||||
|
||||
// Pattern 1: action { source } { target } { class } { permission }
|
||||
// Pattern 1: allow { source } { target } { class } { permission }
|
||||
template <typename Func>
|
||||
static bool parse_pattern_1(const Func &fn, const char *action, char *stmt) {
|
||||
vector<vector<char *>> arr;
|
||||
parsed_tokens arr;
|
||||
if (!tokenize_and_check<4>(stmt, arr))
|
||||
return false;
|
||||
for (char *src : arr[0])
|
||||
for (char *tgt : arr[1])
|
||||
for (char *cls : arr[2])
|
||||
for (char *perm : arr[3])
|
||||
for (auto src : arr[0])
|
||||
for (auto tgt : arr[1])
|
||||
for (auto cls : arr[2])
|
||||
for (auto perm : arr[3])
|
||||
run_fn(src, tgt, cls, perm);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Pattern 2: action { source } { target } { class } ioctl range
|
||||
// Pattern 2: allowxperm { source } { target } { class } ioctl range
|
||||
template <typename Func>
|
||||
static bool parse_pattern_2(const Func &fn, const char *action, char *stmt) {
|
||||
vector<vector<char *>> arr;
|
||||
parsed_tokens arr;
|
||||
if (!tokenize_and_check<5, 3, 4>(stmt, arr) || arr[3][0] != "ioctl"sv)
|
||||
return false;
|
||||
char *range = arr[4][0];
|
||||
for (char *src : arr[0])
|
||||
for (char *tgt : arr[1])
|
||||
for (char *cls : arr[2])
|
||||
auto range = arr[4][0];
|
||||
for (auto src : arr[0])
|
||||
for (auto tgt : arr[1])
|
||||
for (auto cls : arr[2])
|
||||
run_fn(src, tgt, cls, range);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Pattern 3: action { type }
|
||||
// Pattern 3: permissive { type }
|
||||
template <typename Func>
|
||||
static bool parse_pattern_3(const Func &fn, const char *action, char *stmt) {
|
||||
vector<vector<char *>> arr;
|
||||
parsed_tokens arr;
|
||||
if (!tokenize_and_check<1>(stmt, arr))
|
||||
return false;
|
||||
for (char *type : arr[0])
|
||||
for (auto type : arr[0])
|
||||
run_fn(type);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Pattern 4: action { type } { attribute }
|
||||
// Pattern 4: typeattribute { type } { attribute }
|
||||
template <typename Func>
|
||||
static bool parse_pattern_4(const Func &fn, const char *action, char *stmt) {
|
||||
vector<vector<char *>> arr;
|
||||
parsed_tokens arr;
|
||||
if (!tokenize_and_check<2>(stmt, arr))
|
||||
return false;
|
||||
for (char *type : arr[0])
|
||||
for (char *attr : arr[1])
|
||||
for (auto type : arr[0])
|
||||
for (auto attr : arr[1])
|
||||
run_fn(type, attr);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Pattern 5: action source target class default
|
||||
// Pattern 5: type name { attribute }
|
||||
template <typename Func>
|
||||
static bool parse_pattern_5(const Func &fn, const char *action, char *stmt) {
|
||||
vector<vector<char *>> arr;
|
||||
if (!tokenize_and_check<4, 0, 1, 2, 3>(stmt, arr))
|
||||
parsed_tokens arr;
|
||||
string tmp_str;
|
||||
if (!tokenize_string(stmt, arr))
|
||||
return false;
|
||||
run_fn(arr[0][0], arr[1][0], arr[2][0], arr[3][0]);
|
||||
if (arr.size() == 1) {
|
||||
arr.emplace_back(initializer_list<const char*>{ "domain" });
|
||||
}
|
||||
if (!check_tokens<2, 0>(arr))
|
||||
return false;
|
||||
for (auto attr : arr[1])
|
||||
run_fn(arr[0][0], attr);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Pattern 6: action source target class default (filename)
|
||||
// Pattern 6: attribute name
|
||||
template <typename Func>
|
||||
static bool parse_pattern_6(const Func &fn, const char *action, char *stmt) {
|
||||
vector<vector<char *>> arr;
|
||||
parsed_tokens arr;
|
||||
if (!tokenize_and_check<1, 0>(stmt, arr))
|
||||
return false;
|
||||
run_fn(arr[0][1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Pattern 7: type_transition source target class default (filename)
|
||||
template <typename Func>
|
||||
static bool parse_pattern_7(const Func &fn, const char *action, char *stmt) {
|
||||
parsed_tokens arr;
|
||||
if (!tokenize_string(stmt, arr))
|
||||
return false;
|
||||
if (arr.size() == 4)
|
||||
arr.emplace_back(initializer_list<char*>{nullptr});
|
||||
arr.emplace_back(initializer_list<const char*>{nullptr});
|
||||
if (!check_tokens<5, 0, 1, 2, 3, 4>(arr))
|
||||
return false;
|
||||
run_fn(arr[0][0], arr[1][0], arr[2][0], arr[3][0], arr[4][0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Pattern 7: action name path context
|
||||
// Pattern 8: type_change source target class default
|
||||
template <typename Func>
|
||||
static bool parse_pattern_7(const Func &fn, const char *action, char *stmt) {
|
||||
vector<vector<char *>> arr;
|
||||
static bool parse_pattern_8(const Func &fn, const char *action, char *stmt) {
|
||||
parsed_tokens arr;
|
||||
if (!tokenize_and_check<4, 0, 1, 2, 3>(stmt, arr))
|
||||
return false;
|
||||
run_fn(arr[0][0], arr[1][0], arr[2][0], arr[3][0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Pattern 9: genfscon name path context
|
||||
template <typename Func>
|
||||
static bool parse_pattern_9(const Func &fn, const char *action, char *stmt) {
|
||||
parsed_tokens arr;
|
||||
if (!tokenize_and_check<3, 0, 1, 2>(stmt, arr))
|
||||
return false;
|
||||
run_fn(arr[0][0], arr[1][0], arr[2][0]);
|
||||
@ -256,18 +295,20 @@ void sepolicy::parse_statement(const char *stmt) {
|
||||
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)
|
||||
add_action(type, 5)
|
||||
add_action(attribute, 6)
|
||||
add_action(type_transition, 7)
|
||||
add_action(type_change, 8)
|
||||
add_action(type_member, 8)
|
||||
add_action(genfscon, 9)
|
||||
|
||||
// Backwards compatible syntax
|
||||
add_action(create, 3)
|
||||
add_action_func("attradd", 4, typeattribute)
|
||||
add_action_func("name_transition", 6, type_transition)
|
||||
add_action_func("name_transition", 7, type_transition)
|
||||
|
||||
else { LOGW("Unknown action: '%s'\n\n", action); }
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user