summaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2019-09-25 08:02:48 -0700
committerJohn Johansen <john.johansen@canonical.com>2020-01-21 05:58:04 -0800
commit3ed4aaa94fc07db3cd0c91be95e3e1b9782a2710 (patch)
treecfc3ea35aca20cc8527aed39583083a6ed414ad2 /security
parenta68d59ff4d67ec182926aaa82daaa66b3d465c9a (diff)
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>
Diffstat (limited to 'security')
-rw-r--r--security/apparmor/domain.c9
-rw-r--r--security/apparmor/include/label.h1
-rw-r--r--security/apparmor/label.c33
3 files changed, 39 insertions, 4 deletions
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index 6ceb74e0f789..f73ba303ba24 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -929,7 +929,8 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
* aways results in a further reduction of permissions.
*/
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;
info = "no new privs";
goto audit;
@@ -1207,7 +1208,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags)
* reduce restrictions.
*/
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 */
AA_DEBUG("no_new_privs - change_hat denied");
error = -EPERM;
@@ -1228,7 +1229,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags)
* reduce restrictions.
*/
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 */
AA_DEBUG("no_new_privs - change_hat denied");
error = -EPERM;
@@ -1424,7 +1425,7 @@ check:
* reduce restrictions.
*/
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 */
AA_DEBUG("no_new_privs - change_hat denied");
error = -EPERM;
diff --git a/security/apparmor/include/label.h b/security/apparmor/include/label.h
index 47942c4ba7ca..255764ab06e2 100644
--- a/security/apparmor/include/label.h
+++ b/security/apparmor/include/label.h
@@ -281,6 +281,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);
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_label *set,
struct aa_label *sub);
diff --git a/security/apparmor/label.c b/security/apparmor/label.c
index bb34094421c4..ba3987242282 100644
--- a/security/apparmor/label.c
+++ b/security/apparmor/label.c
@@ -550,6 +550,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;
}
+/**
+ * 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;
+}
/**