Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
context.c
Go to the documentation of this file.
1 /*
2  * AppArmor security module
3  *
4  * This file contains AppArmor functions used to manipulate object security
5  * contexts.
6  *
7  * Copyright (C) 1998-2008 Novell/SUSE
8  * Copyright 2009-2010 Canonical Ltd.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License as
12  * published by the Free Software Foundation, version 2 of the
13  * License.
14  *
15  *
16  * AppArmor sets confinement on every task, via the the aa_task_cxt and
17  * the aa_task_cxt.profile, both of which are required and are not allowed
18  * to be NULL. The aa_task_cxt is not reference counted and is unique
19  * to each cred (which is reference count). The profile pointed to by
20  * the task_cxt is reference counted.
21  *
22  * TODO
23  * If a task uses change_hat it currently does not return to the old
24  * cred or task context but instead creates a new one. Ideally the task
25  * should return to the previous cred if it has not been modified.
26  *
27  */
28 
29 #include "include/context.h"
30 #include "include/policy.h"
31 
39 {
40  return kzalloc(sizeof(struct aa_task_cxt), flags);
41 }
42 
48 {
49  if (cxt) {
50  aa_put_profile(cxt->profile);
51  aa_put_profile(cxt->previous);
52  aa_put_profile(cxt->onexec);
53 
54  kzfree(cxt);
55  }
56 }
57 
63 void aa_dup_task_context(struct aa_task_cxt *new, const struct aa_task_cxt *old)
64 {
65  *new = *old;
66  aa_get_profile(new->profile);
67  aa_get_profile(new->previous);
68  aa_get_profile(new->onexec);
69 }
70 
78 {
79  struct aa_task_cxt *cxt = current_cred()->security;
80  struct cred *new;
81  BUG_ON(!profile);
82 
83  if (cxt->profile == profile)
84  return 0;
85 
86  new = prepare_creds();
87  if (!new)
88  return -ENOMEM;
89 
90  cxt = new->security;
91  if (unconfined(profile) || (cxt->profile->ns != profile->ns)) {
92  /* if switching to unconfined or a different profile namespace
93  * clear out context state
94  */
95  aa_put_profile(cxt->previous);
96  aa_put_profile(cxt->onexec);
97  cxt->previous = NULL;
98  cxt->onexec = NULL;
99  cxt->token = 0;
100  }
101  /* be careful switching cxt->profile, when racing replacement it
102  * is possible that cxt->profile->replacedby is the reference keeping
103  * @profile valid, so make sure to get its reference before dropping
104  * the reference on cxt->profile */
105  aa_get_profile(profile);
106  aa_put_profile(cxt->profile);
107  cxt->profile = profile;
108 
109  commit_creds(new);
110  return 0;
111 }
112 
120 {
121  struct aa_task_cxt *cxt;
122  struct cred *new = prepare_creds();
123  if (!new)
124  return -ENOMEM;
125 
126  cxt = new->security;
127  aa_get_profile(profile);
128  aa_put_profile(cxt->onexec);
129  cxt->onexec = profile;
130 
131  commit_creds(new);
132  return 0;
133 }
134 
146 {
147  struct aa_task_cxt *cxt;
148  struct cred *new = prepare_creds();
149  if (!new)
150  return -ENOMEM;
151  BUG_ON(!profile);
152 
153  cxt = new->security;
154  if (!cxt->previous) {
155  /* transfer refcount */
156  cxt->previous = cxt->profile;
157  cxt->token = token;
158  } else if (cxt->token == token) {
159  aa_put_profile(cxt->profile);
160  } else {
161  /* previous_profile && cxt->token != token */
162  abort_creds(new);
163  return -EACCES;
164  }
165  cxt->profile = aa_get_profile(aa_newest_version(profile));
166  /* clear exec on switching context */
167  aa_put_profile(cxt->onexec);
168  cxt->onexec = NULL;
169 
170  commit_creds(new);
171  return 0;
172 }
173 
184 {
185  struct aa_task_cxt *cxt;
186  struct cred *new = prepare_creds();
187  if (!new)
188  return -ENOMEM;
189 
190  cxt = new->security;
191  if (cxt->token != token) {
192  abort_creds(new);
193  return -EACCES;
194  }
195  /* ignore restores when there is no saved profile */
196  if (!cxt->previous) {
197  abort_creds(new);
198  return 0;
199  }
200 
201  aa_put_profile(cxt->profile);
202  cxt->profile = aa_newest_version(cxt->previous);
203  BUG_ON(!cxt->profile);
204  if (unlikely(cxt->profile != cxt->previous)) {
205  aa_get_profile(cxt->profile);
206  aa_put_profile(cxt->previous);
207  }
208  /* clear exec && prev information when restoring to previous context */
209  cxt->previous = NULL;
210  cxt->token = 0;
211  aa_put_profile(cxt->onexec);
212  cxt->onexec = NULL;
213 
214  commit_creds(new);
215  return 0;
216 }