mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-04 08:24:42 +01:00
add basic handling of profile namespaces
This commit is contained in:
parent
11d8181d0d
commit
a4721bd02d
9 changed files with 160 additions and 24 deletions
|
@ -36,7 +36,8 @@ struct cod_pattern {
|
|||
};
|
||||
|
||||
struct cod_entry {
|
||||
char * name ;
|
||||
char *namespace;
|
||||
char *name ;
|
||||
struct codomain *codomain ; /* Special codomain defined
|
||||
* just for this executable */
|
||||
int mode ; /* mode is 'or' of AA_* bits */
|
||||
|
@ -67,6 +68,7 @@ struct aa_network_entry {
|
|||
};
|
||||
|
||||
struct codomain {
|
||||
char *namespace;
|
||||
char *name; /* codomain name */
|
||||
char *sub_name; /* subdomain name or NULL */
|
||||
int default_deny; /* TRUE or FALSE */
|
||||
|
@ -176,6 +178,7 @@ struct var_string {
|
|||
extern char *progname;
|
||||
extern char *subdomainbase;
|
||||
extern char *profilename;
|
||||
extern char *profile_namespace;
|
||||
|
||||
/* from parser_main */
|
||||
extern int force_complain;
|
||||
|
@ -201,7 +204,7 @@ extern char *processunquoted(char *string, int len);
|
|||
extern int get_keyword_token(const char *keyword);
|
||||
extern char *process_var(const char *var);
|
||||
extern int parse_mode(const char *mode);
|
||||
extern struct cod_entry *new_entry(char *id, int mode);
|
||||
extern struct cod_entry *new_entry(char *namespace, char *id, int mode);
|
||||
extern struct cod_net_entry *new_network_entry(int action,
|
||||
struct ipv4_endpoints *addrs,
|
||||
char *interface);
|
||||
|
|
|
@ -702,6 +702,15 @@ int sd_serialize_top_profile(sd_serialize *p, struct codomain *profile)
|
|||
|
||||
if (!sd_write32(p, version))
|
||||
return 0;
|
||||
|
||||
if (profile_namespace) {
|
||||
if (!sd_write_string(p, profile_namespace, "namespace"))
|
||||
return 0;
|
||||
} else if (profile->namespace) {
|
||||
if (!sd_write_string(p, profile->namespace, "namespace"))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sd_serialize_profile(p, profile, profile->parent ? 1 : 0);
|
||||
}
|
||||
|
||||
|
@ -746,16 +755,38 @@ int sd_serialize_codomain(int option, struct codomain *cod)
|
|||
free(filename);
|
||||
|
||||
if (option == OPTION_REMOVE) {
|
||||
char *name;
|
||||
char *name, *ns = NULL;
|
||||
int len = 0;
|
||||
|
||||
if (profile_namespace) {
|
||||
len += strlen(profile_namespace) + 1;
|
||||
ns = profile_namespace;
|
||||
} else if (cod->namespace) {
|
||||
len += strlen(cod->namespace) + 1;
|
||||
ns = cod->namespace;
|
||||
}
|
||||
if (cod->parent) {
|
||||
name = malloc(strlen(cod->name) + 3 +
|
||||
strlen(cod->parent->name));
|
||||
strlen(cod->parent->name) + len);
|
||||
if (!name) {
|
||||
PERROR(_("Unable to remove ^%s\n"), cod->name);
|
||||
PERROR(_("Memory Allocation Error: Unable to remove ^%s\n"), cod->name);
|
||||
error = -errno;
|
||||
goto exit;
|
||||
}
|
||||
sprintf(name, "%s//%s", cod->parent->name, cod->name);
|
||||
if (ns)
|
||||
sprintf(name, "%s:%s//%s", ns,
|
||||
cod->parent->name, cod->name);
|
||||
else
|
||||
sprintf(name, "%s//%s", cod->parent->name,
|
||||
cod->name);
|
||||
} else if (ns) {
|
||||
name = malloc(len + strlen(cod->name) + 1);
|
||||
if (!name) {
|
||||
PERROR(_("Memory Allocation Error: Unable to remove %s:%s."), ns, cod->name);
|
||||
error = -errno;
|
||||
goto exit;
|
||||
}
|
||||
sprintf(name, "%s:%s", ns, cod->name);
|
||||
} else {
|
||||
name = cod->name;
|
||||
}
|
||||
|
@ -763,7 +794,7 @@ int sd_serialize_codomain(int option, struct codomain *cod)
|
|||
wsize = write(fd, name, size);
|
||||
if (wsize < 0)
|
||||
error = -errno;
|
||||
if (cod->parent)
|
||||
if (cod->parent || ns)
|
||||
free(name);
|
||||
} else {
|
||||
|
||||
|
|
|
@ -346,14 +346,21 @@ ADD_ASSIGN \+=
|
|||
return TOK_HAT;
|
||||
}
|
||||
|
||||
{KEYWORD} {
|
||||
{COLON} {
|
||||
PDEBUG("Found a colon\n");
|
||||
return TOK_COLON;
|
||||
}
|
||||
|
||||
{VARIABLE_NAME} {
|
||||
int token = get_keyword_token(yytext);
|
||||
|
||||
/* special cases */
|
||||
switch (token) {
|
||||
case -1:
|
||||
/* no token found */
|
||||
yyerror(_("Found unexpected keyword: '%s'"), yytext);
|
||||
yylval = (YYSTYPE) processunquoted(yytext, yyleng);
|
||||
PDEBUG("Found id: \"%s\"\n", yylval);
|
||||
return TOK_ID;
|
||||
break;
|
||||
case TOK_VIA:
|
||||
BEGIN(IF_MODE); /* look for an interface name next */
|
||||
|
|
|
@ -67,6 +67,7 @@ char *subdomainbase = NULL;
|
|||
char *profilename;
|
||||
char *match_string = NULL;
|
||||
int regex_type = AARE_DFA;
|
||||
char *profile_namespace = NULL;
|
||||
|
||||
extern int current_lineno;
|
||||
|
||||
|
@ -89,6 +90,7 @@ struct option long_options[] = {
|
|||
{"stdout", 0, 0, 'S'},
|
||||
{"match-string", 1, 0, 'm'},
|
||||
{"quiet", 0, 0, 'q'},
|
||||
{"namespace", 1, 0, 'n'},
|
||||
{NULL, 0, 0, 0},
|
||||
};
|
||||
|
||||
|
@ -119,6 +121,7 @@ static void display_usage(char *command)
|
|||
"-f n, --subdomainfs n Set location of apparmor filesystem\n"
|
||||
"-S, --stdout Write output to stdout\n"
|
||||
"-m n, --match-string n Use only match features n\n"
|
||||
"-n n, --namespace n Set Namespace for the profile\n"
|
||||
"-q, --quiet Don't emit warnings\n", command);
|
||||
}
|
||||
|
||||
|
@ -149,7 +152,7 @@ static int process_args(int argc, char *argv[])
|
|||
int count = 0;
|
||||
option = OPTION_ADD;
|
||||
|
||||
while ((c = getopt_long(argc, argv, "adf:hrRvpI:b:CNSm:q", long_options, &o)) != -1)
|
||||
while ((c = getopt_long(argc, argv, "adf:hrRvpI:b:CNSm:qn:", long_options, &o)) != -1)
|
||||
{
|
||||
switch (c) {
|
||||
case 0:
|
||||
|
@ -215,6 +218,9 @@ static int process_args(int argc, char *argv[])
|
|||
case 'q':
|
||||
conf_quiet = 1;
|
||||
break;
|
||||
case 'n':
|
||||
profile_namespace = strdup(optarg);
|
||||
break;
|
||||
default:
|
||||
display_usage(progname);
|
||||
exit(0);
|
||||
|
|
|
@ -43,7 +43,20 @@ static int file_comp(const void *c1, const void *c2)
|
|||
struct cod_entry **e1, **e2;
|
||||
e1 = (struct cod_entry **)c1;
|
||||
e2 = (struct cod_entry **)c2;
|
||||
int res = 0;
|
||||
|
||||
//PERROR("strcmp %s %s\n", (*e1)->name, (*e2)->name);
|
||||
if ((*e1)->namespace) {
|
||||
if ((*e2)->namespace)
|
||||
res = strcmp((*e1)->namespace, (*e2)->namespace);
|
||||
else
|
||||
return 1;
|
||||
} else if ((*e2)->namespace) {
|
||||
return -1;
|
||||
}
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
return strcmp((*e1)->name, (*e2)->name);
|
||||
}
|
||||
|
||||
|
|
|
@ -632,7 +632,7 @@ struct cod_net_entry *new_network_entry(int action,
|
|||
return entry;
|
||||
}
|
||||
|
||||
struct cod_entry *new_entry(char *id, int mode)
|
||||
struct cod_entry *new_entry(char *namespace, char *id, int mode)
|
||||
{
|
||||
struct cod_entry *entry = NULL;
|
||||
|
||||
|
@ -640,7 +640,8 @@ struct cod_entry *new_entry(char *id, int mode)
|
|||
if (!entry)
|
||||
return NULL;
|
||||
|
||||
entry->name = id ? id : NULL;
|
||||
entry->namespace = namespace;
|
||||
entry->name = id;
|
||||
entry->mode = mode;
|
||||
entry->deny = FALSE;
|
||||
|
||||
|
@ -662,6 +663,7 @@ struct cod_entry *copy_cod_entry(struct cod_entry *orig)
|
|||
if (!entry)
|
||||
return NULL;
|
||||
|
||||
entry->namespace = orig->namespace ? strdup(orig->namespace) : NULL;
|
||||
entry->name = strdup(orig->name);
|
||||
entry->mode = orig->mode;
|
||||
entry->deny = orig->deny;
|
||||
|
@ -693,6 +695,8 @@ void free_cod_entries(struct cod_entry *list)
|
|||
return;
|
||||
if (list->next)
|
||||
free_cod_entries(list->next);
|
||||
if (list->namespace)
|
||||
free(list->namespace);
|
||||
if (list->name)
|
||||
free(list->name);
|
||||
if (list->pat.regex)
|
||||
|
@ -765,8 +769,13 @@ void debug_cod_entries(struct cod_entry *list)
|
|||
|
||||
if (item->name)
|
||||
printf("\tName:\t(%s)\n", item->name);
|
||||
|
||||
else
|
||||
printf("\tName:\tNULL\n");
|
||||
|
||||
if (item->namespace)
|
||||
printf("\tNamespace:\t(%s)\n", item->namespace);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -865,6 +874,9 @@ const char *capability_to_name(unsigned int cap)
|
|||
void debug_cod_list(struct codomain *cod)
|
||||
{
|
||||
unsigned int i;
|
||||
if (cod->namespace)
|
||||
printf("Namespcae:\t\t%s\n", cod->namespace);
|
||||
|
||||
if (cod->name)
|
||||
printf("Name:\t\t%s\n", cod->name);
|
||||
else
|
||||
|
|
|
@ -41,8 +41,20 @@ void *policy_list = NULL;
|
|||
|
||||
static int codomain_compare(const void *a, const void *b)
|
||||
{
|
||||
return strcmp(((struct codomain *) a)->name,
|
||||
((struct codomain *) b)->name);
|
||||
struct codomain *A = (struct codomain *) a;
|
||||
struct codomain *B = (struct codoamin *) b;
|
||||
|
||||
int res = 0;
|
||||
if (A->namespace) {
|
||||
if (B->namespace)
|
||||
res = strcmp(A->namespace, B->namespace);
|
||||
else
|
||||
res = -1;
|
||||
} else if (B->namespace)
|
||||
res = 1;
|
||||
if (res)
|
||||
return res;
|
||||
return strcmp(A->name, B->name);
|
||||
}
|
||||
|
||||
void add_to_list(struct codomain *codomain)
|
||||
|
|
|
@ -502,6 +502,18 @@ static int process_dfa_entry(aare_ruleset_t *dfarules, struct cod_entry *entry)
|
|||
if (!aare_add_rule(dfarules, tbuf, entry->mode))
|
||||
ret = FALSE;
|
||||
|
||||
if (entry->mode & AA_CHANGE_PROFILE) {
|
||||
char lbuf[2*PATH_MAX + 8];
|
||||
if (entry->namespace)
|
||||
sprintf(lbuf, "%s//%s", entry->namespace, entry->name);
|
||||
else
|
||||
sprintf(lbuf, "%s", entry->namespace, entry->name);
|
||||
ptype = convert_aaregex_to_pcre(lbuf, 0, tbuf, 2*PATH_MAX + 8);
|
||||
if (ptype == ePatternInvalid)
|
||||
return FALSE;
|
||||
if (!aare_add_rule(dfarules, tbuf, AA_CHANGE_PROFILE))
|
||||
return FALSE;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ struct value_list {
|
|||
};
|
||||
|
||||
void free_value_list(struct value_list *list);
|
||||
struct cod_entry *do_file_rule(char *id, int mode);
|
||||
struct cod_entry *do_file_rule(char *namespace, char *id, int mode);
|
||||
|
||||
%}
|
||||
|
||||
|
@ -238,6 +238,10 @@ profile: TOK_ID flags TOK_OPEN rules TOK_CLOSE
|
|||
if (!cod) {
|
||||
yyerror(_("Memory allocation error."));
|
||||
}
|
||||
|
||||
if ($1[0] != '/')
|
||||
yyerror(_("Profile names must begin with a '/'."));
|
||||
|
||||
cod->name = $1;
|
||||
cod->flags = $2;
|
||||
if (force_complain)
|
||||
|
@ -251,6 +255,31 @@ profile: TOK_ID flags TOK_OPEN rules TOK_CLOSE
|
|||
$$ = cod;
|
||||
};
|
||||
|
||||
profile: TOK_ID TOK_COLON TOK_ID flags TOK_OPEN rules TOK_CLOSE
|
||||
{
|
||||
struct codomain *cod = $6;
|
||||
PDEBUG("Matched: id (%s:%s) open rules close\n", $1, $3);
|
||||
if (!cod) {
|
||||
yyerror(_("Memory allocation error."));
|
||||
}
|
||||
|
||||
if ($3[0] != '/')
|
||||
yyerror(_("Profile names must begin with a '/'."));
|
||||
|
||||
cod->namespace = $1;
|
||||
cod->name = $3;
|
||||
cod->flags = $4;
|
||||
if (force_complain)
|
||||
cod->flags = force_complain_flags;
|
||||
|
||||
PDEBUG("%s: flags='%s%s'\n",
|
||||
$1,
|
||||
cod->flags.complain ? "complain, " : "",
|
||||
cod->flags.audit ? "audit" : "");
|
||||
|
||||
$$ = cod;
|
||||
};
|
||||
|
||||
varlist: { /* nothing */ }
|
||||
|
||||
varlist: varlist varassign
|
||||
|
@ -567,36 +596,36 @@ expr: TOK_DEFINED TOK_BOOL_VAR
|
|||
|
||||
rule: TOK_ID file_mode TOK_END_OF_RULE
|
||||
{
|
||||
$$ = do_file_rule($1, $2);
|
||||
$$ = do_file_rule(NULL, $1, $2);
|
||||
};
|
||||
|
||||
rule: TOK_SET_VAR file_mode TOK_END_OF_RULE
|
||||
{
|
||||
$$ = do_file_rule($1, $2);
|
||||
$$ = do_file_rule(NULL, $1, $2);
|
||||
};
|
||||
|
||||
rule: file_mode TOK_ID TOK_END_OF_RULE
|
||||
{
|
||||
$$ = do_file_rule($2, $1 & ~AA_EXEC_UNSAFE);
|
||||
$$ = do_file_rule(NULL, $2, $1 & ~AA_EXEC_UNSAFE);
|
||||
};
|
||||
|
||||
rule: file_mode TOK_SET_VAR TOK_END_OF_RULE
|
||||
{
|
||||
$$ = do_file_rule($2, $1 & ~AA_EXEC_UNSAFE);
|
||||
$$ = do_file_rule(NULL, $2, $1 & ~AA_EXEC_UNSAFE);
|
||||
};
|
||||
|
||||
rule: TOK_UNSAFE file_mode TOK_ID TOK_END_OF_RULE
|
||||
{
|
||||
if (!($2 & AA_MAY_EXEC))
|
||||
yyerror(_("unsafe rule missing exec permissions"));
|
||||
$$ = do_file_rule($3, $2 | AA_EXEC_UNSAFE);
|
||||
$$ = do_file_rule(NULL, $3, $2 | AA_EXEC_UNSAFE);
|
||||
};
|
||||
|
||||
rule: TOK_UNSAFE file_mode TOK_SET_VAR TOK_END_OF_RULE
|
||||
{
|
||||
if (!($2 & AA_MAY_EXEC))
|
||||
yyerror(_("unsafe rule missing exec permissions"));
|
||||
$$ = do_file_rule($3, $2 | AA_EXEC_UNSAFE);
|
||||
$$ = do_file_rule(NULL, $3, $2 | AA_EXEC_UNSAFE);
|
||||
};
|
||||
|
||||
rule: TOK_ID file_mode TOK_ID
|
||||
|
@ -937,7 +966,18 @@ change_profile: TOK_CHANGE_PROFILE TOK_ID TOK_END_OF_RULE
|
|||
{
|
||||
struct cod_entry *entry;
|
||||
PDEBUG("Matched change_profile: tok_id (%s)\n", $2);
|
||||
entry = new_entry($2, AA_CHANGE_PROFILE);
|
||||
entry = new_entry(NULL, $2, AA_CHANGE_PROFILE);
|
||||
if (!entry)
|
||||
yyerror(_("Memory allocation error."));
|
||||
PDEBUG("change_profile.entry: (%s)\n", entry->name);
|
||||
$$ = entry;
|
||||
};
|
||||
|
||||
change_profile: TOK_CHANGE_PROFILE TOK_ID TOK_COLON TOK_ID TOK_END_OF_RULE
|
||||
{
|
||||
struct cod_entry *entry;
|
||||
PDEBUG("Matched change_profile: tok_id (%s:%s)\n", $2, $4);
|
||||
entry = new_entry($2, $4, AA_CHANGE_PROFILE);
|
||||
if (!entry)
|
||||
yyerror(_("Memory allocation error."));
|
||||
PDEBUG("change_profile.entry: (%s)\n", entry->name);
|
||||
|
@ -1017,11 +1057,11 @@ void free_value_list(struct value_list *list)
|
|||
}
|
||||
}
|
||||
|
||||
struct cod_entry *do_file_rule(char *id, int mode)
|
||||
struct cod_entry *do_file_rule(char *namespace, char *id, int mode)
|
||||
{
|
||||
struct cod_entry *entry;
|
||||
PDEBUG("Matched: tok_id (%s) tok_mode (0x%x)\n", id, mode);
|
||||
entry = new_entry(id, mode);
|
||||
entry = new_entry(namespace, id, mode);
|
||||
if (!entry)
|
||||
yyerror(_("Memory allocation error."));
|
||||
PDEBUG("rule.entry: (%s)\n", entry->name);
|
||||
|
|
Loading…
Add table
Reference in a new issue