mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-22 10:07:12 +00:00
parser: add support for matching based on extended file attributes
Add userland support for matching based on extended file attributes. This leverages DFA based matching already in the kernel: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=8e51f908 https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=73f488cd Matching is exposed via flags on the profile: /usr/bin/* xattrs=(user.foo=bar user.bar=**) { # ... } Profiles list the set of extended attributes that a file MUST have, and a regex to match the value of that extended attributes. Additional extended attributes on the file don't effect the match. Signed-off-by: Eric Chiang <ericchiang@google.com>
This commit is contained in:
parent
6804731892
commit
a42fd8c6f4
@ -124,6 +124,44 @@ bool aare_rules::add_rule_vec(int deny, uint32_t perms, uint32_t audit,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* append_rule is like add_rule, but appends the rule to any existing rules
|
||||||
|
* with a null transition. The appended rule matches with the same permissions
|
||||||
|
* as the rule it's appended to.
|
||||||
|
*
|
||||||
|
* This is used by xattrs matching where, after matching the path, the DFA is
|
||||||
|
* advanced by a null character for each xattr.
|
||||||
|
*/
|
||||||
|
bool aare_rules::append_rule(const char *rule, dfaflags_t flags)
|
||||||
|
{
|
||||||
|
Node *tree = NULL;
|
||||||
|
if (regex_parse(&tree, rule))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (flags & DFA_DUMP_RULE_EXPR) {
|
||||||
|
cerr << "rule: ";
|
||||||
|
cerr << rule;
|
||||||
|
cerr << " -> ";
|
||||||
|
tree->dump(cerr);
|
||||||
|
cerr << "\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For each matching state, we want to create an optional path
|
||||||
|
* separated by a null character.
|
||||||
|
*
|
||||||
|
* When matching xattrs, the DFA must end up in an accepting state for
|
||||||
|
* the path, then each value of the xattrs. Using an optional node
|
||||||
|
* lets each rule end up in an accepting state.
|
||||||
|
*/
|
||||||
|
tree = new OptionalNode(new CatNode(new CharNode(0), tree));
|
||||||
|
PermExprMap::iterator it;
|
||||||
|
for (it = expr_map.begin(); it != expr_map.end(); it++) {
|
||||||
|
expr_map[it->first] = new CatNode(it->second, tree);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* create a dfa from the ruleset
|
/* create a dfa from the ruleset
|
||||||
* returns: buffer contain dfa tables, @size set to the size of the tables
|
* returns: buffer contain dfa tables, @size set to the size of the tables
|
||||||
* else NULL on failure, @min_match_len set to the shortest string
|
* else NULL on failure, @min_match_len set to the shortest string
|
||||||
|
@ -104,6 +104,7 @@ class aare_rules {
|
|||||||
uint32_t audit, dfaflags_t flags);
|
uint32_t audit, dfaflags_t flags);
|
||||||
bool add_rule_vec(int deny, uint32_t perms, uint32_t audit, int count,
|
bool add_rule_vec(int deny, uint32_t perms, uint32_t audit, int count,
|
||||||
const char **rulev, dfaflags_t flags);
|
const char **rulev, dfaflags_t flags);
|
||||||
|
bool append_rule(const char *rule, dfaflags_t flags);
|
||||||
void *create_dfa(size_t *size, int *min_match_len, dfaflags_t flags);
|
void *create_dfa(size_t *size, int *min_match_len, dfaflags_t flags);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -534,6 +534,9 @@ static void count_tree_nodes(Node *t, struct node_counts *counts)
|
|||||||
} else if (dynamic_cast<StarNode *>(t)) {
|
} else if (dynamic_cast<StarNode *>(t)) {
|
||||||
counts->star++;
|
counts->star++;
|
||||||
count_tree_nodes(t->child[0], counts);
|
count_tree_nodes(t->child[0], counts);
|
||||||
|
} else if (dynamic_cast<OptionalNode *>(t)) {
|
||||||
|
counts->optional++;
|
||||||
|
count_tree_nodes(t->child[0], counts);
|
||||||
} else if (dynamic_cast<CharNode *>(t)) {
|
} else if (dynamic_cast<CharNode *>(t)) {
|
||||||
counts->charnode++;
|
counts->charnode++;
|
||||||
} else if (dynamic_cast<AnyCharNode *>(t)) {
|
} else if (dynamic_cast<AnyCharNode *>(t)) {
|
||||||
@ -559,7 +562,7 @@ Node *simplify_tree(Node *t, dfaflags_t flags)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (flags & DFA_DUMP_TREE_STATS) {
|
if (flags & DFA_DUMP_TREE_STATS) {
|
||||||
struct node_counts counts = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
struct node_counts counts = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||||
count_tree_nodes(t, &counts);
|
count_tree_nodes(t, &counts);
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"expr tree: c %d, [] %d, [^] %d, | %d, + %d, * %d, . %d, cat %d\n",
|
"expr tree: c %d, [] %d, [^] %d, | %d, + %d, * %d, . %d, cat %d\n",
|
||||||
@ -595,7 +598,7 @@ Node *simplify_tree(Node *t, dfaflags_t flags)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (flags & DFA_DUMP_TREE_STATS) {
|
if (flags & DFA_DUMP_TREE_STATS) {
|
||||||
struct node_counts counts = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
struct node_counts counts = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||||
count_tree_nodes(t, &counts);
|
count_tree_nodes(t, &counts);
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"simplified expr tree: c %d, [] %d, [^] %d, | %d, + %d, * %d, . %d, cat %d\n",
|
"simplified expr tree: c %d, [] %d, [^] %d, | %d, + %d, * %d, . %d, cat %d\n",
|
||||||
|
@ -482,6 +482,26 @@ public:
|
|||||||
bool contains_null() { return child[0]->contains_null(); }
|
bool contains_null() { return child[0]->contains_null(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Match a node zero or one times. */
|
||||||
|
class OptionalNode: public OneChildNode {
|
||||||
|
public:
|
||||||
|
OptionalNode(Node *left): OneChildNode(left) { nullable = true; }
|
||||||
|
void compute_firstpos() { firstpos = child[0]->firstpos; }
|
||||||
|
void compute_lastpos() { lastpos = child[0]->lastpos; }
|
||||||
|
int eq(Node *other)
|
||||||
|
{
|
||||||
|
if (dynamic_cast<OptionalNode *>(other))
|
||||||
|
return child[0]->eq(other->child[0]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ostream &dump(ostream &os)
|
||||||
|
{
|
||||||
|
os << '(';
|
||||||
|
child[0]->dump(os);
|
||||||
|
return os << ")?";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/* Match a node one or more times. (This is a unary operator.) */
|
/* Match a node one or more times. (This is a unary operator.) */
|
||||||
class PlusNode: public OneChildNode {
|
class PlusNode: public OneChildNode {
|
||||||
public:
|
public:
|
||||||
@ -713,6 +733,7 @@ struct node_counts {
|
|||||||
int alt;
|
int alt;
|
||||||
int plus;
|
int plus;
|
||||||
int star;
|
int star;
|
||||||
|
int optional;
|
||||||
int any;
|
int any;
|
||||||
int cat;
|
int cat;
|
||||||
};
|
};
|
||||||
|
@ -371,6 +371,28 @@ void sd_serialize_xtable(std::ostringstream &buf, char **table)
|
|||||||
sd_write_structend(buf);
|
sd_write_structend(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sd_serialize_xattrs(std::ostringstream &buf, struct cond_entry_list xattrs)
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
struct cond_entry *entry;
|
||||||
|
|
||||||
|
if (!(xattrs.list))
|
||||||
|
return;
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
for (entry = xattrs.list; entry; entry = entry->next) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
sd_write_struct(buf, "xattrs");
|
||||||
|
sd_write_array(buf, NULL, count);
|
||||||
|
for (entry = xattrs.list; entry; entry = entry->next) {
|
||||||
|
sd_write_string(buf, entry->name, NULL);
|
||||||
|
}
|
||||||
|
sd_write_arrayend(buf);
|
||||||
|
sd_write_structend(buf);
|
||||||
|
}
|
||||||
|
|
||||||
void sd_serialize_profile(std::ostringstream &buf, Profile *profile,
|
void sd_serialize_profile(std::ostringstream &buf, Profile *profile,
|
||||||
int flattened)
|
int flattened)
|
||||||
{
|
{
|
||||||
@ -432,6 +454,8 @@ void sd_serialize_profile(std::ostringstream &buf, Profile *profile,
|
|||||||
sd_write_uint32(buf, 0);
|
sd_write_uint32(buf, 0);
|
||||||
sd_write_structend(buf);
|
sd_write_structend(buf);
|
||||||
|
|
||||||
|
sd_serialize_xattrs(buf, profile->xattrs);
|
||||||
|
|
||||||
sd_serialize_rlimits(buf, &profile->rlimits);
|
sd_serialize_rlimits(buf, &profile->rlimits);
|
||||||
|
|
||||||
if (profile->net.allow && kernel_supports_network) {
|
if (profile->net.allow && kernel_supports_network) {
|
||||||
|
@ -308,7 +308,7 @@ GT >
|
|||||||
}
|
}
|
||||||
|
|
||||||
<INITIAL,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE>{
|
<INITIAL,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE>{
|
||||||
peer/{WS}*={WS}*\( {
|
(peer|xattrs)/{WS}*={WS}*\( {
|
||||||
/* we match to the = in the lexer so that we can switch scanner
|
/* we match to the = in the lexer so that we can switch scanner
|
||||||
* state. By the time the parser see the = it may be too late
|
* state. By the time the parser see the = it may be too late
|
||||||
* as bison may have requested the next token from the scanner
|
* as bison may have requested the next token from the scanner
|
||||||
|
@ -432,12 +432,29 @@ static const char *local_name(const char *name)
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get_xattr_value returns the value of an xattr expression, performing NULL
|
||||||
|
* checks along the way. The method returns NULL if the xattr match doesn't
|
||||||
|
* have an xattrs (though this case currently isn't permitted by the parser).
|
||||||
|
*/
|
||||||
|
char *get_xattr_value(struct cond_entry *entry)
|
||||||
|
{
|
||||||
|
if (!entry->eq)
|
||||||
|
return NULL;
|
||||||
|
if (!entry->vals)
|
||||||
|
return NULL;
|
||||||
|
return entry->vals->value;
|
||||||
|
}
|
||||||
|
|
||||||
static int process_profile_name_xmatch(Profile *prof)
|
static int process_profile_name_xmatch(Profile *prof)
|
||||||
{
|
{
|
||||||
std::string tbuf;
|
std::string tbuf;
|
||||||
pattern_t ptype;
|
pattern_t ptype;
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
|
struct cond_entry *entry;
|
||||||
|
const char *xattr_value;
|
||||||
|
|
||||||
/* don't filter_slashes for profile names */
|
/* don't filter_slashes for profile names */
|
||||||
if (prof->attachment)
|
if (prof->attachment)
|
||||||
name = prof->attachment;
|
name = prof->attachment;
|
||||||
@ -451,7 +468,7 @@ static int process_profile_name_xmatch(Profile *prof)
|
|||||||
if (ptype == ePatternInvalid) {
|
if (ptype == ePatternInvalid) {
|
||||||
PERROR(_("%s: Invalid profile name '%s' - bad regular expression\n"), progname, name);
|
PERROR(_("%s: Invalid profile name '%s' - bad regular expression\n"), progname, name);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
} else if (ptype == ePatternBasic && !(prof->altnames || prof->attachment)) {
|
} else if (ptype == ePatternBasic && !(prof->altnames || prof->attachment || prof->xattrs.list)) {
|
||||||
/* no regex so do not set xmatch */
|
/* no regex so do not set xmatch */
|
||||||
prof->xmatch = NULL;
|
prof->xmatch = NULL;
|
||||||
prof->xmatch_len = 0;
|
prof->xmatch_len = 0;
|
||||||
@ -479,6 +496,28 @@ static int process_profile_name_xmatch(Profile *prof)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (prof->xattrs.list) {
|
||||||
|
for (entry = prof->xattrs.list; entry; entry = entry->next) {
|
||||||
|
xattr_value = get_xattr_value(entry);
|
||||||
|
if (!xattr_value)
|
||||||
|
xattr_value = "**"; // Default to allowing any value.
|
||||||
|
/* len is measured because it's required to
|
||||||
|
* convert the regex to pcre, but doesn't impact
|
||||||
|
* xmatch_len. The kernel uses the number of
|
||||||
|
* xattrs matched to prioritized in addition to
|
||||||
|
* xmatch_len.
|
||||||
|
*/
|
||||||
|
int len;
|
||||||
|
tbuf.clear();
|
||||||
|
convert_aaregex_to_pcre(xattr_value, 0,
|
||||||
|
glob_default, tbuf,
|
||||||
|
&len);
|
||||||
|
if (!rules->append_rule(tbuf.c_str(), dfaflags)) {
|
||||||
|
delete rules;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
prof->xmatch = rules->create_dfa(&prof->xmatch_size, &prof->xmatch_len, dfaflags);
|
prof->xmatch = rules->create_dfa(&prof->xmatch_size, &prof->xmatch_len, dfaflags);
|
||||||
delete rules;
|
delete rules;
|
||||||
if (!prof->xmatch)
|
if (!prof->xmatch)
|
||||||
|
@ -306,9 +306,9 @@ opt_id: { /* nothing */ $$ = NULL; }
|
|||||||
opt_id_or_var: { /* nothing */ $$ = NULL; }
|
opt_id_or_var: { /* nothing */ $$ = NULL; }
|
||||||
| id_or_var { $$ = $1; }
|
| id_or_var { $$ = $1; }
|
||||||
|
|
||||||
profile_base: TOK_ID opt_id_or_var flags TOK_OPEN rules TOK_CLOSE
|
profile_base: TOK_ID opt_id_or_var opt_cond_list flags TOK_OPEN rules TOK_CLOSE
|
||||||
{
|
{
|
||||||
Profile *prof = $5;
|
Profile *prof = $6;
|
||||||
bool self_stack = false;
|
bool self_stack = false;
|
||||||
|
|
||||||
if (!prof) {
|
if (!prof) {
|
||||||
@ -342,7 +342,13 @@ profile_base: TOK_ID opt_id_or_var flags TOK_OPEN rules TOK_CLOSE
|
|||||||
prof->attachment = $2;
|
prof->attachment = $2;
|
||||||
if ($2 && !($2[0] == '/' || strncmp($2, "@{", 2) == 0))
|
if ($2 && !($2[0] == '/' || strncmp($2, "@{", 2) == 0))
|
||||||
yyerror(_("Profile attachment must begin with a '/' or variable."));
|
yyerror(_("Profile attachment must begin with a '/' or variable."));
|
||||||
prof->flags = $3;
|
if ($3.name) {
|
||||||
|
if (strcmp($3.name, "xattrs") != 0)
|
||||||
|
yyerror(_("profile id: invalid conditional group %s=()"), $3.name);
|
||||||
|
free ($3.name);
|
||||||
|
prof->xattrs = $3;
|
||||||
|
}
|
||||||
|
prof->flags = $4;
|
||||||
if (force_complain && kernel_abi_version == 5)
|
if (force_complain && kernel_abi_version == 5)
|
||||||
/* newer abis encode force complain as part of the
|
/* newer abis encode force complain as part of the
|
||||||
* header
|
* header
|
||||||
@ -393,6 +399,12 @@ hat: hat_start profile_base
|
|||||||
Profile *prof = $2;
|
Profile *prof = $2;
|
||||||
if ($2)
|
if ($2)
|
||||||
PDEBUG("Matched: hat %s { ... }\n", prof->name);
|
PDEBUG("Matched: hat %s { ... }\n", prof->name);
|
||||||
|
/*
|
||||||
|
* It isn't clear what a xattrs match on a hat profile
|
||||||
|
* should do, disallow it for now.
|
||||||
|
*/
|
||||||
|
if ($2->xattrs.list)
|
||||||
|
yyerror("hat profiles can't use xattrs matches");
|
||||||
|
|
||||||
prof->flags.hat = 1;
|
prof->flags.hat = 1;
|
||||||
$$ = prof;
|
$$ = prof;
|
||||||
|
@ -120,6 +120,8 @@ public:
|
|||||||
size_t xmatch_size;
|
size_t xmatch_size;
|
||||||
int xmatch_len;
|
int xmatch_len;
|
||||||
|
|
||||||
|
struct cond_entry_list xattrs;
|
||||||
|
|
||||||
/* char *sub_name; */ /* subdomain name or NULL */
|
/* char *sub_name; */ /* subdomain name or NULL */
|
||||||
/* int default_deny; */ /* TRUE or FALSE */
|
/* int default_deny; */ /* TRUE or FALSE */
|
||||||
int local;
|
int local;
|
||||||
@ -151,6 +153,8 @@ public:
|
|||||||
xmatch_size = 0;
|
xmatch_size = 0;
|
||||||
xmatch_len = 0;
|
xmatch_len = 0;
|
||||||
|
|
||||||
|
xattrs.list = NULL;
|
||||||
|
|
||||||
local = local_mode = local_audit = 0;
|
local = local_mode = local_audit = 0;
|
||||||
|
|
||||||
parent = NULL;
|
parent = NULL;
|
||||||
|
7
parser/tst/simple_tests/xattrs/bad_01.sd
Normal file
7
parser/tst/simple_tests/xattrs/bad_01.sd
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#
|
||||||
|
#=Description wrong conditional group
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/xattrs-test peer=(myvalue=foo) {
|
||||||
|
/foo r,
|
||||||
|
}
|
7
parser/tst/simple_tests/xattrs/bad_02.sd
Normal file
7
parser/tst/simple_tests/xattrs/bad_02.sd
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#
|
||||||
|
#=Description no xattrs value
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/xattrs-test xattrs=(myvalue) {
|
||||||
|
/foo r,
|
||||||
|
}
|
7
parser/tst/simple_tests/xattrs/bad_03.sd
Normal file
7
parser/tst/simple_tests/xattrs/bad_03.sd
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#
|
||||||
|
#=Description flags before xattrs
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/xattrs-test flags=(complain) xattrs=(myvalue=foo) {
|
||||||
|
/foo r,
|
||||||
|
}
|
10
parser/tst/simple_tests/xattrs/hats_01.sd
Normal file
10
parser/tst/simple_tests/xattrs/hats_01.sd
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#
|
||||||
|
#=Description hat profile with xattrs
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/xattrs-test {
|
||||||
|
^hat xattrs=(myvalue=foo) {
|
||||||
|
/foo r,
|
||||||
|
}
|
||||||
|
/foo w,
|
||||||
|
}
|
7
parser/tst/simple_tests/xattrs/ok_01.sd
Normal file
7
parser/tst/simple_tests/xattrs/ok_01.sd
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#
|
||||||
|
#=Description basic xattr value
|
||||||
|
#=EXRESULT PASS
|
||||||
|
#
|
||||||
|
/usr/bin/xattrs-test xattrs=(myvalue=foo) {
|
||||||
|
/foo r,
|
||||||
|
}
|
7
parser/tst/simple_tests/xattrs/ok_02.sd
Normal file
7
parser/tst/simple_tests/xattrs/ok_02.sd
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#
|
||||||
|
#=Description xattrs with quoted value
|
||||||
|
#=EXRESULT PASS
|
||||||
|
#
|
||||||
|
/usr/bin/xattrs-test xattrs=(myvalue="foo.bar") {
|
||||||
|
/foo r,
|
||||||
|
}
|
7
parser/tst/simple_tests/xattrs/ok_03.sd
Normal file
7
parser/tst/simple_tests/xattrs/ok_03.sd
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#
|
||||||
|
#=Description match any value of an xattr
|
||||||
|
#=EXRESULT PASS
|
||||||
|
#
|
||||||
|
/usr/bin/xattrs-test xattrs=(myvalue="*") {
|
||||||
|
/foo r,
|
||||||
|
}
|
7
parser/tst/simple_tests/xattrs/ok_04.sd
Normal file
7
parser/tst/simple_tests/xattrs/ok_04.sd
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#
|
||||||
|
#=Description key with '.' character
|
||||||
|
#=EXRESULT PASS
|
||||||
|
#
|
||||||
|
/usr/bin/xattrs-test xattrs=(hello.world=foo) {
|
||||||
|
/foo r,
|
||||||
|
}
|
7
parser/tst/simple_tests/xattrs/ok_05.sd
Normal file
7
parser/tst/simple_tests/xattrs/ok_05.sd
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#
|
||||||
|
#=Description multiple xattrs
|
||||||
|
#=EXRESULT PASS
|
||||||
|
#
|
||||||
|
/usr/bin/xattrs-test xattrs=(hello.world=foo goodbye.word=bar) {
|
||||||
|
/foo r,
|
||||||
|
}
|
7
parser/tst/simple_tests/xattrs/ok_06.sd
Normal file
7
parser/tst/simple_tests/xattrs/ok_06.sd
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#
|
||||||
|
#=Description xattrs then flags
|
||||||
|
#=EXRESULT PASS
|
||||||
|
#
|
||||||
|
/usr/bin/xattrs-test xattrs=(myvalue=foo) flags=(audit, mediate_deleted) {
|
||||||
|
/foo r,
|
||||||
|
}
|
8
parser/tst/simple_tests/xattrs/ok_07.sd
Normal file
8
parser/tst/simple_tests/xattrs/ok_07.sd
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=Description named profile
|
||||||
|
#=EXRESULT PASS
|
||||||
|
#
|
||||||
|
|
||||||
|
profile xattrs-test /usr/bin/hi xattrs=(user.foo=* user.bar=*) {
|
||||||
|
/foo r,
|
||||||
|
}
|
8
parser/tst/simple_tests/xattrs/ok_08.sd
Normal file
8
parser/tst/simple_tests/xattrs/ok_08.sd
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=Description named profile without path
|
||||||
|
#=EXRESULT PASS
|
||||||
|
#
|
||||||
|
|
||||||
|
profile xattrs-test xattrs=(user.foo="bar") {
|
||||||
|
/foo r,
|
||||||
|
}
|
7
parser/tst/simple_tests/xattrs/ok_09.sd
Normal file
7
parser/tst/simple_tests/xattrs/ok_09.sd
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#
|
||||||
|
#=Description profile with xattrs then flags
|
||||||
|
#=EXRESULT PASS
|
||||||
|
#
|
||||||
|
/usr/bin/xattrs-test xattrs=(myvalue=foo) flags=(complain) {
|
||||||
|
/foo r,
|
||||||
|
}
|
@ -45,7 +45,7 @@ RE_PROFILE_CONDITIONAL_VARIABLE = re.compile('^\s*if\s+(not\s+)?defined\s+(@\{?\
|
|||||||
RE_PROFILE_CONDITIONAL_BOOLEAN = re.compile('^\s*if\s+(not\s+)?defined\s+(\$\{?\w+\}?)\s*\{\s*(#.*)?$')
|
RE_PROFILE_CONDITIONAL_BOOLEAN = re.compile('^\s*if\s+(not\s+)?defined\s+(\$\{?\w+\}?)\s*\{\s*(#.*)?$')
|
||||||
RE_PROFILE_NETWORK = re.compile(RE_AUDIT_DENY + 'network(?P<details>\s+.*)?' + RE_COMMA_EOL)
|
RE_PROFILE_NETWORK = re.compile(RE_AUDIT_DENY + 'network(?P<details>\s+.*)?' + RE_COMMA_EOL)
|
||||||
RE_PROFILE_CHANGE_HAT = re.compile('^\s*\^(\"??.+?\"??)' + RE_COMMA_EOL)
|
RE_PROFILE_CHANGE_HAT = re.compile('^\s*\^(\"??.+?\"??)' + RE_COMMA_EOL)
|
||||||
RE_PROFILE_HAT_DEF = re.compile('^(?P<leadingspace>\s*)(?P<hat_keyword>\^|hat\s+)(?P<hat>\"??[^)]+?\"??)' + RE_XATTRS + RE_FLAGS + '\s*\{' + RE_EOL)
|
RE_PROFILE_HAT_DEF = re.compile('^(?P<leadingspace>\s*)(?P<hat_keyword>\^|hat\s+)(?P<hat>\"??[^)]+?\"??)' + RE_FLAGS + '\s*\{' + RE_EOL)
|
||||||
RE_PROFILE_DBUS = re.compile(RE_AUDIT_DENY + '(dbus\s*,|dbus(?P<details>\s+[^#]*)\s*,)' + RE_EOL)
|
RE_PROFILE_DBUS = re.compile(RE_AUDIT_DENY + '(dbus\s*,|dbus(?P<details>\s+[^#]*)\s*,)' + RE_EOL)
|
||||||
RE_PROFILE_MOUNT = re.compile(RE_AUDIT_DENY + '((mount|remount|umount|unmount)(\s+[^#]*)?\s*,)' + RE_EOL)
|
RE_PROFILE_MOUNT = re.compile(RE_AUDIT_DENY + '((mount|remount|umount|unmount)(\s+[^#]*)?\s*,)' + RE_EOL)
|
||||||
RE_PROFILE_SIGNAL = re.compile(RE_AUDIT_DENY + '(signal\s*,|signal(?P<details>\s+[^#]*)\s*,)' + RE_EOL)
|
RE_PROFILE_SIGNAL = re.compile(RE_AUDIT_DENY + '(signal\s*,|signal(?P<details>\s+[^#]*)\s*,)' + RE_EOL)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user