aboutsummaryrefslogtreecommitdiffstats
path: root/security/apparmor/include/policy.h
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2013-07-11 00:08:43 -0400
committerJohn Johansen <john.johansen@canonical.com>2013-08-14 14:42:06 -0400
commitfa2ac468db510c653499a47c1ec3deb045bf4763 (patch)
tree561c1c638d4e2c337712db0f2daf856a19560e2f /security/apparmor/include/policy.h
parent77b071b34045a0c65d0e1f85f3d47fd2b8b7a8a1 (diff)
apparmor: update how unconfined is handled
ns->unconfined is being used read side without locking, nor rcu but is being updated when a namespace is removed. This works for the root ns which is never removed but has a race window and can cause failures when children namespaces are removed. Also ns and ns->unconfined have a circular refcounting dependency that is problematic and must be broken. Currently this is done incorrectly when the namespace is destroyed. Fix this by forward referencing unconfined via the replacedby infrastructure instead of directly updating the ns->unconfined pointer. Remove the circular refcount dependency by making the ns and its unconfined profile share the same refcount. Signed-off-by: John Johansen <john.johansen@canonical.com> Acked-by: Seth Arnold <seth.arnold@canonical.com>
Diffstat (limited to 'security/apparmor/include/policy.h')
-rw-r--r--security/apparmor/include/policy.h80
1 files changed, 39 insertions, 41 deletions
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
index e9f2baf4467e..1ddd5e5728b8 100644
--- a/security/apparmor/include/policy.h
+++ b/security/apparmor/include/policy.h
@@ -68,6 +68,7 @@ enum profile_flags {
68 PFLAG_NO_LIST_REF = 0x40, /* list doesn't keep profile ref */ 68 PFLAG_NO_LIST_REF = 0x40, /* list doesn't keep profile ref */
69 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 */ 70 PFLAG_INVALID = 0x200, /* profile replaced/removed */
71 PFLAG_NS_COUNT = 0x400, /* carries NS ref count */
71 72
72 /* These flags must correspond with PATH_flags */ 73 /* These flags must correspond with PATH_flags */
73 PFLAG_MEDIATE_DELETED = 0x10000, /* mediate instead delegate deleted */ 74 PFLAG_MEDIATE_DELETED = 0x10000, /* mediate instead delegate deleted */
@@ -78,7 +79,6 @@ struct aa_profile;
78/* struct aa_policy - common part of both namespaces and profiles 79/* struct aa_policy - common part of both namespaces and profiles
79 * @name: name of the object 80 * @name: name of the object
80 * @hname - The hierarchical name 81 * @hname - The hierarchical name
81 * @count: reference count of the obj
82 * @list: list policy object is on 82 * @list: list policy object is on
83 * @rcu: rcu head used when removing from @list 83 * @rcu: rcu head used when removing from @list
84 * @profiles: head of the profiles list contained in the object 84 * @profiles: head of the profiles list contained in the object
@@ -86,7 +86,6 @@ struct aa_profile;
86struct aa_policy { 86struct aa_policy {
87 char *name; 87 char *name;
88 char *hname; 88 char *hname;
89 struct kref count;
90 struct list_head list; 89 struct list_head list;
91 struct list_head profiles; 90 struct list_head profiles;
92 struct rcu_head rcu; 91 struct rcu_head rcu;
@@ -157,6 +156,7 @@ struct aa_replacedby {
157 156
158/* struct aa_profile - basic confinement data 157/* struct aa_profile - basic confinement data
159 * @base - base components of the profile (name, refcount, lists, lock ...) 158 * @base - base components of the profile (name, refcount, lists, lock ...)
159 * @count: reference count of the obj
160 * @parent: parent of profile 160 * @parent: parent of profile
161 * @ns: namespace the profile is in 161 * @ns: namespace the profile is in
162 * @replacedby: is set to the profile that replaced this profile 162 * @replacedby: is set to the profile that replaced this profile
@@ -189,6 +189,7 @@ struct aa_replacedby {
189 */ 189 */
190struct aa_profile { 190struct aa_profile {
191 struct aa_policy base; 191 struct aa_policy base;
192 struct kref count;
192 struct aa_profile __rcu *parent; 193 struct aa_profile __rcu *parent;
193 194
194 struct aa_namespace *ns; 195 struct aa_namespace *ns;
@@ -223,40 +224,6 @@ void aa_free_namespace_kref(struct kref *kref);
223struct aa_namespace *aa_find_namespace(struct aa_namespace *root, 224struct aa_namespace *aa_find_namespace(struct aa_namespace *root,
224 const char *name); 225 const char *name);
225 226
226static inline struct aa_policy *aa_get_common(struct aa_policy *c)
227{
228 if (c)
229 kref_get(&c->count);
230
231 return c;
232}
233
234/**
235 * aa_get_namespace - increment references count on @ns
236 * @ns: namespace to increment reference count of (MAYBE NULL)
237 *
238 * Returns: pointer to @ns, if @ns is NULL returns NULL
239 * Requires: @ns must be held with valid refcount when called
240 */
241static inline struct aa_namespace *aa_get_namespace(struct aa_namespace *ns)
242{
243 if (ns)
244 kref_get(&(ns->base.count));
245
246 return ns;
247}
248
249/**
250 * aa_put_namespace - decrement refcount on @ns
251 * @ns: namespace to put reference of
252 *
253 * Decrement reference count of @ns and if no longer in use free it
254 */
255static inline void aa_put_namespace(struct aa_namespace *ns)
256{
257 if (ns)
258 kref_put(&ns->base.count, aa_free_namespace_kref);
259}
260 227
261void aa_free_replacedby_kref(struct kref *kref); 228void aa_free_replacedby_kref(struct kref *kref);
262struct aa_profile *aa_alloc_profile(const char *name); 229struct aa_profile *aa_alloc_profile(const char *name);
@@ -285,7 +252,7 @@ ssize_t aa_remove_profiles(char *name, size_t size);
285static inline struct aa_profile *aa_get_profile(struct aa_profile *p) 252static inline struct aa_profile *aa_get_profile(struct aa_profile *p)
286{ 253{
287 if (p) 254 if (p)
288 kref_get(&(p->base.count)); 255 kref_get(&(p->count));
289 256
290 return p; 257 return p;
291} 258}
@@ -299,7 +266,7 @@ static inline struct aa_profile *aa_get_profile(struct aa_profile *p)
299 */ 266 */
300static inline struct aa_profile *aa_get_profile_not0(struct aa_profile *p) 267static inline struct aa_profile *aa_get_profile_not0(struct aa_profile *p)
301{ 268{
302 if (p && kref_get_not0(&p->base.count)) 269 if (p && kref_get_not0(&p->count))
303 return p; 270 return p;
304 271
305 return NULL; 272 return NULL;
@@ -319,7 +286,7 @@ static inline struct aa_profile *aa_get_profile_rcu(struct aa_profile __rcu **p)
319 rcu_read_lock(); 286 rcu_read_lock();
320 do { 287 do {
321 c = rcu_dereference(*p); 288 c = rcu_dereference(*p);
322 } while (c && !kref_get_not0(&c->base.count)); 289 } while (c && !kref_get_not0(&c->count));
323 rcu_read_unlock(); 290 rcu_read_unlock();
324 291
325 return c; 292 return c;
@@ -350,8 +317,12 @@ static inline struct aa_profile *aa_get_newest_profile(struct aa_profile *p)
350 */ 317 */
351static inline void aa_put_profile(struct aa_profile *p) 318static inline void aa_put_profile(struct aa_profile *p)
352{ 319{
353 if (p) 320 if (p) {
354 kref_put(&p->base.count, aa_free_profile_kref); 321 if (p->flags & PFLAG_NS_COUNT)
322 kref_put(&p->count, aa_free_namespace_kref);
323 else
324 kref_put(&p->count, aa_free_profile_kref);
325 }
355} 326}
356 327
357static inline struct aa_replacedby *aa_get_replacedby(struct aa_replacedby *p) 328static inline struct aa_replacedby *aa_get_replacedby(struct aa_replacedby *p)
@@ -378,6 +349,33 @@ static inline void __aa_update_replacedby(struct aa_profile *orig,
378 aa_put_profile(tmp); 349 aa_put_profile(tmp);
379} 350}
380 351
352/**
353 * aa_get_namespace - increment references count on @ns
354 * @ns: namespace to increment reference count of (MAYBE NULL)
355 *
356 * Returns: pointer to @ns, if @ns is NULL returns NULL
357 * Requires: @ns must be held with valid refcount when called
358 */
359static inline struct aa_namespace *aa_get_namespace(struct aa_namespace *ns)
360{
361 if (ns)
362 aa_get_profile(ns->unconfined);
363
364 return ns;
365}
366
367/**
368 * aa_put_namespace - decrement refcount on @ns
369 * @ns: namespace to put reference of
370 *
371 * Decrement reference count of @ns and if no longer in use free it
372 */
373static inline void aa_put_namespace(struct aa_namespace *ns)
374{
375 if (ns)
376 aa_put_profile(ns->unconfined);
377}
378
381static inline int AUDIT_MODE(struct aa_profile *profile) 379static inline int AUDIT_MODE(struct aa_profile *profile)
382{ 380{
383 if (aa_g_audit != AUDIT_NORMAL) 381 if (aa_g_audit != AUDIT_NORMAL)