Commit | Line | Data |
---|---|---|
c75afcd1 JJ |
1 | /* |
2 | * AppArmor security module | |
3 | * | |
de62de59 | 4 | * This file contains AppArmor task related definitions and mediation |
c75afcd1 | 5 | * |
de62de59 | 6 | * Copyright 2017 Canonical Ltd. |
c75afcd1 JJ |
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 | * | |
c75afcd1 JJ |
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. | |
c75afcd1 JJ |
17 | */ |
18 | ||
d8889d49 | 19 | #include "include/cred.h" |
de62de59 | 20 | #include "include/task.h" |
c75afcd1 | 21 | |
3cfcc19e | 22 | /** |
637f688d | 23 | * aa_get_task_label - Get another task's label |
3cfcc19e JJ |
24 | * @task: task to query (NOT NULL) |
25 | * | |
637f688d | 26 | * Returns: counted reference to @task's label |
3cfcc19e | 27 | */ |
637f688d | 28 | struct aa_label *aa_get_task_label(struct task_struct *task) |
3cfcc19e | 29 | { |
637f688d | 30 | struct aa_label *p; |
3cfcc19e JJ |
31 | |
32 | rcu_read_lock(); | |
637f688d | 33 | p = aa_get_newest_label(__aa_task_raw_label(task)); |
3cfcc19e JJ |
34 | rcu_read_unlock(); |
35 | ||
36 | return p; | |
37 | } | |
38 | ||
c75afcd1 | 39 | /** |
637f688d JJ |
40 | * aa_replace_current_label - replace the current tasks label |
41 | * @label: new label (NOT NULL) | |
c75afcd1 JJ |
42 | * |
43 | * Returns: 0 or error on failure | |
44 | */ | |
637f688d | 45 | int aa_replace_current_label(struct aa_label *label) |
c75afcd1 | 46 | { |
d9087c49 | 47 | struct aa_label *old = aa_current_raw_label(); |
9fcf78cc | 48 | struct aa_task_ctx *ctx = task_ctx(current); |
c75afcd1 | 49 | struct cred *new; |
d9087c49 | 50 | |
637f688d | 51 | AA_BUG(!label); |
c75afcd1 | 52 | |
d9087c49 | 53 | if (old == label) |
c75afcd1 JJ |
54 | return 0; |
55 | ||
a20aa95f JJ |
56 | if (current_cred() != current_real_cred()) |
57 | return -EBUSY; | |
58 | ||
c75afcd1 JJ |
59 | new = prepare_creds(); |
60 | if (!new) | |
61 | return -ENOMEM; | |
62 | ||
9fcf78cc JJ |
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 | } | |
d9087c49 JJ |
69 | if (unconfined(label) || (labels_ns(old) != labels_ns(label))) |
70 | /* | |
71 | * if switching to unconfined or a different label namespace | |
c75afcd1 JJ |
72 | * clear out context state |
73 | */ | |
de62de59 | 74 | aa_clear_task_ctx_trans(task_ctx(current)); |
7a2871b5 | 75 | |
55a26ebf | 76 | /* |
d9087c49 JJ |
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 | |
55a26ebf | 81 | */ |
637f688d | 82 | aa_get_label(label); |
d9087c49 JJ |
83 | aa_put_label(cred_label(new)); |
84 | cred_label(new) = label; | |
c75afcd1 JJ |
85 | |
86 | commit_creds(new); | |
87 | return 0; | |
88 | } | |
89 | ||
de62de59 | 90 | |
c75afcd1 JJ |
91 | /** |
92 | * aa_set_current_onexec - set the tasks change_profile to happen onexec | |
637f688d JJ |
93 | * @label: system label to set at exec (MAYBE NULL to clear value) |
94 | * @stack: whether stacking should be done | |
c75afcd1 JJ |
95 | * Returns: 0 or error on failure |
96 | */ | |
637f688d | 97 | int aa_set_current_onexec(struct aa_label *label, bool stack) |
c75afcd1 | 98 | { |
de62de59 | 99 | struct aa_task_ctx *ctx = task_ctx(current); |
c75afcd1 | 100 | |
637f688d | 101 | aa_get_label(label); |
3b529a76 | 102 | aa_put_label(ctx->onexec); |
637f688d JJ |
103 | ctx->onexec = label; |
104 | ctx->token = stack; | |
c75afcd1 | 105 | |
c75afcd1 JJ |
106 | return 0; |
107 | } | |
108 | ||
109 | /** | |
110 | * aa_set_current_hat - set the current tasks hat | |
637f688d | 111 | * @label: label to set as the current hat (NOT NULL) |
c75afcd1 JJ |
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 | */ | |
637f688d | 119 | int aa_set_current_hat(struct aa_label *label, u64 token) |
c75afcd1 | 120 | { |
de62de59 | 121 | struct aa_task_ctx *ctx = task_ctx(current); |
d9087c49 | 122 | struct cred *new; |
3b529a76 | 123 | |
d9087c49 | 124 | new = prepare_creds(); |
c75afcd1 JJ |
125 | if (!new) |
126 | return -ENOMEM; | |
637f688d | 127 | AA_BUG(!label); |
c75afcd1 | 128 | |
f175221a | 129 | if (!ctx->previous) { |
c75afcd1 | 130 | /* transfer refcount */ |
f175221a JJ |
131 | ctx->previous = cred_label(new); |
132 | ctx->token = token; | |
133 | } else if (ctx->token == token) { | |
d9087c49 | 134 | aa_put_label(cred_label(new)); |
c75afcd1 | 135 | } else { |
55a26ebf | 136 | /* previous_profile && ctx->token != token */ |
c75afcd1 JJ |
137 | abort_creds(new); |
138 | return -EACCES; | |
139 | } | |
3b529a76 | 140 | |
d9087c49 | 141 | cred_label(new) = aa_get_newest_label(label); |
c75afcd1 | 142 | /* clear exec on switching context */ |
f175221a JJ |
143 | aa_put_label(ctx->onexec); |
144 | ctx->onexec = NULL; | |
c75afcd1 JJ |
145 | |
146 | commit_creds(new); | |
147 | return 0; | |
148 | } | |
149 | ||
150 | /** | |
637f688d | 151 | * aa_restore_previous_label - exit from hat context restoring previous label |
c75afcd1 JJ |
152 | * @token: the token that must be matched to exit hat context |
153 | * | |
637f688d | 154 | * Attempt to return out of a hat to the previous label. The token |
c75afcd1 JJ |
155 | * must match the stored token value. |
156 | * | |
157 | * Returns: 0 or error of failure | |
158 | */ | |
637f688d | 159 | int aa_restore_previous_label(u64 token) |
c75afcd1 | 160 | { |
de62de59 | 161 | struct aa_task_ctx *ctx = task_ctx(current); |
3b529a76 | 162 | struct cred *new; |
c75afcd1 | 163 | |
f175221a | 164 | if (ctx->token != token) |
c75afcd1 | 165 | return -EACCES; |
637f688d | 166 | /* ignore restores when there is no saved label */ |
f175221a | 167 | if (!ctx->previous) |
c75afcd1 | 168 | return 0; |
3b529a76 JJ |
169 | |
170 | new = prepare_creds(); | |
171 | if (!new) | |
172 | return -ENOMEM; | |
c75afcd1 | 173 | |
d9087c49 | 174 | aa_put_label(cred_label(new)); |
f175221a | 175 | cred_label(new) = aa_get_newest_label(ctx->previous); |
d9087c49 | 176 | AA_BUG(!cred_label(new)); |
7a2871b5 | 177 | /* clear exec && prev information when restoring to previous context */ |
f175221a | 178 | aa_clear_task_ctx_trans(ctx); |
c75afcd1 JJ |
179 | |
180 | commit_creds(new); | |
3b529a76 | 181 | |
c75afcd1 JJ |
182 | return 0; |
183 | } |