Merge tag 'for-linus-20180413' of git://git.kernel.dk/linux-block
[sfrench/cifs-2.6.git] / security / apparmor / context.c
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_ctx and
17  * the aa_task_ctx.label, both of which are required and are not allowed
18  * to be NULL.  The aa_task_ctx is not reference counted and is unique
19  * to each cred (which is reference count).  The label pointed to by
20  * the task_ctx 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
32 /**
33  * aa_alloc_task_context - allocate a new task_ctx
34  * @flags: gfp flags for allocation
35  *
36  * Returns: allocated buffer or NULL on failure
37  */
38 struct aa_task_ctx *aa_alloc_task_context(gfp_t flags)
39 {
40         return kzalloc(sizeof(struct aa_task_ctx), flags);
41 }
42
43 /**
44  * aa_free_task_context - free a task_ctx
45  * @ctx: task_ctx to free (MAYBE NULL)
46  */
47 void aa_free_task_context(struct aa_task_ctx *ctx)
48 {
49         if (ctx) {
50                 aa_put_label(ctx->label);
51                 aa_put_label(ctx->previous);
52                 aa_put_label(ctx->onexec);
53
54                 kzfree(ctx);
55         }
56 }
57
58 /**
59  * aa_dup_task_context - duplicate a task context, incrementing reference counts
60  * @new: a blank task context      (NOT NULL)
61  * @old: the task context to copy  (NOT NULL)
62  */
63 void aa_dup_task_context(struct aa_task_ctx *new, const struct aa_task_ctx *old)
64 {
65         *new = *old;
66         aa_get_label(new->label);
67         aa_get_label(new->previous);
68         aa_get_label(new->onexec);
69 }
70
71 /**
72  * aa_get_task_label - Get another task's label
73  * @task: task to query  (NOT NULL)
74  *
75  * Returns: counted reference to @task's label
76  */
77 struct aa_label *aa_get_task_label(struct task_struct *task)
78 {
79         struct aa_label *p;
80
81         rcu_read_lock();
82         p = aa_get_newest_label(__aa_task_raw_label(task));
83         rcu_read_unlock();
84
85         return p;
86 }
87
88 /**
89  * aa_replace_current_label - replace the current tasks label
90  * @label: new label  (NOT NULL)
91  *
92  * Returns: 0 or error on failure
93  */
94 int aa_replace_current_label(struct aa_label *label)
95 {
96         struct aa_task_ctx *ctx = current_ctx();
97         struct cred *new;
98         AA_BUG(!label);
99
100         if (ctx->label == label)
101                 return 0;
102
103         if (current_cred() != current_real_cred())
104                 return -EBUSY;
105
106         new  = prepare_creds();
107         if (!new)
108                 return -ENOMEM;
109
110         ctx = cred_ctx(new);
111         if (unconfined(label) || (labels_ns(ctx->label) != labels_ns(label)))
112                 /* if switching to unconfined or a different label namespace
113                  * clear out context state
114                  */
115                 aa_clear_task_ctx_trans(ctx);
116
117         /*
118          * be careful switching ctx->profile, when racing replacement it
119          * is possible that ctx->profile->proxy->profile is the reference
120          * keeping @profile valid, so make sure to get its reference before
121          * dropping the reference on ctx->profile
122          */
123         aa_get_label(label);
124         aa_put_label(ctx->label);
125         ctx->label = label;
126
127         commit_creds(new);
128         return 0;
129 }
130
131 /**
132  * aa_set_current_onexec - set the tasks change_profile to happen onexec
133  * @label: system label to set at exec  (MAYBE NULL to clear value)
134  * @stack: whether stacking should be done
135  * Returns: 0 or error on failure
136  */
137 int aa_set_current_onexec(struct aa_label *label, bool stack)
138 {
139         struct aa_task_ctx *ctx;
140         struct cred *new = prepare_creds();
141         if (!new)
142                 return -ENOMEM;
143
144         ctx = cred_ctx(new);
145         aa_get_label(label);
146         aa_clear_task_ctx_trans(ctx);
147         ctx->onexec = label;
148         ctx->token = stack;
149
150         commit_creds(new);
151         return 0;
152 }
153
154 /**
155  * aa_set_current_hat - set the current tasks hat
156  * @label: label to set as the current hat  (NOT NULL)
157  * @token: token value that must be specified to change from the hat
158  *
159  * Do switch of tasks hat.  If the task is currently in a hat
160  * validate the token to match.
161  *
162  * Returns: 0 or error on failure
163  */
164 int aa_set_current_hat(struct aa_label *label, u64 token)
165 {
166         struct aa_task_ctx *ctx;
167         struct cred *new = prepare_creds();
168         if (!new)
169                 return -ENOMEM;
170         AA_BUG(!label);
171
172         ctx = cred_ctx(new);
173         if (!ctx->previous) {
174                 /* transfer refcount */
175                 ctx->previous = ctx->label;
176                 ctx->token = token;
177         } else if (ctx->token == token) {
178                 aa_put_label(ctx->label);
179         } else {
180                 /* previous_profile && ctx->token != token */
181                 abort_creds(new);
182                 return -EACCES;
183         }
184         ctx->label = aa_get_newest_label(label);
185         /* clear exec on switching context */
186         aa_put_label(ctx->onexec);
187         ctx->onexec = NULL;
188
189         commit_creds(new);
190         return 0;
191 }
192
193 /**
194  * aa_restore_previous_label - exit from hat context restoring previous label
195  * @token: the token that must be matched to exit hat context
196  *
197  * Attempt to return out of a hat to the previous label.  The token
198  * must match the stored token value.
199  *
200  * Returns: 0 or error of failure
201  */
202 int aa_restore_previous_label(u64 token)
203 {
204         struct aa_task_ctx *ctx;
205         struct cred *new = prepare_creds();
206         if (!new)
207                 return -ENOMEM;
208
209         ctx = cred_ctx(new);
210         if (ctx->token != token) {
211                 abort_creds(new);
212                 return -EACCES;
213         }
214         /* ignore restores when there is no saved label */
215         if (!ctx->previous) {
216                 abort_creds(new);
217                 return 0;
218         }
219
220         aa_put_label(ctx->label);
221         ctx->label = aa_get_newest_label(ctx->previous);
222         AA_BUG(!ctx->label);
223         /* clear exec && prev information when restoring to previous context */
224         aa_clear_task_ctx_trans(ctx);
225
226         commit_creds(new);
227         return 0;
228 }