Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

apparmor: fix nnp subset test for unconfined

The subset test is not taking into account the unconfined exception
which will cause profile transitions in the stacked confinement
case to fail when no_new_privs is applied.

This fixes a regression introduced in the fix for
https://bugs.launchpad.net/bugs/1839037

BugLink: https://bugs.launchpad.net/bugs/1844186
Signed-off-by: John Johansen <john.johansen@canonical.com>

+39 -4
+5 -4
security/apparmor/domain.c
··· 929 929 * aways results in a further reduction of permissions. 930 930 */ 931 931 if ((bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) && 932 - !unconfined(label) && !aa_label_is_subset(new, ctx->nnp)) { 932 + !unconfined(label) && 933 + !aa_label_is_unconfined_subset(new, ctx->nnp)) { 933 934 error = -EPERM; 934 935 info = "no new privs"; 935 936 goto audit; ··· 1208 1207 * reduce restrictions. 1209 1208 */ 1210 1209 if (task_no_new_privs(current) && !unconfined(label) && 1211 - !aa_label_is_subset(new, ctx->nnp)) { 1210 + !aa_label_is_unconfined_subset(new, ctx->nnp)) { 1212 1211 /* not an apparmor denial per se, so don't log it */ 1213 1212 AA_DEBUG("no_new_privs - change_hat denied"); 1214 1213 error = -EPERM; ··· 1229 1228 * reduce restrictions. 1230 1229 */ 1231 1230 if (task_no_new_privs(current) && !unconfined(label) && 1232 - !aa_label_is_subset(previous, ctx->nnp)) { 1231 + !aa_label_is_unconfined_subset(previous, ctx->nnp)) { 1233 1232 /* not an apparmor denial per se, so don't log it */ 1234 1233 AA_DEBUG("no_new_privs - change_hat denied"); 1235 1234 error = -EPERM; ··· 1425 1424 * reduce restrictions. 1426 1425 */ 1427 1426 if (task_no_new_privs(current) && !unconfined(label) && 1428 - !aa_label_is_subset(new, ctx->nnp)) { 1427 + !aa_label_is_unconfined_subset(new, ctx->nnp)) { 1429 1428 /* not an apparmor denial per se, so don't log it */ 1430 1429 AA_DEBUG("no_new_privs - change_hat denied"); 1431 1430 error = -EPERM;
+1
security/apparmor/include/label.h
··· 281 281 struct aa_label *aa_label_alloc(int size, struct aa_proxy *proxy, gfp_t gfp); 282 282 283 283 bool aa_label_is_subset(struct aa_label *set, struct aa_label *sub); 284 + bool aa_label_is_unconfined_subset(struct aa_label *set, struct aa_label *sub); 284 285 struct aa_profile *__aa_label_next_not_in_set(struct label_it *I, 285 286 struct aa_label *set, 286 287 struct aa_label *sub);
+33
security/apparmor/label.c
··· 550 550 return __aa_label_next_not_in_set(&i, set, sub) == NULL; 551 551 } 552 552 553 + /** 554 + * aa_label_is_unconfined_subset - test if @sub is a subset of @set 555 + * @set: label to test against 556 + * @sub: label to test if is subset of @set 557 + * 558 + * This checks for subset but taking into account unconfined. IF 559 + * @sub contains an unconfined profile that does not have a matching 560 + * unconfined in @set then this will not cause the test to fail. 561 + * Conversely we don't care about an unconfined in @set that is not in 562 + * @sub 563 + * 564 + * Returns: true if @sub is special_subset of @set 565 + * else false 566 + */ 567 + bool aa_label_is_unconfined_subset(struct aa_label *set, struct aa_label *sub) 568 + { 569 + struct label_it i = { }; 570 + struct aa_profile *p; 571 + 572 + AA_BUG(!set); 573 + AA_BUG(!sub); 574 + 575 + if (sub == set) 576 + return true; 577 + 578 + do { 579 + p = __aa_label_next_not_in_set(&i, set, sub); 580 + if (p && !profile_unconfined(p)) 581 + break; 582 + } while (p); 583 + 584 + return p == NULL; 585 + } 553 586 554 587 555 588 /**