mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-22 01:57:43 +00:00
Named transition - but disabled due to a bug
This commit is contained in:
parent
db34aac811
commit
015df061e3
@ -31,6 +31,12 @@ struct flagval {
|
||||
int audit;
|
||||
};
|
||||
|
||||
struct named_transition {
|
||||
int present;
|
||||
char *namespace;
|
||||
char *name;
|
||||
};
|
||||
|
||||
struct cod_pattern {
|
||||
char *regex; // posix regex
|
||||
pcre *compiled; // compiled regex, size is compiled->size
|
||||
@ -40,6 +46,7 @@ struct cod_entry {
|
||||
char *namespace;
|
||||
char *name;
|
||||
char *link_name;
|
||||
char *nt_name;
|
||||
struct codomain *codomain; /* Special codomain defined
|
||||
* just for this executable */
|
||||
int mode; /* mode is 'or' of AA_* bits */
|
||||
@ -73,6 +80,9 @@ struct codomain {
|
||||
char *name; /* codomain name */
|
||||
char *sub_name; /* subdomain name or NULL */
|
||||
int default_deny; /* TRUE or FALSE */
|
||||
int local;
|
||||
int local_mode; /* true if local, not hat */
|
||||
int local_audit;
|
||||
|
||||
struct codomain *parent;
|
||||
|
||||
@ -92,6 +102,7 @@ struct codomain {
|
||||
|
||||
struct aa_rlimits rlimits;
|
||||
|
||||
char *exec_table[AA_EXEC_COUNT];
|
||||
struct cod_entry *entries;
|
||||
void *hat_table;
|
||||
//struct codomain *next;
|
||||
|
@ -377,13 +377,11 @@ inline int sd_write_aligned_blob(sd_serialize *p, void *b, int buf_size,
|
||||
return 1;
|
||||
}
|
||||
|
||||
inline int sd_write_string(sd_serialize *p, char *b, char *name)
|
||||
static int sd_write_strn(sd_serialize *p, char *b, int size, char *name)
|
||||
{
|
||||
u16 tmp;
|
||||
int size;
|
||||
if (!sd_write_name(p, name))
|
||||
return 0;
|
||||
size = strlen(b) + 1;
|
||||
if (!sd_prepare_write(p, SD_STRING, SD_STR_LEN + size))
|
||||
return 0;
|
||||
tmp = cpu_to_le16(size);
|
||||
@ -394,6 +392,11 @@ inline int sd_write_string(sd_serialize *p, char *b, char *name)
|
||||
return 1;
|
||||
}
|
||||
|
||||
inline int sd_write_string(sd_serialize *p, char *b, char *name)
|
||||
{
|
||||
return sd_write_strn(p, b, strlen(b) + 1, name);
|
||||
}
|
||||
|
||||
inline int sd_write_struct(sd_serialize *p, char *name)
|
||||
{
|
||||
if (!sd_write_name(p, name))
|
||||
@ -527,6 +530,41 @@ int sd_serialize_rlimits(sd_serialize *p, struct aa_rlimits *limits)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sd_serialize_xtable(sd_serialize *p, char **table)
|
||||
{
|
||||
int count, i;
|
||||
if (!table[4])
|
||||
return 1;
|
||||
if (!sd_write_struct(p, "xtable"))
|
||||
return 0;
|
||||
count = 0;
|
||||
for (i = 4; i < AA_EXEC_COUNT; i++) {
|
||||
if (table[i])
|
||||
count++;
|
||||
}
|
||||
|
||||
if (!sd_write_array(p, NULL, count))
|
||||
return 0;
|
||||
for (i = 4; i < count + 4; i++) {
|
||||
int len = strlen(table[i]) + 1;
|
||||
|
||||
/* if its a namespace make sure the second : is overwritten
|
||||
* with 0, so that the namespace and name are \0 seperated
|
||||
*/
|
||||
if (*table[i] == ':') {
|
||||
char *tmp = table[i] + 1;
|
||||
strsep(&tmp, ":");
|
||||
}
|
||||
if (!sd_write_strn(p, table[i], len, NULL));
|
||||
return 0;
|
||||
}
|
||||
if (!sd_write_arrayend(p))
|
||||
return 0;
|
||||
if (!sd_write_structend(p))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int count_file_ents(struct cod_entry *list)
|
||||
{
|
||||
struct cod_entry *entry;
|
||||
@ -634,6 +672,9 @@ int sd_serialize_profile(sd_serialize *p, struct codomain *profile,
|
||||
if (regex_type == AARE_DFA) {
|
||||
if (!sd_serialize_dfa(p, profile->dfa, profile->dfa_size))
|
||||
return 0;
|
||||
|
||||
if (!sd_serialize_xtable(p, profile->exec_table))
|
||||
return 0;
|
||||
} else {
|
||||
/* pcre globbing entries */
|
||||
if (count_pcre_ents(profile->entries)) {
|
||||
|
@ -93,8 +93,62 @@ void add_hat_to_policy(struct codomain *cod, struct codomain *hat)
|
||||
}
|
||||
}
|
||||
|
||||
static int add_named_transition(struct codomain *cod, char *namespace, char *trans)
|
||||
{
|
||||
char *name = NULL;
|
||||
int i;
|
||||
|
||||
/* check to see if it is a local transition */
|
||||
if (!namespace) {
|
||||
if (strstr(name, "//")) {
|
||||
free(trans);
|
||||
return AA_EXEC_LOCAL;
|
||||
}
|
||||
}
|
||||
if (namespace) {
|
||||
name = malloc(strlen(namespace) + strlen(trans) + 3);
|
||||
if (!name) {
|
||||
PERROR("Memory allocation error\n");
|
||||
exit(1);
|
||||
}
|
||||
sprintf(name, ":%s:%s", namespace, trans);
|
||||
free(namespace);
|
||||
free(trans);
|
||||
} else {
|
||||
name = trans;
|
||||
}
|
||||
|
||||
for (i = (AA_EXEC_LOCAL + 1) >> 10; i < AA_EXEC_COUNT; i++) {
|
||||
if (!cod->exec_table[i]) {
|
||||
cod->exec_table[i] = name;
|
||||
return i;
|
||||
} else if (strcmp(cod->exec_table[i], name) == 0) {
|
||||
/* name already in table */
|
||||
free(name);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
free(name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void add_entry_to_policy(struct codomain *cod, struct cod_entry *entry)
|
||||
{
|
||||
if (entry->nt_name) {
|
||||
int mode = 0;
|
||||
int n = add_named_transition(cod, entry->namespace, entry->nt_name);
|
||||
if (!n)
|
||||
PERROR("Profile %s has to many specified profile transitions.\n", cod->name);
|
||||
exit(1);
|
||||
if (entry->mode & AA_USER_EXEC)
|
||||
mode |= SHIFT_MODE(n << 10, AA_USER_SHIFT);
|
||||
if (entry->mode & AA_OTHER_EXEC)
|
||||
mode |= SHIFT_MODE(n << 10, AA_OTHER_SHIFT);
|
||||
entry->mode = ((entry->mode & ~AA_ALL_EXEC_MODIFIERS) |
|
||||
(mode & AA_ALL_EXEC_MODIFIERS));
|
||||
entry->namespace = NULL;
|
||||
entry->nt_name = NULL;
|
||||
}
|
||||
entry->next = cod->entries;
|
||||
cod->entries = entry;
|
||||
}
|
||||
@ -272,6 +326,10 @@ static void __add_hat_rules_parent(const void *nodep, const VISIT value,
|
||||
if (!(*t)->hat_table && !(*t)->parent)
|
||||
return;
|
||||
|
||||
/* don't add hat rules for local_profiles */
|
||||
if ((*t)->local)
|
||||
return;
|
||||
|
||||
/* add rule to grant permission to change_hat - AA 2.3 requirement,
|
||||
* rules are added to the parent of the hat
|
||||
*/
|
||||
@ -319,6 +377,10 @@ static void __add_hat_rules_hats(const void *nodep, const VISIT value,
|
||||
if (!(*t)->hat_table && !(*t)->parent)
|
||||
return;
|
||||
|
||||
/* don't add hat rules for local_profiles */
|
||||
if ((*t)->local)
|
||||
return;
|
||||
|
||||
/* hat */
|
||||
if ((*t)->parent) {
|
||||
struct cod_entry *entry, *new_ent;
|
||||
|
@ -68,7 +68,11 @@ struct value_list {
|
||||
|
||||
void free_value_list(struct value_list *list);
|
||||
struct cod_entry *do_file_rule(char *namespace, char *id, int mode,
|
||||
char *link_id);
|
||||
char *link_id, char *nt);
|
||||
|
||||
void add_local_entry(struct codomain *cod);
|
||||
|
||||
struct codomain *do_local_profile(struct codomain *cod, char *name, int mode, int audit);
|
||||
|
||||
%}
|
||||
|
||||
@ -153,6 +157,7 @@ struct cod_entry *do_file_rule(char *namespace, char *id, int mode,
|
||||
char *var_val;
|
||||
struct value_list *val_list;
|
||||
int boolean;
|
||||
struct named_transition transition;
|
||||
}
|
||||
|
||||
%type <id> TOK_ID
|
||||
@ -161,6 +166,7 @@ struct cod_entry *do_file_rule(char *namespace, char *id, int mode,
|
||||
%type <cod> profile
|
||||
%type <cod> rules
|
||||
%type <cod> hat
|
||||
%type <cod> local_profile
|
||||
%type <cod> cond_rule
|
||||
%type <network_entry> network_rule
|
||||
%type <user_entry> rule
|
||||
@ -183,6 +189,8 @@ struct cod_entry *do_file_rule(char *namespace, char *id, int mode,
|
||||
%type <boolean> opt_audit_flag
|
||||
%type <boolean> opt_owner_flag
|
||||
%type <boolean> opt_profile_flag
|
||||
%type <transition> opt_named_transition
|
||||
|
||||
%%
|
||||
|
||||
|
||||
@ -623,6 +631,18 @@ rules: rules hat
|
||||
$$ = $1;
|
||||
};
|
||||
|
||||
/*
|
||||
rules: rules local_profile
|
||||
{
|
||||
PDEBUG("Matched: hat rule\n");
|
||||
if (!$2)
|
||||
yyerror(_("Assert: 'local_profile rule' returned NULL."));
|
||||
add_hat_to_policy($1, $2);
|
||||
add_local_entry($2);
|
||||
$$ = $1;
|
||||
};
|
||||
*/
|
||||
|
||||
rules: rules cond_rule
|
||||
{
|
||||
PDEBUG("Matched: conditional rules\n");
|
||||
@ -780,23 +800,61 @@ expr: TOK_DEFINED TOK_BOOL_VAR
|
||||
id_or_var: TOK_ID { $$ = $1; }
|
||||
id_or_var: TOK_SET_VAR { $$ = $1; };
|
||||
|
||||
rule: id_or_var file_mode TOK_END_OF_RULE
|
||||
opt_named_transition:
|
||||
{ /* nothing */
|
||||
$$.present = 0;
|
||||
$$.namespace = NULL;
|
||||
$$.name = NULL;
|
||||
}
|
||||
| TOK_ARROW id_or_var
|
||||
{
|
||||
$$ = do_file_rule(NULL, $1, $2, NULL);
|
||||
$$.present = 1;
|
||||
$$.namespace = NULL;
|
||||
$$.name = $2;
|
||||
}
|
||||
| TOK_ARROW TOK_COLON id_or_var TOK_COLON id_or_var
|
||||
{
|
||||
$$.present = 1;
|
||||
$$.namespace = $3;
|
||||
$$.name = $5;
|
||||
};
|
||||
|
||||
rule: file_mode id_or_var TOK_END_OF_RULE
|
||||
rule: id_or_var file_mode opt_named_transition TOK_END_OF_RULE
|
||||
{
|
||||
$$ = do_file_rule(NULL, $2, $1 & ~ALL_AA_EXEC_UNSAFE, NULL);
|
||||
$$ = do_file_rule($3.namespace, $1, $2, NULL, $3.name);
|
||||
};
|
||||
|
||||
rule: file_mode opt_subset_flag id_or_var opt_named_transition TOK_END_OF_RULE
|
||||
{
|
||||
if ($2 && ($1 & ~AA_LINK_BITS))
|
||||
yyerror(_("subset can only be used with link rules."));
|
||||
if ($4.present && ($1 & AA_LINK_BITS) && ($1 & AA_EXEC_BITS))
|
||||
yyerror(_("link and exec perms conflict on a file rule using ->"));
|
||||
if ($4.present && $4.namespace && ($1 & AA_LINK_BITS))
|
||||
yyerror(_("link perms are not allowed on a named profile transition.\n"));
|
||||
if (($1 & AA_LINK_BITS)) {
|
||||
$$ = do_file_rule(NULL, $3, $1 & ~ALL_AA_EXEC_UNSAFE,
|
||||
$4.name, NULL);
|
||||
$$->subset = $2;
|
||||
|
||||
} else {
|
||||
$$ = do_file_rule($4.namespace, $3, $1 & ~ALL_AA_EXEC_UNSAFE, NULL, $4.name);
|
||||
}
|
||||
};
|
||||
|
||||
rule: TOK_UNSAFE file_mode id_or_var TOK_END_OF_RULE
|
||||
rule: TOK_UNSAFE file_mode id_or_var opt_named_transition TOK_END_OF_RULE
|
||||
{
|
||||
int mode = (($2 & AA_EXEC_BITS) << 8) & ALL_AA_EXEC_UNSAFE;
|
||||
|
||||
if (!($2 & AA_EXEC_BITS))
|
||||
yyerror(_("unsafe rule missing exec permissions"));
|
||||
$$ = do_file_rule(NULL, $3, ($2 & ~ALL_AA_EXEC_UNSAFE) | mode,
|
||||
NULL);
|
||||
|
||||
if ($4.present && ($2 & AA_LINK_BITS))
|
||||
yyerror(_("link perms are not allowed on a named profile transtion.\n"));
|
||||
|
||||
$$ = do_file_rule($4.namespace, $3,
|
||||
($2 & ~ALL_AA_EXEC_UNSAFE) | mode,
|
||||
NULL, $4.name);
|
||||
};
|
||||
|
||||
rule: id_or_var file_mode id_or_var
|
||||
@ -813,28 +871,11 @@ rule: TOK_LINK opt_subset_flag TOK_ID TOK_ARROW TOK_ID TOK_END_OF_RULE
|
||||
struct cod_entry *entry;
|
||||
PDEBUG("Matched: link tok_id (%s) -> (%s)\n", $3, $5);
|
||||
entry = new_entry(NULL, $3, AA_LINK_BITS, $5);
|
||||
if (!entry)
|
||||
yyerror(_("Memory allocation error."));
|
||||
entry->subset = $2;
|
||||
PDEBUG("rule.entry: link (%s)\n", entry->name);
|
||||
$$ = entry;
|
||||
};
|
||||
|
||||
rule: file_mode opt_subset_flag TOK_ID TOK_ARROW TOK_ID TOK_END_OF_RULE
|
||||
{
|
||||
struct cod_entry *entry;
|
||||
PDEBUG("Matched: link tok_id (%s) -> (%s)\n", $3, $5);
|
||||
if ($1 & ~AA_LINK_BITS)
|
||||
yyerror(_("only link perms can be specified in a link rule."));
|
||||
entry = new_entry(NULL, $3, AA_LINK_BITS, $5);
|
||||
if (!entry)
|
||||
yyerror(_("Memory allocation error."));
|
||||
entry->subset = $2;
|
||||
|
||||
PDEBUG("rule.entry: link (%s)\n", entry->name);
|
||||
$$ = entry;
|
||||
};
|
||||
|
||||
rule: TOK_PTRACE TOK_ID TOK_END_OF_RULE
|
||||
{
|
||||
struct cod_entry *entry;
|
||||
@ -883,6 +924,54 @@ hat: hat_start TOK_ID flags TOK_OPEN rules TOK_CLOSE
|
||||
$$ = cod;
|
||||
};
|
||||
|
||||
local_profile: opt_audit_flag opt_owner_flag TOK_ID file_mode TOK_ARROW TOK_OPEN rules TOK_CLOSE
|
||||
{
|
||||
int audit = 0, mode = $4;
|
||||
if ($2 == 1)
|
||||
mode &= (AA_USER_PERMS | AA_SHARED_PERMS | AA_USER_PTRACE);
|
||||
else if ($2 == 2)
|
||||
mode &= (AA_OTHER_PERMS | AA_SHARED_PERMS | AA_OTHER_PTRACE);
|
||||
if ($1)
|
||||
audit = mode & ~ALL_AA_EXEC_TYPE;
|
||||
|
||||
$$ = do_local_profile($7, $3, mode, audit);
|
||||
};
|
||||
|
||||
local_profile: opt_audit_flag opt_owner_flag file_mode TOK_ID TOK_ARROW TOK_OPEN rules TOK_CLOSE
|
||||
{
|
||||
int audit = 0, mode = $3;
|
||||
mode &= ~ALL_AA_EXEC_UNSAFE;
|
||||
if ($2 == 1)
|
||||
mode &= (AA_USER_PERMS | AA_SHARED_PERMS | AA_USER_PTRACE);
|
||||
else if ($2 == 2)
|
||||
mode &= (AA_OTHER_PERMS | AA_SHARED_PERMS | AA_OTHER_PTRACE);
|
||||
if ($1)
|
||||
audit = mode & ~ALL_AA_EXEC_TYPE;
|
||||
|
||||
$$ = do_local_profile($7, $4, mode, audit);
|
||||
};
|
||||
|
||||
local_profile: opt_audit_flag opt_owner_flag TOK_UNSAFE file_mode TOK_ID TOK_ARROW TOK_OPEN rules TOK_CLOSE
|
||||
{
|
||||
int unsafe = (($4 & AA_EXEC_BITS) << 8) & ALL_AA_EXEC_UNSAFE;
|
||||
int audit = 0, mode = ($4 & ~ALL_AA_EXEC_UNSAFE) | unsafe;
|
||||
if ($2 == 1)
|
||||
mode &= (AA_USER_PERMS | AA_SHARED_PERMS | AA_USER_PTRACE);
|
||||
else if ($2 == 2)
|
||||
mode &= (AA_OTHER_PERMS | AA_SHARED_PERMS | AA_OTHER_PTRACE);
|
||||
if ($1)
|
||||
audit = mode & ~ALL_AA_EXEC_TYPE;
|
||||
|
||||
$$ = do_local_profile($8, $5, mode, audit);
|
||||
};
|
||||
|
||||
local_profile: TOK_PROFILE TOK_ID flags TOK_OPEN rules TOK_CLOSE
|
||||
{
|
||||
struct codomain *cod = do_local_profile($5, $2, 0, 0);
|
||||
cod->flags = $3;
|
||||
$$ = cod;
|
||||
};
|
||||
|
||||
network_rule: TOK_NETWORK TOK_END_OF_RULE
|
||||
{
|
||||
int family;
|
||||
@ -933,22 +1022,22 @@ file_mode: TOK_MODE
|
||||
free($1);
|
||||
}
|
||||
|
||||
change_profile: TOK_CHANGE_PROFILE TOK_ID TOK_END_OF_RULE
|
||||
change_profile: TOK_CHANGE_PROFILE TOK_ARROW TOK_ID TOK_END_OF_RULE
|
||||
{
|
||||
struct cod_entry *entry;
|
||||
PDEBUG("Matched change_profile: tok_id (%s)\n", $2);
|
||||
entry = new_entry(NULL, $2, AA_CHANGE_PROFILE, NULL);
|
||||
PDEBUG("Matched change_profile: tok_id (%s)\n", $3);
|
||||
entry = new_entry(NULL, $3, AA_CHANGE_PROFILE, NULL);
|
||||
if (!entry)
|
||||
yyerror(_("Memory allocation error."));
|
||||
PDEBUG("change_profile.entry: (%s)\n", entry->name);
|
||||
$$ = entry;
|
||||
};
|
||||
|
||||
change_profile: TOK_CHANGE_PROFILE TOK_COLON TOK_ID TOK_COLON TOK_ID TOK_END_OF_RULE
|
||||
change_profile: TOK_CHANGE_PROFILE TOK_ARROW TOK_COLON TOK_ID TOK_COLON TOK_ID TOK_END_OF_RULE
|
||||
{
|
||||
struct cod_entry *entry;
|
||||
PDEBUG("Matched change_profile: tok_id (%s:%s)\n", $3, $5);
|
||||
entry = new_entry($3, $5, AA_CHANGE_PROFILE, NULL);
|
||||
PDEBUG("Matched change_profile: tok_id (%s:%s)\n", $4, $6);
|
||||
entry = new_entry($4, $6, AA_CHANGE_PROFILE, NULL);
|
||||
if (!entry)
|
||||
yyerror(_("Memory allocation error."));
|
||||
PDEBUG("change_profile.entry: (%s)\n", entry->name);
|
||||
@ -1019,13 +1108,58 @@ void free_value_list(struct value_list *list)
|
||||
}
|
||||
|
||||
struct cod_entry *do_file_rule(char *namespace, char *id, int mode,
|
||||
char *link_id)
|
||||
char *link_id, char *nt)
|
||||
{
|
||||
struct cod_entry *entry;
|
||||
PDEBUG("Matched: tok_id (%s) tok_mode (0x%x)\n", id, mode);
|
||||
entry = new_entry(namespace, id, mode, link_id);
|
||||
if (!entry)
|
||||
yyerror(_("Memory allocation error."));
|
||||
entry->nt_name = nt;
|
||||
PDEBUG("rule.entry: (%s)\n", entry->name);
|
||||
return entry;
|
||||
}
|
||||
|
||||
void add_local_entry(struct codomain *cod)
|
||||
{
|
||||
/* ugh this has to be called after the hat is attached to its parent */
|
||||
if (cod->local_mode) {
|
||||
struct cod_entry *entry;
|
||||
char *trans = malloc(strlen(cod->parent->name) +
|
||||
strlen(cod->name) + 3);
|
||||
char *name = strdup(cod->name);
|
||||
if (!trans)
|
||||
yyerror(_("Memory allocation error."));
|
||||
sprintf(name, "%s//%s", cod->parent->name, cod->name);
|
||||
|
||||
entry = new_entry(NULL, name, cod->local_mode, NULL);
|
||||
entry->audit = cod->local_audit;
|
||||
entry->nt_name = trans;
|
||||
if (!entry)
|
||||
yyerror(_("Memory allocation error."));
|
||||
|
||||
add_entry_to_policy(cod, entry);
|
||||
}
|
||||
}
|
||||
|
||||
struct codomain *do_local_profile(struct codomain *cod, char *name, int mode,
|
||||
int audit)
|
||||
{
|
||||
PDEBUG("Matched: local profile trans (%s) open rules close\n", $1);
|
||||
if (!cod) {
|
||||
yyerror(_("Memory allocation error."));
|
||||
}
|
||||
cod->name = name;
|
||||
if (force_complain)
|
||||
cod->flags = force_complain_flags;
|
||||
PDEBUG("profile %s: flags='%s%s'\n",
|
||||
name,
|
||||
cod->flags.complain ? "complain, " : "",
|
||||
cod->flags.audit ? "audit" : "");
|
||||
|
||||
cod->local = 1;
|
||||
cod->local_mode = mode;
|
||||
cod->local_audit = audit;
|
||||
|
||||
return cod;
|
||||
}
|
||||
|
@ -3,5 +3,5 @@
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
change_profile /bin/foo,
|
||||
change_profile -> /bin/foo,
|
||||
}
|
||||
|
@ -3,5 +3,5 @@
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
change_profile /bin/foo//bar,
|
||||
change_profile -> /bin/foo//bar,
|
||||
}
|
||||
|
@ -3,5 +3,5 @@
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
change_profile :foo:/bin/foo,
|
||||
change_profile -> :foo:/bin/foo,
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user