task.c 4.31 KB
Newer Older
1 2 3
/*
 * AppArmor security module
 *
4
 * This file contains AppArmor task related definitions and mediation
5
 *
6
 * Copyright 2017 Canonical Ltd.
7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, version 2 of the
 * License.
 *
 * TODO
 * If a task uses change_hat it currently does not return to the old
 * cred or task context but instead creates a new one.  Ideally the task
 * should return to the previous cred if it has not been modified.
 */

19
#include "include/cred.h"
20
#include "include/task.h"
21

22
/**
23
 * aa_get_task_label - Get another task's label
24 25
 * @task: task to query  (NOT NULL)
 *
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 35 36 37 38
	rcu_read_unlock();

	return p;
}

39
/**
40 41
 * aa_replace_current_label - replace the current tasks label
 * @label: new label  (NOT NULL)
42 43 44
 *
 * Returns: 0 or error on failure
 */
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 55
		return 0;

56 57 58
	if (current_cred() != current_real_cred())
		return -EBUSY;

59 60 61 62
	new  = prepare_creds();
	if (!new)
		return -ENOMEM;

63 64 65 66 67 68
	if (ctx->nnp && label_is_stale(ctx->nnp)) {
		struct aa_label *tmp = ctx->nnp;

		ctx->nnp = aa_get_newest_label(tmp);
		aa_put_label(tmp);
	}
69 70 71
	if (unconfined(label) || (labels_ns(old) != labels_ns(label)))
		/*
		 * if switching to unconfined or a different label namespace
72 73
		 * clear out context state
		 */
74
		aa_clear_task_ctx_trans(task_ctx(current));
75

76
	/*
77 78 79 80
	 * be careful switching cred label, when racing replacement it
	 * is possible that the cred labels's->proxy->label is the reference
	 * keeping @label valid, so make sure to get its reference before
	 * 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 87 88 89

	commit_creds(new);
	return 0;
}

90

91 92
/**
 * aa_set_current_onexec - set the tasks change_profile to happen onexec
93 94
 * @label: system label to set at exec  (MAYBE NULL to clear value)
 * @stack: whether stacking should be done
95 96
 * Returns: 0 or error on failure
 */
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 104
	ctx->onexec = label;
	ctx->token = stack;
105 106 107 108 109 110

	return 0;
}

/**
 * aa_set_current_hat - set the current tasks hat
111
 * @label: label to set as the current hat  (NOT NULL)
112 113 114 115 116 117 118
 * @token: token value that must be specified to change from the hat
 *
 * Do switch of tasks hat.  If the task is currently in a hat
 * validate the token to match.
 *
 * Returns: 0 or error on failure
 */
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 126
	if (!new)
		return -ENOMEM;
127
	AA_BUG(!label);
128

129
	if (!ctx->previous) {
130
		/* transfer refcount */
131 132 133
		ctx->previous = cred_label(new);
		ctx->token = token;
	} else if (ctx->token == token) {
134
		aa_put_label(cred_label(new));
135
	} else {
136
		/* previous_profile && ctx->token != token */
137 138 139
		abort_creds(new);
		return -EACCES;
	}
140

141
	set_cred_label(new, aa_get_newest_label(label));
142
	/* clear exec on switching context */
143 144
	aa_put_label(ctx->onexec);
	ctx->onexec = NULL;
145 146 147 148 149 150

	commit_creds(new);
	return 0;
}

/**
151
 * aa_restore_previous_label - exit from hat context restoring previous label
152 153
 * @token: the token that must be matched to exit hat context
 *
154
 * Attempt to return out of a hat to the previous label.  The token
155 156 157 158
 * must match the stored token value.
 *
 * Returns: 0 or error of failure
 */
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 171 172

	new = prepare_creds();
	if (!new)
		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 183
	return 0;
}