xref: /openbmc/linux/security/apparmor/task.c (revision 8f762fe5)
1 /*
2  * AppArmor security module
3  *
4  * This file contains AppArmor task related definitions and mediation
5  *
6  * Copyright 2017 Canonical Ltd.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation, version 2 of the
11  * License.
12  *
13  * TODO
14  * If a task uses change_hat it currently does not return to the old
15  * cred or task context but instead creates a new one.  Ideally the task
16  * should return to the previous cred if it has not been modified.
17  */
18 
19 #include "include/cred.h"
20 #include "include/task.h"
21 
22 /**
23  * aa_get_task_label - Get another task's label
24  * @task: task to query  (NOT NULL)
25  *
26  * Returns: counted reference to @task's label
27  */
28 struct aa_label *aa_get_task_label(struct task_struct *task)
29 {
30 	struct aa_label *p;
31 
32 	rcu_read_lock();
33 	p = aa_get_newest_label(__aa_task_raw_label(task));
34 	rcu_read_unlock();
35 
36 	return p;
37 }
38 
39 /**
40  * aa_replace_current_label - replace the current tasks label
41  * @label: new label  (NOT NULL)
42  *
43  * Returns: 0 or error on failure
44  */
45 int aa_replace_current_label(struct aa_label *label)
46 {
47 	struct aa_label *old = aa_current_raw_label();
48 	struct aa_task_ctx *ctx = task_ctx(current);
49 	struct cred *new;
50 
51 	AA_BUG(!label);
52 
53 	if (old == label)
54 		return 0;
55 
56 	if (current_cred() != current_real_cred())
57 		return -EBUSY;
58 
59 	new  = prepare_creds();
60 	if (!new)
61 		return -ENOMEM;
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 	}
69 	if (unconfined(label) || (labels_ns(old) != labels_ns(label)))
70 		/*
71 		 * if switching to unconfined or a different label namespace
72 		 * clear out context state
73 		 */
74 		aa_clear_task_ctx_trans(task_ctx(current));
75 
76 	/*
77 	 * be careful switching cred label, when racing replacement it
78 	 * is possible that the cred labels's->proxy->label is the reference
79 	 * keeping @label valid, so make sure to get its reference before
80 	 * dropping the reference on the cred's label
81 	 */
82 	aa_get_label(label);
83 	aa_put_label(cred_label(new));
84 	set_cred_label(new, label);
85 
86 	commit_creds(new);
87 	return 0;
88 }
89 
90 
91 /**
92  * aa_set_current_onexec - set the tasks change_profile to happen onexec
93  * @label: system label to set at exec  (MAYBE NULL to clear value)
94  * @stack: whether stacking should be done
95  * Returns: 0 or error on failure
96  */
97 int aa_set_current_onexec(struct aa_label *label, bool stack)
98 {
99 	struct aa_task_ctx *ctx = task_ctx(current);
100 
101 	aa_get_label(label);
102 	aa_put_label(ctx->onexec);
103 	ctx->onexec = label;
104 	ctx->token = stack;
105 
106 	return 0;
107 }
108 
109 /**
110  * aa_set_current_hat - set the current tasks hat
111  * @label: label to set as the current hat  (NOT NULL)
112  * @token: token value that must be specified to change from the hat
113  *
114  * Do switch of tasks hat.  If the task is currently in a hat
115  * validate the token to match.
116  *
117  * Returns: 0 or error on failure
118  */
119 int aa_set_current_hat(struct aa_label *label, u64 token)
120 {
121 	struct aa_task_ctx *ctx = task_ctx(current);
122 	struct cred *new;
123 
124 	new = prepare_creds();
125 	if (!new)
126 		return -ENOMEM;
127 	AA_BUG(!label);
128 
129 	if (!ctx->previous) {
130 		/* transfer refcount */
131 		ctx->previous = cred_label(new);
132 		ctx->token = token;
133 	} else if (ctx->token == token) {
134 		aa_put_label(cred_label(new));
135 	} else {
136 		/* previous_profile && ctx->token != token */
137 		abort_creds(new);
138 		return -EACCES;
139 	}
140 
141 	set_cred_label(new, aa_get_newest_label(label));
142 	/* clear exec on switching context */
143 	aa_put_label(ctx->onexec);
144 	ctx->onexec = NULL;
145 
146 	commit_creds(new);
147 	return 0;
148 }
149 
150 /**
151  * aa_restore_previous_label - exit from hat context restoring previous label
152  * @token: the token that must be matched to exit hat context
153  *
154  * Attempt to return out of a hat to the previous label.  The token
155  * must match the stored token value.
156  *
157  * Returns: 0 or error of failure
158  */
159 int aa_restore_previous_label(u64 token)
160 {
161 	struct aa_task_ctx *ctx = task_ctx(current);
162 	struct cred *new;
163 
164 	if (ctx->token != token)
165 		return -EACCES;
166 	/* ignore restores when there is no saved label */
167 	if (!ctx->previous)
168 		return 0;
169 
170 	new = prepare_creds();
171 	if (!new)
172 		return -ENOMEM;
173 
174 	aa_put_label(cred_label(new));
175 	set_cred_label(new, aa_get_newest_label(ctx->previous));
176 	AA_BUG(!cred_label(new));
177 	/* clear exec && prev information when restoring to previous context */
178 	aa_clear_task_ctx_trans(ctx);
179 
180 	commit_creds(new);
181 
182 	return 0;
183 }
184