Skip to content

Commit 73f488c

Browse files
committed
apparmor: convert attaching profiles via xattrs to use dfa matching
This converts profile attachment based on xattrs to a fixed extended conditional using dfa matching. This has a couple of advantages - pattern matching can be used for the xattr match - xattrs can be optional for an attachment or marked as required - the xattr attachment conditional will be able to be combined with other extended conditionals when the flexible extended conditional work lands. The xattr fixed extended conditional is appended to the xmatch conditional. If an xattr attachment is specified the profile xmatch will be generated regardless of whether there is a pattern match on the executable name. Signed-off-by: John Johansen <[email protected]> Acked-by: Seth Arnold <[email protected]>
1 parent 8e51f90 commit 73f488c

File tree

5 files changed

+43
-57
lines changed

5 files changed

+43
-57
lines changed

security/apparmor/apparmorfs.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2147,6 +2147,10 @@ static struct aa_sfs_entry aa_sfs_entry_signal[] = {
21472147
{ }
21482148
};
21492149

2150+
static struct aa_sfs_entry aa_sfs_entry_attach[] = {
2151+
AA_SFS_FILE_BOOLEAN("xattr", 1),
2152+
{ }
2153+
};
21502154
static struct aa_sfs_entry aa_sfs_entry_domain[] = {
21512155
AA_SFS_FILE_BOOLEAN("change_hat", 1),
21522156
AA_SFS_FILE_BOOLEAN("change_hatv", 1),
@@ -2155,6 +2159,7 @@ static struct aa_sfs_entry aa_sfs_entry_domain[] = {
21552159
AA_SFS_FILE_BOOLEAN("stack", 1),
21562160
AA_SFS_FILE_BOOLEAN("fix_binfmt_elf_mmap", 1),
21572161
AA_SFS_FILE_BOOLEAN("post_nnp_subset", 1),
2162+
AA_SFS_DIR("attach_conditions", aa_sfs_entry_attach),
21582163
AA_SFS_FILE_STRING("version", "1.2"),
21592164
{ }
21602165
};

security/apparmor/domain.c

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -306,11 +306,12 @@ static int change_profile_perms(struct aa_profile *profile,
306306
* aa_xattrs_match - check whether a file matches the xattrs defined in profile
307307
* @bprm: binprm struct for the process to validate
308308
* @profile: profile to match against (NOT NULL)
309+
* @state: state to start match in
309310
*
310311
* Returns: number of extended attributes that matched, or < 0 on error
311312
*/
312313
static int aa_xattrs_match(const struct linux_binprm *bprm,
313-
struct aa_profile *profile)
314+
struct aa_profile *profile, unsigned int state)
314315
{
315316
int i;
316317
size_t size;
@@ -321,27 +322,40 @@ static int aa_xattrs_match(const struct linux_binprm *bprm,
321322
if (!bprm || !profile->xattr_count)
322323
return 0;
323324

325+
/* transition from exec match to xattr set */
326+
state = aa_dfa_null_transition(profile->xmatch, state);
327+
324328
d = bprm->file->f_path.dentry;
325329

326330
for (i = 0; i < profile->xattr_count; i++) {
327331
size = vfs_getxattr_alloc(d, profile->xattrs[i], &value,
328332
value_size, GFP_KERNEL);
329-
if (size < 0) {
330-
ret = -EINVAL;
331-
goto out;
332-
}
333+
if (size >= 0) {
334+
u32 perm;
333335

334-
/* Check the xattr value, not just presence */
335-
if (profile->xattr_lens[i]) {
336-
if (profile->xattr_lens[i] != size) {
336+
/* Check the xattr value, not just presence */
337+
state = aa_dfa_match_len(profile->xmatch, state, value,
338+
size);
339+
perm = dfa_user_allow(profile->xmatch, state);
340+
if (!(perm & MAY_EXEC)) {
337341
ret = -EINVAL;
338342
goto out;
339343
}
340-
341-
if (memcmp(value, profile->xattr_values[i], size)) {
344+
}
345+
/* transition to next element */
346+
state = aa_dfa_null_transition(profile->xmatch, state);
347+
if (size < 0) {
348+
/*
349+
* No xattr match, so verify if transition to
350+
* next element was valid. IFF so the xattr
351+
* was optional.
352+
*/
353+
if (!state) {
342354
ret = -EINVAL;
343355
goto out;
344356
}
357+
/* don't count missing optional xattr as matched */
358+
ret--;
345359
}
346360
}
347361

@@ -403,13 +417,16 @@ static struct aa_profile *__attach_match(const struct linux_binprm *bprm,
403417
perm = dfa_user_allow(profile->xmatch, state);
404418
/* any accepting state means a valid match. */
405419
if (perm & MAY_EXEC) {
406-
int ret = aa_xattrs_match(bprm, profile);
420+
int ret = aa_xattrs_match(bprm, profile, state);
407421

408422
/* Fail matching if the xattrs don't match */
409423
if (ret < 0)
410424
continue;
411425

412-
/* The new match isn't more specific
426+
/*
427+
* TODO: allow for more flexible best match
428+
*
429+
* The new match isn't more specific
413430
* than the current best match
414431
*/
415432
if (profile->xmatch_len == len &&
@@ -428,9 +445,11 @@ static struct aa_profile *__attach_match(const struct linux_binprm *bprm,
428445
xattrs = ret;
429446
conflict = false;
430447
}
431-
} else if (!strcmp(profile->base.name, name) &&
432-
aa_xattrs_match(bprm, profile) >= 0)
433-
/* exact non-re match, no more searching required */
448+
} else if (!strcmp(profile->base.name, name))
449+
/*
450+
* old exact non-re match, without conditionals such
451+
* as xattrs. no more searching required
452+
*/
434453
return profile;
435454
}
436455

@@ -652,7 +671,8 @@ static struct aa_label *profile_transition(struct aa_profile *profile,
652671
* met, and fail execution otherwise
653672
*/
654673
label_for_each(i, new, component) {
655-
if (aa_xattrs_match(bprm, component) < 0) {
674+
if (aa_xattrs_match(bprm, component, state) <
675+
0) {
656676
error = -EACCES;
657677
info = "required xattrs not present";
658678
perms.allow &= ~MAY_EXEC;

security/apparmor/include/policy.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,6 @@ struct aa_profile {
151151

152152
int xattr_count;
153153
char **xattrs;
154-
size_t *xattr_lens;
155-
char **xattr_values;
156154

157155
struct aa_rlimit rlimits;
158156

security/apparmor/policy.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -228,13 +228,9 @@ void aa_free_profile(struct aa_profile *profile)
228228
aa_free_cap_rules(&profile->caps);
229229
aa_free_rlimit_rules(&profile->rlimits);
230230

231-
for (i = 0; i < profile->xattr_count; i++) {
231+
for (i = 0; i < profile->xattr_count; i++)
232232
kzfree(profile->xattrs[i]);
233-
kzfree(profile->xattr_values[i]);
234-
}
235233
kzfree(profile->xattrs);
236-
kzfree(profile->xattr_lens);
237-
kzfree(profile->xattr_values);
238234
kzfree(profile->dirname);
239235
aa_put_dfa(profile->xmatch);
240236
aa_put_dfa(profile->policy.dfa);

security/apparmor/policy_unpack.c

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -540,8 +540,7 @@ static bool unpack_xattrs(struct aa_ext *e, struct aa_profile *profile)
540540

541541
size = unpack_array(e, NULL);
542542
profile->xattr_count = size;
543-
profile->xattrs = kcalloc(size, sizeof(char *),
544-
GFP_KERNEL);
543+
profile->xattrs = kcalloc(size, sizeof(char *), GFP_KERNEL);
545544
if (!profile->xattrs)
546545
goto fail;
547546
for (i = 0; i < size; i++) {
@@ -554,38 +553,6 @@ static bool unpack_xattrs(struct aa_ext *e, struct aa_profile *profile)
554553
goto fail;
555554
}
556555

557-
if (unpack_nameX(e, AA_STRUCT, "xattr_values")) {
558-
int i, size;
559-
560-
size = unpack_array(e, NULL);
561-
562-
/* Must be the same number of xattr values as xattrs */
563-
if (size != profile->xattr_count)
564-
goto fail;
565-
566-
profile->xattr_lens = kcalloc(size, sizeof(size_t),
567-
GFP_KERNEL);
568-
if (!profile->xattr_lens)
569-
goto fail;
570-
571-
profile->xattr_values = kcalloc(size, sizeof(char *),
572-
GFP_KERNEL);
573-
if (!profile->xattr_values)
574-
goto fail;
575-
576-
for (i = 0; i < size; i++) {
577-
profile->xattr_lens[i] = unpack_blob(e,
578-
&profile->xattr_values[i], NULL);
579-
profile->xattr_values[i] =
580-
kvmemdup(profile->xattr_values[i],
581-
profile->xattr_lens[i]);
582-
}
583-
584-
if (!unpack_nameX(e, AA_ARRAYEND, NULL))
585-
goto fail;
586-
if (!unpack_nameX(e, AA_STRUCTEND, NULL))
587-
goto fail;
588-
}
589556
return 1;
590557

591558
fail:

0 commit comments

Comments
 (0)