aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2017-11-17 20:42:42 -0500
committerJohn Johansen <john.johansen@canonical.com>2017-11-21 05:17:14 -0500
commit844b8292b6311ecd30ae63db1471edb26e01d895 (patch)
tree9c0993f64ff7eeaf3144a5063a4fb562c36c2f48
parent4633307e5ed6128975595df43f796a10c41d11c1 (diff)
apparmor: ensure that undecidable profile attachments fail
Profiles that have an undecidable overlap in their attachments are being incorrectly handled. Instead of failing to attach the first one encountered is being used. eg. profile A /** { .. } profile B /*foo { .. } have an unresolvable longest left attachment, they both have an exact match on / and then have an overlapping expression that has no clear winner. Currently the winner will be the profile that is loaded first which can result in non-deterministic behavior. Instead in this situation the exec should fail. Fixes: 898127c34ec0 ("AppArmor: functions for domain transitions") Signed-off-by: John Johansen <john.johansen@canonical.com>
-rw-r--r--security/apparmor/domain.c46
1 files changed, 32 insertions, 14 deletions
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index dd754b7850a8..9527adc11c6d 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -305,6 +305,7 @@ static int change_profile_perms(struct aa_profile *profile,
305 * __attach_match_ - find an attachment match 305 * __attach_match_ - find an attachment match
306 * @name - to match against (NOT NULL) 306 * @name - to match against (NOT NULL)
307 * @head - profile list to walk (NOT NULL) 307 * @head - profile list to walk (NOT NULL)
308 * @info - info message if there was an error (NOT NULL)
308 * 309 *
309 * Do a linear search on the profiles in the list. There is a matching 310 * Do a linear search on the profiles in the list. There is a matching
310 * preference where an exact match is preferred over a name which uses 311 * preference where an exact match is preferred over a name which uses
@@ -316,28 +317,44 @@ static int change_profile_perms(struct aa_profile *profile,
316 * Returns: profile or NULL if no match found 317 * Returns: profile or NULL if no match found
317 */ 318 */
318static struct aa_profile *__attach_match(const char *name, 319static struct aa_profile *__attach_match(const char *name,
319 struct list_head *head) 320 struct list_head *head,
321 const char **info)
320{ 322{
321 int len = 0; 323 int len = 0;
324 bool conflict = false;
322 struct aa_profile *profile, *candidate = NULL; 325 struct aa_profile *profile, *candidate = NULL;
323 326
324 list_for_each_entry_rcu(profile, head, base.list) { 327 list_for_each_entry_rcu(profile, head, base.list) {
325 if (profile->label.flags & FLAG_NULL) 328 if (profile->label.flags & FLAG_NULL)
326 continue; 329 continue;
327 if (profile->xmatch && profile->xmatch_len > len) { 330 if (profile->xmatch) {
328 unsigned int state = aa_dfa_match(profile->xmatch, 331 if (profile->xmatch_len == len) {
329 DFA_START, name); 332 conflict = true;
330 u32 perm = dfa_user_allow(profile->xmatch, state); 333 continue;
331 /* any accepting state means a valid match. */ 334 } else if (profile->xmatch_len > len) {
332 if (perm & MAY_EXEC) { 335 unsigned int state;
333 candidate = profile; 336 u32 perm;
334 len = profile->xmatch_len; 337
338 state = aa_dfa_match(profile->xmatch,
339 DFA_START, name);
340 perm = dfa_user_allow(profile->xmatch, state);
341 /* any accepting state means a valid match. */
342 if (perm & MAY_EXEC) {
343 candidate = profile;
344 len = profile->xmatch_len;
345 conflict = false;
346 }
335 } 347 }
336 } else if (!strcmp(profile->base.name, name)) 348 } else if (!strcmp(profile->base.name, name))
337 /* exact non-re match, no more searching required */ 349 /* exact non-re match, no more searching required */
338 return profile; 350 return profile;
339 } 351 }
340 352
353 if (conflict) {
354 *info = "conflicting profile attachments";
355 return NULL;
356 }
357
341 return candidate; 358 return candidate;
342} 359}
343 360
@@ -346,16 +363,17 @@ static struct aa_profile *__attach_match(const char *name,
346 * @ns: the current namespace (NOT NULL) 363 * @ns: the current namespace (NOT NULL)
347 * @list: list to search (NOT NULL) 364 * @list: list to search (NOT NULL)
348 * @name: the executable name to match against (NOT NULL) 365 * @name: the executable name to match against (NOT NULL)
366 * @info: info message if there was an error
349 * 367 *
350 * Returns: label or NULL if no match found 368 * Returns: label or NULL if no match found
351 */ 369 */
352static struct aa_label *find_attach(struct aa_ns *ns, struct list_head *list, 370static struct aa_label *find_attach(struct aa_ns *ns, struct list_head *list,
353 const char *name) 371 const char *name, const char **info)
354{ 372{
355 struct aa_profile *profile; 373 struct aa_profile *profile;
356 374
357 rcu_read_lock(); 375 rcu_read_lock();
358 profile = aa_get_profile(__attach_match(name, list)); 376 profile = aa_get_profile(__attach_match(name, list, info));
359 rcu_read_unlock(); 377 rcu_read_unlock();
360 378
361 return profile ? &profile->label : NULL; 379 return profile ? &profile->label : NULL;
@@ -448,11 +466,11 @@ static struct aa_label *x_to_label(struct aa_profile *profile,
448 if (xindex & AA_X_CHILD) 466 if (xindex & AA_X_CHILD)
449 /* released by caller */ 467 /* released by caller */
450 new = find_attach(ns, &profile->base.profiles, 468 new = find_attach(ns, &profile->base.profiles,
451 name); 469 name, info);
452 else 470 else
453 /* released by caller */ 471 /* released by caller */
454 new = find_attach(ns, &ns->base.profiles, 472 new = find_attach(ns, &ns->base.profiles,
455 name); 473 name, info);
456 *lookupname = name; 474 *lookupname = name;
457 break; 475 break;
458 } 476 }
@@ -516,7 +534,7 @@ static struct aa_label *profile_transition(struct aa_profile *profile,
516 534
517 if (profile_unconfined(profile)) { 535 if (profile_unconfined(profile)) {
518 new = find_attach(profile->ns, &profile->ns->base.profiles, 536 new = find_attach(profile->ns, &profile->ns->base.profiles,
519 name); 537 name, &info);
520 if (new) { 538 if (new) {
521 AA_DEBUG("unconfined attached to new label"); 539 AA_DEBUG("unconfined attached to new label");
522 return new; 540 return new;