Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/security/apparmor/resource.c
26377 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* AppArmor security module
4
*
5
* This file contains AppArmor resource mediation and attachment
6
*
7
* Copyright (C) 1998-2008 Novell/SUSE
8
* Copyright 2009-2010 Canonical Ltd.
9
*/
10
11
#include <linux/audit.h>
12
#include <linux/security.h>
13
14
#include "include/audit.h"
15
#include "include/cred.h"
16
#include "include/resource.h"
17
#include "include/policy.h"
18
19
/*
20
* Table of rlimit names: we generate it from resource.h.
21
*/
22
#include "rlim_names.h"
23
24
struct aa_sfs_entry aa_sfs_entry_rlimit[] = {
25
AA_SFS_FILE_STRING("mask", AA_SFS_RLIMIT_MASK),
26
{ }
27
};
28
29
/* audit callback for resource specific fields */
30
static void audit_cb(struct audit_buffer *ab, void *va)
31
{
32
struct common_audit_data *sa = va;
33
struct apparmor_audit_data *ad = aad(sa);
34
35
audit_log_format(ab, " rlimit=%s value=%lu",
36
rlim_names[ad->rlim.rlim], ad->rlim.max);
37
if (ad->peer) {
38
audit_log_format(ab, " peer=");
39
aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer,
40
FLAGS_NONE, GFP_ATOMIC);
41
}
42
}
43
44
/**
45
* audit_resource - audit setting resource limit
46
* @subj_cred: cred setting the resource
47
* @profile: profile being enforced (NOT NULL)
48
* @resource: rlimit being auditing
49
* @value: value being set
50
* @peer: aa_albel of the task being set
51
* @info: info being auditing
52
* @error: error value
53
*
54
* Returns: 0 or ad->error else other error code on failure
55
*/
56
static int audit_resource(const struct cred *subj_cred,
57
struct aa_profile *profile, unsigned int resource,
58
unsigned long value, struct aa_label *peer,
59
const char *info, int error)
60
{
61
DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_RLIMITS,
62
OP_SETRLIMIT);
63
64
ad.subj_cred = subj_cred;
65
ad.rlim.rlim = resource;
66
ad.rlim.max = value;
67
ad.peer = peer;
68
ad.info = info;
69
ad.error = error;
70
71
return aa_audit(AUDIT_APPARMOR_AUTO, profile, &ad, audit_cb);
72
}
73
74
/**
75
* aa_map_resource - map compiled policy resource to internal #
76
* @resource: flattened policy resource number
77
*
78
* Returns: resource # for the current architecture.
79
*
80
* rlimit resource can vary based on architecture, map the compiled policy
81
* resource # to the internal representation for the architecture.
82
*/
83
int aa_map_resource(int resource)
84
{
85
return rlim_map[resource];
86
}
87
88
static int profile_setrlimit(const struct cred *subj_cred,
89
struct aa_profile *profile, unsigned int resource,
90
struct rlimit *new_rlim)
91
{
92
struct aa_ruleset *rules = profile->label.rules[0];
93
int e = 0;
94
95
if (rules->rlimits.mask & (1 << resource) && new_rlim->rlim_max >
96
rules->rlimits.limits[resource].rlim_max)
97
e = -EACCES;
98
return audit_resource(subj_cred, profile, resource, new_rlim->rlim_max,
99
NULL, NULL, e);
100
}
101
102
/**
103
* aa_task_setrlimit - test permission to set an rlimit
104
* @subj_cred: cred setting the limit
105
* @label: label confining the task (NOT NULL)
106
* @task: task the resource is being set on
107
* @resource: the resource being set
108
* @new_rlim: the new resource limit (NOT NULL)
109
*
110
* Control raising the processes hard limit.
111
*
112
* Returns: 0 or error code if setting resource failed
113
*/
114
int aa_task_setrlimit(const struct cred *subj_cred, struct aa_label *label,
115
struct task_struct *task,
116
unsigned int resource, struct rlimit *new_rlim)
117
{
118
struct aa_profile *profile;
119
struct aa_label *peer;
120
int error = 0;
121
122
rcu_read_lock();
123
peer = aa_get_newest_cred_label(__task_cred(task));
124
rcu_read_unlock();
125
126
/* TODO: extend resource control to handle other (non current)
127
* profiles. AppArmor rules currently have the implicit assumption
128
* that the task is setting the resource of a task confined with
129
* the same profile or that the task setting the resource of another
130
* task has CAP_SYS_RESOURCE.
131
*/
132
133
if (label != peer &&
134
aa_capable(subj_cred, label, CAP_SYS_RESOURCE, CAP_OPT_NOAUDIT) != 0)
135
error = fn_for_each(label, profile,
136
audit_resource(subj_cred, profile, resource,
137
new_rlim->rlim_max, peer,
138
"cap_sys_resource", -EACCES));
139
else
140
error = fn_for_each_confined(label, profile,
141
profile_setrlimit(subj_cred, profile, resource,
142
new_rlim));
143
aa_put_label(peer);
144
145
return error;
146
}
147
148
/**
149
* __aa_transition_rlimits - apply new profile rlimits
150
* @old_l: old label on task (NOT NULL)
151
* @new_l: new label with rlimits to apply (NOT NULL)
152
*/
153
void __aa_transition_rlimits(struct aa_label *old_l, struct aa_label *new_l)
154
{
155
unsigned int mask = 0;
156
struct rlimit *rlim, *initrlim;
157
struct aa_profile *old, *new;
158
struct label_it i;
159
160
old = labels_profile(old_l);
161
new = labels_profile(new_l);
162
163
/* for any rlimits the profile controlled, reset the soft limit
164
* to the lesser of the tasks hard limit and the init tasks soft limit
165
*/
166
label_for_each_confined(i, old_l, old) {
167
struct aa_ruleset *rules = old->label.rules[0];
168
if (rules->rlimits.mask) {
169
int j;
170
171
for (j = 0, mask = 1; j < RLIM_NLIMITS; j++,
172
mask <<= 1) {
173
if (rules->rlimits.mask & mask) {
174
rlim = current->signal->rlim + j;
175
initrlim = init_task.signal->rlim + j;
176
rlim->rlim_cur = min(rlim->rlim_max,
177
initrlim->rlim_cur);
178
}
179
}
180
}
181
}
182
183
/* set any new hard limits as dictated by the new profile */
184
label_for_each_confined(i, new_l, new) {
185
struct aa_ruleset *rules = new->label.rules[0];
186
int j;
187
188
if (!rules->rlimits.mask)
189
continue;
190
for (j = 0, mask = 1; j < RLIM_NLIMITS; j++, mask <<= 1) {
191
if (!(rules->rlimits.mask & mask))
192
continue;
193
194
rlim = current->signal->rlim + j;
195
rlim->rlim_max = min(rlim->rlim_max,
196
rules->rlimits.limits[j].rlim_max);
197
/* soft limit should not exceed hard limit */
198
rlim->rlim_cur = min(rlim->rlim_cur, rlim->rlim_max);
199
}
200
}
201
}
202
203