summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2017-10-08 21:26:19 -0400
committerJohn Johansen <john.johansen@canonical.com>2018-02-09 14:30:01 -0500
commit9fcf78cca198600b27c44b4e50f00f8af3927f17 (patch)
tree7399172a2190db01668808fe8d6782c29145428b
parentd8889d49e414b371eb235c08c3a759ab3e0cfa51 (diff)
apparmor: update domain transitions that are subsets of confinement at nnp
Domain transition so far have been largely blocked by no new privs, unless the transition has been provably a subset of the previous confinement. There was a couple problems with the previous implementations, - transitions that weren't explicitly a stack but resulted in a subset of confinement were disallowed - confinement subsets were only calculated from the previous confinement instead of the confinement being enforced at the time of no new privs, so transitions would have to get progressively tighter. Fix this by detecting and storing a reference to the task's confinement at the "time" no new privs is set. This reference is then used to determine whether a transition is a subsystem of the confinement at the time no new privs was set. Unfortunately the implementation is less than ideal in that we have to detect no new privs after the fact when a task attempts a domain transition. This is adequate for the currently but will not work in a stacking situation where no new privs could be conceivably be set in both the "host" and in the container. Signed-off-by: John Johansen <john.johansen@canonical.com>
-rw-r--r--security/apparmor/apparmorfs.c1
-rw-r--r--security/apparmor/domain.c163
-rw-r--r--security/apparmor/include/task.h4
-rw-r--r--security/apparmor/task.c7
4 files changed, 110 insertions, 65 deletions
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 874c1bf6b84a..07623fb41e32 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -2156,6 +2156,7 @@ static struct aa_sfs_entry aa_sfs_entry_domain[] = {
2156 AA_SFS_FILE_BOOLEAN("change_profile", 1), 2156 AA_SFS_FILE_BOOLEAN("change_profile", 1),
2157 AA_SFS_FILE_BOOLEAN("stack", 1), 2157 AA_SFS_FILE_BOOLEAN("stack", 1),
2158 AA_SFS_FILE_BOOLEAN("fix_binfmt_elf_mmap", 1), 2158 AA_SFS_FILE_BOOLEAN("fix_binfmt_elf_mmap", 1),
2159 AA_SFS_FILE_BOOLEAN("post_nnp_subset", 1),
2159 AA_SFS_FILE_STRING("version", "1.2"), 2160 AA_SFS_FILE_STRING("version", "1.2"),
2160 { } 2161 { }
2161}; 2162};
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index cd58eef4eb8d..9d1936519cfd 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -592,22 +592,6 @@ static struct aa_label *profile_transition(struct aa_profile *profile,
592 if (!new) 592 if (!new)
593 goto audit; 593 goto audit;
594 594
595 /* Policy has specified a domain transitions. if no_new_privs and
596 * confined and not transitioning to the current domain fail.
597 *
598 * NOTE: Domain transitions from unconfined and to stritly stacked
599 * subsets are allowed even when no_new_privs is set because this
600 * aways results in a further reduction of permissions.
601 */
602 if ((bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) &&
603 !profile_unconfined(profile) &&
604 !aa_label_is_subset(new, &profile->label)) {
605 error = -EPERM;
606 info = "no new privs";
607 nonewprivs = true;
608 perms.allow &= ~MAY_EXEC;
609 goto audit;
610 }
611 595
612 if (!(perms.xindex & AA_X_UNSAFE)) { 596 if (!(perms.xindex & AA_X_UNSAFE)) {
613 if (DEBUG_ON) { 597 if (DEBUG_ON) {
@@ -684,21 +668,6 @@ static int profile_onexec(struct aa_profile *profile, struct aa_label *onexec,
684 perms.allow &= ~AA_MAY_ONEXEC; 668 perms.allow &= ~AA_MAY_ONEXEC;
685 goto audit; 669 goto audit;
686 } 670 }
687 /* Policy has specified a domain transitions. if no_new_privs and
688 * confined and not transitioning to the current domain fail.
689 *
690 * NOTE: Domain transitions from unconfined and to stritly stacked
691 * subsets are allowed even when no_new_privs is set because this
692 * aways results in a further reduction of permissions.
693 */
694 if ((bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) &&
695 !profile_unconfined(profile) &&
696 !aa_label_is_subset(onexec, &profile->label)) {
697 error = -EPERM;
698 info = "no new privs";
699 perms.allow &= ~AA_MAY_ONEXEC;
700 goto audit;
701 }
702 671
703 if (!(perms.xindex & AA_X_UNSAFE)) { 672 if (!(perms.xindex & AA_X_UNSAFE)) {
704 if (DEBUG_ON) { 673 if (DEBUG_ON) {
@@ -800,6 +769,17 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
800 769
801 label = aa_get_newest_label(cred_label(bprm->cred)); 770 label = aa_get_newest_label(cred_label(bprm->cred));
802 771
772 /*
773 * Detect no new privs being set, and store the label it
774 * occurred under. Ideally this would happen when nnp
775 * is set but there isn't a good way to do that yet.
776 *
777 * Testing for unconfined must be done before the subset test
778 */
779 if ((bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) && !unconfined(label) &&
780 !ctx->nnp)
781 ctx->nnp = aa_get_label(label);
782
803 /* buffer freed below, name is pointer into buffer */ 783 /* buffer freed below, name is pointer into buffer */
804 get_buffers(buffer); 784 get_buffers(buffer);
805 /* Test for onexec first as onexec override other x transitions. */ 785 /* Test for onexec first as onexec override other x transitions. */
@@ -820,7 +800,20 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
820 goto done; 800 goto done;
821 } 801 }
822 802
823 /* TODO: Add ns level no_new_privs subset test */ 803 /* Policy has specified a domain transitions. If no_new_privs and
804 * confined ensure the transition is to confinement that is subset
805 * of the confinement when the task entered no new privs.
806 *
807 * NOTE: Domain transitions from unconfined and to stacked
808 * subsets are allowed even when no_new_privs is set because this
809 * aways results in a further reduction of permissions.
810 */
811 if ((bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) &&
812 !unconfined(label) && !aa_label_is_subset(new, ctx->nnp)) {
813 error = -EPERM;
814 info = "no new privs";
815 goto audit;
816 }
824 817
825 if (bprm->unsafe & LSM_UNSAFE_SHARE) { 818 if (bprm->unsafe & LSM_UNSAFE_SHARE) {
826 /* FIXME: currently don't mediate shared state */ 819 /* FIXME: currently don't mediate shared state */
@@ -1047,30 +1040,28 @@ build:
1047int aa_change_hat(const char *hats[], int count, u64 token, int flags) 1040int aa_change_hat(const char *hats[], int count, u64 token, int flags)
1048{ 1041{
1049 const struct cred *cred; 1042 const struct cred *cred;
1050 struct aa_task_ctx *ctx; 1043 struct aa_task_ctx *ctx = task_ctx(current);
1051 struct aa_label *label, *previous, *new = NULL, *target = NULL; 1044 struct aa_label *label, *previous, *new = NULL, *target = NULL;
1052 struct aa_profile *profile; 1045 struct aa_profile *profile;
1053 struct aa_perms perms = {}; 1046 struct aa_perms perms = {};
1054 const char *info = NULL; 1047 const char *info = NULL;
1055 int error = 0; 1048 int error = 0;
1056 1049
1057 /*
1058 * Fail explicitly requested domain transitions if no_new_privs.
1059 * There is no exception for unconfined as change_hat is not
1060 * available.
1061 */
1062 if (task_no_new_privs(current)) {
1063 /* not an apparmor denial per se, so don't log it */
1064 AA_DEBUG("no_new_privs - change_hat denied");
1065 return -EPERM;
1066 }
1067
1068 /* released below */ 1050 /* released below */
1069 cred = get_current_cred(); 1051 cred = get_current_cred();
1070 ctx = task_ctx(current);
1071 label = aa_get_newest_cred_label(cred); 1052 label = aa_get_newest_cred_label(cred);
1072 previous = aa_get_newest_label(ctx->previous); 1053 previous = aa_get_newest_label(ctx->previous);
1073 1054
1055 /*
1056 * Detect no new privs being set, and store the label it
1057 * occurred under. Ideally this would happen when nnp
1058 * is set but there isn't a good way to do that yet.
1059 *
1060 * Testing for unconfined must be done before the subset test
1061 */
1062 if (task_no_new_privs(current) && !unconfined(label) && !ctx->nnp)
1063 ctx->nnp = aa_get_label(label);
1064
1074 if (unconfined(label)) { 1065 if (unconfined(label)) {
1075 info = "unconfined can not change_hat"; 1066 info = "unconfined can not change_hat";
1076 error = -EPERM; 1067 error = -EPERM;
@@ -1091,6 +1082,18 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags)
1091 if (error) 1082 if (error)
1092 goto fail; 1083 goto fail;
1093 1084
1085 /*
1086 * no new privs prevents domain transitions that would
1087 * reduce restrictions.
1088 */
1089 if (task_no_new_privs(current) && !unconfined(label) &&
1090 !aa_label_is_subset(new, ctx->nnp)) {
1091 /* not an apparmor denial per se, so don't log it */
1092 AA_DEBUG("no_new_privs - change_hat denied");
1093 error = -EPERM;
1094 goto out;
1095 }
1096
1094 if (flags & AA_CHANGE_TEST) 1097 if (flags & AA_CHANGE_TEST)
1095 goto out; 1098 goto out;
1096 1099
@@ -1100,6 +1103,18 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags)
1100 /* kill task in case of brute force attacks */ 1103 /* kill task in case of brute force attacks */
1101 goto kill; 1104 goto kill;
1102 } else if (previous && !(flags & AA_CHANGE_TEST)) { 1105 } else if (previous && !(flags & AA_CHANGE_TEST)) {
1106 /*
1107 * no new privs prevents domain transitions that would
1108 * reduce restrictions.
1109 */
1110 if (task_no_new_privs(current) && !unconfined(label) &&
1111 !aa_label_is_subset(previous, ctx->nnp)) {
1112 /* not an apparmor denial per se, so don't log it */
1113 AA_DEBUG("no_new_privs - change_hat denied");
1114 error = -EPERM;
1115 goto out;
1116 }
1117
1103 /* Return to saved label. Kill task if restore fails 1118 /* Return to saved label. Kill task if restore fails
1104 * to avoid brute force attacks 1119 * to avoid brute force attacks
1105 */ 1120 */
@@ -1142,21 +1157,6 @@ static int change_profile_perms_wrapper(const char *op, const char *name,
1142 const char *info = NULL; 1157 const char *info = NULL;
1143 int error = 0; 1158 int error = 0;
1144 1159
1145 /*
1146 * Fail explicitly requested domain transitions when no_new_privs
1147 * and not unconfined OR the transition results in a stack on
1148 * the current label.
1149 * Stacking domain transitions and transitions from unconfined are
1150 * allowed even when no_new_privs is set because this aways results
1151 * in a reduction of permissions.
1152 */
1153 if (task_no_new_privs(current) && !stack &&
1154 !profile_unconfined(profile) &&
1155 !aa_label_is_subset(target, &profile->label)) {
1156 info = "no new privs";
1157 error = -EPERM;
1158 }
1159
1160 if (!error) 1160 if (!error)
1161 error = change_profile_perms(profile, target, stack, request, 1161 error = change_profile_perms(profile, target, stack, request,
1162 profile->file.start, perms); 1162 profile->file.start, perms);
@@ -1190,10 +1190,23 @@ int aa_change_profile(const char *fqname, int flags)
1190 const char *info = NULL; 1190 const char *info = NULL;
1191 const char *auditname = fqname; /* retain leading & if stack */ 1191 const char *auditname = fqname; /* retain leading & if stack */
1192 bool stack = flags & AA_CHANGE_STACK; 1192 bool stack = flags & AA_CHANGE_STACK;
1193 struct aa_task_ctx *ctx = task_ctx(current);
1193 int error = 0; 1194 int error = 0;
1194 char *op; 1195 char *op;
1195 u32 request; 1196 u32 request;
1196 1197
1198 label = aa_get_current_label();
1199
1200 /*
1201 * Detect no new privs being set, and store the label it
1202 * occurred under. Ideally this would happen when nnp
1203 * is set but there isn't a good way to do that yet.
1204 *
1205 * Testing for unconfined must be done before the subset test
1206 */
1207 if (task_no_new_privs(current) && !unconfined(label) && !ctx->nnp)
1208 ctx->nnp = aa_get_label(label);
1209
1197 if (!fqname || !*fqname) { 1210 if (!fqname || !*fqname) {
1198 AA_DEBUG("no profile name"); 1211 AA_DEBUG("no profile name");
1199 return -EINVAL; 1212 return -EINVAL;
@@ -1281,14 +1294,28 @@ check:
1281 if (flags & AA_CHANGE_TEST) 1294 if (flags & AA_CHANGE_TEST)
1282 goto out; 1295 goto out;
1283 1296
1297 /* stacking is always a subset, so only check the nonstack case */
1298 if (!stack) {
1299 new = fn_label_build_in_ns(label, profile, GFP_KERNEL,
1300 aa_get_label(target),
1301 aa_get_label(&profile->label));
1302 /*
1303 * no new privs prevents domain transitions that would
1304 * reduce restrictions.
1305 */
1306 if (task_no_new_privs(current) && !unconfined(label) &&
1307 !aa_label_is_subset(new, ctx->nnp)) {
1308 /* not an apparmor denial per se, so don't log it */
1309 AA_DEBUG("no_new_privs - change_hat denied");
1310 error = -EPERM;
1311 goto out;
1312 }
1313 }
1314
1284 if (!(flags & AA_CHANGE_ONEXEC)) { 1315 if (!(flags & AA_CHANGE_ONEXEC)) {
1285 /* only transition profiles in the current ns */ 1316 /* only transition profiles in the current ns */
1286 if (stack) 1317 if (stack)
1287 new = aa_label_merge(label, target, GFP_KERNEL); 1318 new = aa_label_merge(label, target, GFP_KERNEL);
1288 else
1289 new = fn_label_build_in_ns(label, profile, GFP_KERNEL,
1290 aa_get_label(target),
1291 aa_get_label(&profile->label));
1292 if (IS_ERR_OR_NULL(new)) { 1319 if (IS_ERR_OR_NULL(new)) {
1293 info = "failed to build target label"; 1320 info = "failed to build target label";
1294 error = PTR_ERR(new); 1321 error = PTR_ERR(new);
@@ -1297,9 +1324,15 @@ check:
1297 goto audit; 1324 goto audit;
1298 } 1325 }
1299 error = aa_replace_current_label(new); 1326 error = aa_replace_current_label(new);
1300 } else 1327 } else {
1328 if (new) {
1329 aa_put_label(new);
1330 new = NULL;
1331 }
1332
1301 /* full transition will be built in exec path */ 1333 /* full transition will be built in exec path */
1302 error = aa_set_current_onexec(target, stack); 1334 error = aa_set_current_onexec(target, stack);
1335 }
1303 1336
1304audit: 1337audit:
1305 error = fn_for_each_in_ns(label, profile, 1338 error = fn_for_each_in_ns(label, profile,
diff --git a/security/apparmor/include/task.h b/security/apparmor/include/task.h
index d222197db299..55edaa1d83f8 100644
--- a/security/apparmor/include/task.h
+++ b/security/apparmor/include/task.h
@@ -18,11 +18,13 @@
18 18
19/* 19/*
20 * struct aa_task_ctx - information for current task label change 20 * struct aa_task_ctx - information for current task label change
21 * @nnp: snapshot of label at time of no_new_privs
21 * @onexec: profile to transition to on next exec (MAY BE NULL) 22 * @onexec: profile to transition to on next exec (MAY BE NULL)
22 * @previous: profile the task may return to (MAY BE NULL) 23 * @previous: profile the task may return to (MAY BE NULL)
23 * @token: magic value the task must know for returning to @previous_profile 24 * @token: magic value the task must know for returning to @previous_profile
24 */ 25 */
25struct aa_task_ctx { 26struct aa_task_ctx {
27 struct aa_label *nnp;
26 struct aa_label *onexec; 28 struct aa_label *onexec;
27 struct aa_label *previous; 29 struct aa_label *previous;
28 u64 token; 30 u64 token;
@@ -52,6 +54,7 @@ static inline struct aa_task_ctx *aa_alloc_task_ctx(gfp_t flags)
52static inline void aa_free_task_ctx(struct aa_task_ctx *ctx) 54static inline void aa_free_task_ctx(struct aa_task_ctx *ctx)
53{ 55{
54 if (ctx) { 56 if (ctx) {
57 aa_put_label(ctx->nnp);
55 aa_put_label(ctx->previous); 58 aa_put_label(ctx->previous);
56 aa_put_label(ctx->onexec); 59 aa_put_label(ctx->onexec);
57 60
@@ -68,6 +71,7 @@ static inline void aa_dup_task_ctx(struct aa_task_ctx *new,
68 const struct aa_task_ctx *old) 71 const struct aa_task_ctx *old)
69{ 72{
70 *new = *old; 73 *new = *old;
74 aa_get_label(new->nnp);
71 aa_get_label(new->previous); 75 aa_get_label(new->previous);
72 aa_get_label(new->onexec); 76 aa_get_label(new->onexec);
73} 77}
diff --git a/security/apparmor/task.c b/security/apparmor/task.c
index 44b9b938e06d..c6b78a14da91 100644
--- a/security/apparmor/task.c
+++ b/security/apparmor/task.c
@@ -45,6 +45,7 @@ struct aa_label *aa_get_task_label(struct task_struct *task)
45int aa_replace_current_label(struct aa_label *label) 45int aa_replace_current_label(struct aa_label *label)
46{ 46{
47 struct aa_label *old = aa_current_raw_label(); 47 struct aa_label *old = aa_current_raw_label();
48 struct aa_task_ctx *ctx = task_ctx(current);
48 struct cred *new; 49 struct cred *new;
49 50
50 AA_BUG(!label); 51 AA_BUG(!label);
@@ -59,6 +60,12 @@ int aa_replace_current_label(struct aa_label *label)
59 if (!new) 60 if (!new)
60 return -ENOMEM; 61 return -ENOMEM;
61 62
63 if (ctx->nnp && label_is_stale(ctx->nnp)) {
64 struct aa_label *tmp = ctx->nnp;
65
66 ctx->nnp = aa_get_newest_label(tmp);
67 aa_put_label(tmp);
68 }
62 if (unconfined(label) || (labels_ns(old) != labels_ns(label))) 69 if (unconfined(label) || (labels_ns(old) != labels_ns(label)))
63 /* 70 /*
64 * if switching to unconfined or a different label namespace 71 * if switching to unconfined or a different label namespace