]> git.ipfire.org Git - thirdparty/linux.git/blame - security/apparmor/task.c
Merge branch 'fixes-v5.1' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris...
[thirdparty/linux.git] / security / apparmor / task.c
CommitLineData
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 28struct 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 45int 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 83 aa_put_label(cred_label(new));
69b5a44a 84 set_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 97int 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 119int 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
69b5a44a 141 set_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 159int 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));
69b5a44a 175 set_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}