parser: Check kernel stacking support when handling stacked transitions

Check if the current kernel supports stacking. If not, ensure that named
transitions (exec, change_profile, etc.) do not attempt to stack their
targets.

Also, set up the change_profile vector according to whether or not the
kernel supports stacking. Earlier kernels expect the policy namespace to
be in its own NUL-terminated vector element rather than passing the
entire label (namespace and profile name) as a single string to the
kernel.

Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
This commit is contained in:
Tyler Hicks 2016-03-18 17:28:51 -05:00
parent 00fb4e94ab
commit 1a7663e89a
6 changed files with 59 additions and 10 deletions

View file

@ -298,6 +298,7 @@ extern int kernel_supports_dbus;
extern int kernel_supports_signal; extern int kernel_supports_signal;
extern int kernel_supports_ptrace; extern int kernel_supports_ptrace;
extern int kernel_supports_unix; extern int kernel_supports_unix;
extern int kernel_supports_stacking;
extern int conf_verbose; extern int conf_verbose;
extern int conf_quiet; extern int conf_quiet;
extern int names_only; extern int names_only;
@ -386,7 +387,8 @@ extern char *process_var(const char *var);
extern int parse_mode(const char *mode); extern int parse_mode(const char *mode);
extern int parse_X_mode(const char *X, int valid, const char *str_mode, int *mode, int fail); extern int parse_X_mode(const char *X, int valid, const char *str_mode, int *mode, int fail);
bool label_contains_ns(const char *label); bool label_contains_ns(const char *label);
void parse_label(bool *stack, char **ns, char **name, const char *label); bool parse_label(bool *_stack, char **_ns, char **_name,
const char *label, bool yyerr);
extern struct cod_entry *new_entry(char *id, int mode, char *link_id); extern struct cod_entry *new_entry(char *id, int mode, char *link_id);
/* returns -1 if value != true or false, otherwise 0 == false, 1 == true */ /* returns -1 if value != true or false, otherwise 0 == false, 1 == true */

View file

@ -73,6 +73,7 @@ int kernel_supports_dbus = 0; /* kernel supports dbus rules */
int kernel_supports_diff_encode = 0; /* kernel supports diff_encode */ int kernel_supports_diff_encode = 0; /* kernel supports diff_encode */
int kernel_supports_signal = 0; /* kernel supports signal rules */ int kernel_supports_signal = 0; /* kernel supports signal rules */
int kernel_supports_ptrace = 0; /* kernel supports ptrace rules */ int kernel_supports_ptrace = 0; /* kernel supports ptrace rules */
int kernel_supports_stacking = 0; /* kernel supports stacking */
int conf_verbose = 0; int conf_verbose = 0;
int conf_quiet = 0; int conf_quiet = 0;
int names_only = 0; int names_only = 0;

View file

@ -638,6 +638,8 @@ static void set_supported_features(void)
"policy/set_load"); "policy/set_load");
kernel_supports_diff_encode = aa_features_supports(features, kernel_supports_diff_encode = aa_features_supports(features,
"policy/diff_encode"); "policy/diff_encode");
kernel_supports_stacking = aa_features_supports(features,
"domain/stack");
if (aa_features_supports(features, "policy/versions/v7")) if (aa_features_supports(features, "policy/versions/v7"))
kernel_abi_version = 7; kernel_abi_version = 7;

View file

@ -661,8 +661,10 @@ bool label_contains_ns(const char *label)
return _parse_label(&stack, &ns, &ns_len, &name, &name_len, label) == 0 && ns; return _parse_label(&stack, &ns, &ns_len, &name, &name_len, label) == 0 && ns;
} }
void parse_label(bool *_stack, char **_ns, char **_name, const char *label) bool parse_label(bool *_stack, char **_ns, char **_name,
const char *label, bool yyerr)
{ {
const char *err = NULL;
char *ns = NULL; char *ns = NULL;
char *name = NULL; char *name = NULL;
size_t ns_len = 0; size_t ns_len = 0;
@ -671,19 +673,28 @@ void parse_label(bool *_stack, char **_ns, char **_name, const char *label)
res = _parse_label(_stack, &ns, &ns_len, &name, &name_len, label); res = _parse_label(_stack, &ns, &ns_len, &name, &name_len, label);
if (res == 1) { if (res == 1) {
yyerror(_("Namespace not terminated: %s\n"), label); err = _("Namespace not terminated: %s\n");
} else if (res == 2) { } else if (res == 2) {
yyerror(_("Empty namespace: %s\n"), label); err = _("Empty namespace: %s\n");
} else if (res == 3) { } else if (res == 3) {
yyerror(_("Empty named transition profile name: %s\n"), label); err = _("Empty named transition profile name: %s\n");
} else if (res != 0) { } else if (res != 0) {
yyerror(_("Unknown error while parsing label: %s\n"), label); err = _("Unknown error while parsing label: %s\n");
}
if (err) {
if (yyerr)
yyerror(err, label);
else
fprintf(stderr, err, label);
return false;
} }
if (ns) { if (ns) {
*_ns = strndup(ns, ns_len); *_ns = strndup(ns, ns_len);
if (!*_ns) if (!*_ns)
yyerror(_("Memory allocation error.")); goto alloc_fail;
} else { } else {
*_ns = NULL; *_ns = NULL;
} }
@ -691,8 +702,19 @@ void parse_label(bool *_stack, char **_ns, char **_name, const char *label)
*_name = strndup(name, name_len); *_name = strndup(name, name_len);
if (!*_name) { if (!*_name) {
free(*_ns); free(*_ns);
yyerror(_("Memory allocation error.")); goto alloc_fail;
} }
return true;
alloc_fail:
err = _("Memory allocation error.");
if (yyerr)
yyerror(err);
else
fprintf(stderr, "%s", err);
return false;
} }
struct cod_entry *new_entry(char *id, int mode, char *link_id) struct cod_entry *new_entry(char *id, int mode, char *link_id)

View file

@ -566,6 +566,8 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
if (entry->mode & AA_CHANGE_PROFILE) { if (entry->mode & AA_CHANGE_PROFILE) {
const char *vec[3]; const char *vec[3];
std::string lbuf, xbuf; std::string lbuf, xbuf;
autofree char *ns = NULL;
autofree char *name = NULL;
int index = 1; int index = 1;
if ((warnflags & WARN_RULE_DOWNGRADED) && entry->audit && warn_change_profile) { if ((warnflags & WARN_RULE_DOWNGRADED) && entry->audit && warn_change_profile) {
@ -585,7 +587,27 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
/* allow change_profile for all execs */ /* allow change_profile for all execs */
vec[0] = "/[^/\\x00][^\\x00]*"; vec[0] = "/[^/\\x00][^\\x00]*";
vec[index++] = tbuf.c_str(); if (!kernel_supports_stacking) {
bool stack;
if (!parse_label(&stack, &ns, &name,
tbuf.c_str(), false)) {
return FALSE;
}
if (stack) {
fprintf(stderr,
_("The current kernel does not support stacking of named transitions: %s\n"),
tbuf.c_str());
return FALSE;
}
if (ns)
vec[index++] = ns;
vec[index++] = name;
} else {
vec[index++] = tbuf.c_str();
}
/* regular change_profile rule */ /* regular change_profile rule */
if (!dfarules->add_rule_vec(entry->deny, AA_CHANGE_PROFILE | AA_ONEXEC, 0, index - 1, &vec[1], dfaflags)) if (!dfarules->add_rule_vec(entry->deny, AA_CHANGE_PROFILE | AA_ONEXEC, 0, index - 1, &vec[1], dfaflags))

View file

@ -311,7 +311,7 @@ profile_base: TOK_ID opt_id_or_var flags TOK_OPEN rules TOK_CLOSE
yyerror(_("Memory allocation error.")); yyerror(_("Memory allocation error."));
} }
parse_label(&self_stack, &prof->ns, &prof->name, $1); parse_label(&self_stack, &prof->ns, &prof->name, $1, true);
free($1); free($1);
if (self_stack) { if (self_stack) {