aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2013-07-11 00:07:43 -0400
committerJohn Johansen <john.johansen@canonical.com>2013-08-14 14:42:06 -0400
commit77b071b34045a0c65d0e1f85f3d47fd2b8b7a8a1 (patch)
treeb0b2c38b79969ac7b9439389888f6a1ac14a32a7 /security
parent01e2b670aa898a39259bc85c78e3d74820f4d3b6 (diff)
apparmor: change how profile replacement update is done
remove the use of replaced by chaining and move to profile invalidation and lookup to handle task replacement. Replacement chaining can result in large chains of profiles being pinned in memory when one profile in the chain is use. With implicit labeling this will be even more of a problem, so move to a direct lookup method. Signed-off-by: John Johansen <john.johansen@canonical.com>
Diffstat (limited to 'security')
-rw-r--r--security/apparmor/context.c16
-rw-r--r--security/apparmor/domain.c4
-rw-r--r--security/apparmor/include/context.h15
-rw-r--r--security/apparmor/include/policy.h78
-rw-r--r--security/apparmor/lsm.c14
-rw-r--r--security/apparmor/policy.c85
6 files changed, 125 insertions, 87 deletions
diff --git a/security/apparmor/context.c b/security/apparmor/context.c
index d5af1d15f26d..3064c6ced87c 100644
--- a/security/apparmor/context.c
+++ b/security/apparmor/context.c
@@ -112,9 +112,9 @@ int aa_replace_current_profile(struct aa_profile *profile)
112 aa_clear_task_cxt_trans(cxt); 112 aa_clear_task_cxt_trans(cxt);
113 113
114 /* be careful switching cxt->profile, when racing replacement it 114 /* be careful switching cxt->profile, when racing replacement it
115 * is possible that cxt->profile->replacedby is the reference keeping 115 * is possible that cxt->profile->replacedby->profile is the reference
116 * @profile valid, so make sure to get its reference before dropping 116 * keeping @profile valid, so make sure to get its reference before
117 * the reference on cxt->profile */ 117 * dropping the reference on cxt->profile */
118 aa_get_profile(profile); 118 aa_get_profile(profile);
119 aa_put_profile(cxt->profile); 119 aa_put_profile(cxt->profile);
120 cxt->profile = profile; 120 cxt->profile = profile;
@@ -175,7 +175,7 @@ int aa_set_current_hat(struct aa_profile *profile, u64 token)
175 abort_creds(new); 175 abort_creds(new);
176 return -EACCES; 176 return -EACCES;
177 } 177 }
178 cxt->profile = aa_get_profile(aa_newest_version(profile)); 178 cxt->profile = aa_get_newest_profile(profile);
179 /* clear exec on switching context */ 179 /* clear exec on switching context */
180 aa_put_profile(cxt->onexec); 180 aa_put_profile(cxt->onexec);
181 cxt->onexec = NULL; 181 cxt->onexec = NULL;
@@ -212,14 +212,8 @@ int aa_restore_previous_profile(u64 token)
212 } 212 }
213 213
214 aa_put_profile(cxt->profile); 214 aa_put_profile(cxt->profile);
215 cxt->profile = aa_newest_version(cxt->previous); 215 cxt->profile = aa_get_newest_profile(cxt->previous);
216 BUG_ON(!cxt->profile); 216 BUG_ON(!cxt->profile);
217 if (unlikely(cxt->profile != cxt->previous)) {
218 aa_get_profile(cxt->profile);
219 aa_put_profile(cxt->previous);
220 }
221 /* ref has been transfered so avoid putting ref in clear_task_cxt */
222 cxt->previous = NULL;
223 /* clear exec && prev information when restoring to previous context */ 217 /* clear exec && prev information when restoring to previous context */
224 aa_clear_task_cxt_trans(cxt); 218 aa_clear_task_cxt_trans(cxt);
225 219
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index 454bcd7f3452..5488d095af6f 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -359,7 +359,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
359 cxt = cred_cxt(bprm->cred); 359 cxt = cred_cxt(bprm->cred);
360 BUG_ON(!cxt); 360 BUG_ON(!cxt);
361 361
362 profile = aa_get_profile(aa_newest_version(cxt->profile)); 362 profile = aa_get_newest_profile(cxt->profile);
363 /* 363 /*
364 * get the namespace from the replacement profile as replacement 364 * get the namespace from the replacement profile as replacement
365 * can change the namespace 365 * can change the namespace
@@ -417,7 +417,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
417 417
418 if (!(cp.allow & AA_MAY_ONEXEC)) 418 if (!(cp.allow & AA_MAY_ONEXEC))
419 goto audit; 419 goto audit;
420 new_profile = aa_get_profile(aa_newest_version(cxt->onexec)); 420 new_profile = aa_get_newest_profile(cxt->onexec);
421 goto apply; 421 goto apply;
422 } 422 }
423 423
diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h
index d44ba5802e3d..6bf65798e5d1 100644
--- a/security/apparmor/include/context.h
+++ b/security/apparmor/include/context.h
@@ -98,7 +98,7 @@ static inline struct aa_profile *aa_cred_profile(const struct cred *cred)
98{ 98{
99 struct aa_task_cxt *cxt = cred_cxt(cred); 99 struct aa_task_cxt *cxt = cred_cxt(cred);
100 BUG_ON(!cxt || !cxt->profile); 100 BUG_ON(!cxt || !cxt->profile);
101 return aa_newest_version(cxt->profile); 101 return cxt->profile;
102} 102}
103 103
104/** 104/**
@@ -152,15 +152,14 @@ static inline struct aa_profile *aa_current_profile(void)
152 struct aa_profile *profile; 152 struct aa_profile *profile;
153 BUG_ON(!cxt || !cxt->profile); 153 BUG_ON(!cxt || !cxt->profile);
154 154
155 profile = aa_newest_version(cxt->profile); 155 if (PROFILE_INVALID(cxt->profile)) {
156 /* 156 profile = aa_get_newest_profile(cxt->profile);
157 * Whether or not replacement succeeds, use newest profile so
158 * there is no need to update it after replacement.
159 */
160 if (unlikely((cxt->profile != profile)))
161 aa_replace_current_profile(profile); 157 aa_replace_current_profile(profile);
158 aa_put_profile(profile);
159 cxt = current_cxt();
160 }
162 161
163 return profile; 162 return cxt->profile;
164} 163}
165 164
166/** 165/**
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
index 82487a853353..e9f2baf4467e 100644
--- a/security/apparmor/include/policy.h
+++ b/security/apparmor/include/policy.h
@@ -42,6 +42,8 @@ extern const char *const profile_mode_names[];
42 42
43#define PROFILE_IS_HAT(_profile) ((_profile)->flags & PFLAG_HAT) 43#define PROFILE_IS_HAT(_profile) ((_profile)->flags & PFLAG_HAT)
44 44
45#define PROFILE_INVALID(_profile) ((_profile)->flags & PFLAG_INVALID)
46
45#define on_list_rcu(X) (!list_empty(X) && (X)->prev != LIST_POISON2) 47#define on_list_rcu(X) (!list_empty(X) && (X)->prev != LIST_POISON2)
46 48
47/* 49/*
@@ -65,6 +67,7 @@ enum profile_flags {
65 PFLAG_USER_DEFINED = 0x20, /* user based profile - lower privs */ 67 PFLAG_USER_DEFINED = 0x20, /* user based profile - lower privs */
66 PFLAG_NO_LIST_REF = 0x40, /* list doesn't keep profile ref */ 68 PFLAG_NO_LIST_REF = 0x40, /* list doesn't keep profile ref */
67 PFLAG_OLD_NULL_TRANS = 0x100, /* use // as the null transition */ 69 PFLAG_OLD_NULL_TRANS = 0x100, /* use // as the null transition */
70 PFLAG_INVALID = 0x200, /* profile replaced/removed */
68 71
69 /* These flags must correspond with PATH_flags */ 72 /* These flags must correspond with PATH_flags */
70 PFLAG_MEDIATE_DELETED = 0x10000, /* mediate instead delegate deleted */ 73 PFLAG_MEDIATE_DELETED = 0x10000, /* mediate instead delegate deleted */
@@ -146,6 +149,12 @@ struct aa_policydb {
146 149
147}; 150};
148 151
152struct aa_replacedby {
153 struct kref count;
154 struct aa_profile __rcu *profile;
155};
156
157
149/* struct aa_profile - basic confinement data 158/* struct aa_profile - basic confinement data
150 * @base - base components of the profile (name, refcount, lists, lock ...) 159 * @base - base components of the profile (name, refcount, lists, lock ...)
151 * @parent: parent of profile 160 * @parent: parent of profile
@@ -169,8 +178,7 @@ struct aa_policydb {
169 * used to determine profile attachment against unconfined tasks. All other 178 * used to determine profile attachment against unconfined tasks. All other
170 * attachments are determined by profile X transition rules. 179 * attachments are determined by profile X transition rules.
171 * 180 *
172 * The @replacedby field is write protected by the profile lock. Reads 181 * The @replacedby struct is write protected by the profile lock.
173 * are assumed to be atomic.
174 * 182 *
175 * Profiles have a hierarchy where hats and children profiles keep 183 * Profiles have a hierarchy where hats and children profiles keep
176 * a reference to their parent. 184 * a reference to their parent.
@@ -184,14 +192,14 @@ struct aa_profile {
184 struct aa_profile __rcu *parent; 192 struct aa_profile __rcu *parent;
185 193
186 struct aa_namespace *ns; 194 struct aa_namespace *ns;
187 struct aa_profile *replacedby; 195 struct aa_replacedby *replacedby;
188 const char *rename; 196 const char *rename;
189 197
190 struct aa_dfa *xmatch; 198 struct aa_dfa *xmatch;
191 int xmatch_len; 199 int xmatch_len;
192 enum audit_mode audit; 200 enum audit_mode audit;
193 enum profile_mode mode;