apparmor: fix nnp subset test for unconfined
[ Upstream commit 3ed4aaa94fc07db3cd0c91be95e3e1b9782a2710 ] 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> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
890775dc6a
commit
3cc2aec68e
3 changed files with 39 additions and 4 deletions
|
@ -939,7 +939,8 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
|
||||||
* aways results in a further reduction of permissions.
|
* aways results in a further reduction of permissions.
|
||||||
*/
|
*/
|
||||||
if ((bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) &&
|
if ((bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) &&
|
||||||
!unconfined(label) && !aa_label_is_subset(new, ctx->nnp)) {
|
!unconfined(label) &&
|
||||||
|
!aa_label_is_unconfined_subset(new, ctx->nnp)) {
|
||||||
error = -EPERM;
|
error = -EPERM;
|
||||||
info = "no new privs";
|
info = "no new privs";
|
||||||
goto audit;
|
goto audit;
|
||||||
|
@ -1217,7 +1218,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags)
|
||||||
* reduce restrictions.
|
* reduce restrictions.
|
||||||
*/
|
*/
|
||||||
if (task_no_new_privs(current) && !unconfined(label) &&
|
if (task_no_new_privs(current) && !unconfined(label) &&
|
||||||
!aa_label_is_subset(new, ctx->nnp)) {
|
!aa_label_is_unconfined_subset(new, ctx->nnp)) {
|
||||||
/* not an apparmor denial per se, so don't log it */
|
/* not an apparmor denial per se, so don't log it */
|
||||||
AA_DEBUG("no_new_privs - change_hat denied");
|
AA_DEBUG("no_new_privs - change_hat denied");
|
||||||
error = -EPERM;
|
error = -EPERM;
|
||||||
|
@ -1238,7 +1239,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags)
|
||||||
* reduce restrictions.
|
* reduce restrictions.
|
||||||
*/
|
*/
|
||||||
if (task_no_new_privs(current) && !unconfined(label) &&
|
if (task_no_new_privs(current) && !unconfined(label) &&
|
||||||
!aa_label_is_subset(previous, ctx->nnp)) {
|
!aa_label_is_unconfined_subset(previous, ctx->nnp)) {
|
||||||
/* not an apparmor denial per se, so don't log it */
|
/* not an apparmor denial per se, so don't log it */
|
||||||
AA_DEBUG("no_new_privs - change_hat denied");
|
AA_DEBUG("no_new_privs - change_hat denied");
|
||||||
error = -EPERM;
|
error = -EPERM;
|
||||||
|
@ -1433,7 +1434,7 @@ int aa_change_profile(const char *fqname, int flags)
|
||||||
* reduce restrictions.
|
* reduce restrictions.
|
||||||
*/
|
*/
|
||||||
if (task_no_new_privs(current) && !unconfined(label) &&
|
if (task_no_new_privs(current) && !unconfined(label) &&
|
||||||
!aa_label_is_subset(new, ctx->nnp)) {
|
!aa_label_is_unconfined_subset(new, ctx->nnp)) {
|
||||||
/* not an apparmor denial per se, so don't log it */
|
/* not an apparmor denial per se, so don't log it */
|
||||||
AA_DEBUG("no_new_privs - change_hat denied");
|
AA_DEBUG("no_new_privs - change_hat denied");
|
||||||
error = -EPERM;
|
error = -EPERM;
|
||||||
|
|
|
@ -285,6 +285,7 @@ bool aa_label_init(struct aa_label *label, int size, gfp_t gfp);
|
||||||
struct aa_label *aa_label_alloc(int size, struct aa_proxy *proxy, gfp_t gfp);
|
struct aa_label *aa_label_alloc(int size, struct aa_proxy *proxy, gfp_t gfp);
|
||||||
|
|
||||||
bool aa_label_is_subset(struct aa_label *set, struct aa_label *sub);
|
bool aa_label_is_subset(struct aa_label *set, struct aa_label *sub);
|
||||||
|
bool aa_label_is_unconfined_subset(struct aa_label *set, struct aa_label *sub);
|
||||||
struct aa_profile *__aa_label_next_not_in_set(struct label_it *I,
|
struct aa_profile *__aa_label_next_not_in_set(struct label_it *I,
|
||||||
struct aa_label *set,
|
struct aa_label *set,
|
||||||
struct aa_label *sub);
|
struct aa_label *sub);
|
||||||
|
|
|
@ -554,6 +554,39 @@ bool aa_label_is_subset(struct aa_label *set, struct aa_label *sub)
|
||||||
return __aa_label_next_not_in_set(&i, set, sub) == NULL;
|
return __aa_label_next_not_in_set(&i, set, sub) == NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* aa_label_is_unconfined_subset - test if @sub is a subset of @set
|
||||||
|
* @set: label to test against
|
||||||
|
* @sub: label to test if is subset of @set
|
||||||
|
*
|
||||||
|
* This checks for subset but taking into account unconfined. IF
|
||||||
|
* @sub contains an unconfined profile that does not have a matching
|
||||||
|
* unconfined in @set then this will not cause the test to fail.
|
||||||
|
* Conversely we don't care about an unconfined in @set that is not in
|
||||||
|
* @sub
|
||||||
|
*
|
||||||
|
* Returns: true if @sub is special_subset of @set
|
||||||
|
* else false
|
||||||
|
*/
|
||||||
|
bool aa_label_is_unconfined_subset(struct aa_label *set, struct aa_label *sub)
|
||||||
|
{
|
||||||
|
struct label_it i = { };
|
||||||
|
struct aa_profile *p;
|
||||||
|
|
||||||
|
AA_BUG(!set);
|
||||||
|
AA_BUG(!sub);
|
||||||
|
|
||||||
|
if (sub == set)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
do {
|
||||||
|
p = __aa_label_next_not_in_set(&i, set, sub);
|
||||||
|
if (p && !profile_unconfined(p))
|
||||||
|
break;
|
||||||
|
} while (p);
|
||||||
|
|
||||||
|
return p == NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue