summaryrefslogtreecommitdiffstats
path: root/security/apparmor/include/policy.h
blob: 545f791cabdae2b4e45c485d9c1010adbc830711 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * AppArmor security module
 *
 * This file contains AppArmor policy definitions.
 *
 * Copyright (C) 1998-2008 Novell/SUSE
 * Copyright 2009-2010 Canonical Ltd.
 */

#ifndef __AA_POLICY_H
#define __AA_POLICY_H

#include <linux/capability.h>
#include <linux/cred.h>
#include <linux/kref.h>
#include <linux/rhashtable.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/socket.h>

#include "apparmor.h"
#include "audit.h"
#include "capability.h"
#include "domain.h"
#include "file.h"
#include "lib.h"
#include "label.h"
#include "net.h"
#include "perms.h"
#include "resource.h"


struct aa_ns;

extern int unprivileged_userns_apparmor_policy;

extern const char *const aa_profile_mode_names[];
#define APPARMOR_MODE_NAMES_MAX_INDEX 4

#define PROFILE_MODE(_profile, _mode)		\
	((aa_g_profile_mode == (_mode)) ||	\
	 ((_profile)->mode == (_mode)))

#define COMPLAIN_MODE(_profile)	PROFILE_MODE((_profile), APPARMOR_COMPLAIN)

#define USER_MODE(_profile)	PROFILE_MODE((_profile), APPARMOR_USER)

#define KILL_MODE(_profile) PROFILE_MODE((_profile), APPARMOR_KILL)

#define PROFILE_IS_HAT(_profile) ((_profile)->label.flags & FLAG_HAT)

#define CHECK_DEBUG1(_profile) ((_profile)->label.flags & FLAG_DEBUG1)

#define CHECK_DEBUG2(_profile) ((_profile)->label.flags & FLAG_DEBUG2)

#define profile_is_stale(_profile) (label_is_stale(&(_profile)->label))

#define on_list_rcu(X) (!list_empty(X) && (X)->prev != LIST_POISON2)

/*
 * FIXME: currently need a clean way to replace and remove profiles as a
 * set.  It should be done at the namespace level.
 * Either, with a set of profiles loaded at the namespace level or via
 * a mark and remove marked interface.
 */
enum profile_mode {
	APPARMOR_ENFORCE,	/* enforce access rules */
	APPARMOR_COMPLAIN,	/* allow and log access violations */
	APPARMOR_KILL,		/* kill task on access violation */
	APPARMOR_UNCONFINED,	/* profile set to unconfined */
	APPARMOR_USER,		/* modified complain mode to userspace */
};


/* struct aa_policydb - match engine for a policy
 * dfa: dfa pattern match
 * perms: table of permissions
 * strs: table of strings, index by x
 * start: set of start states for the different classes of data
 */
struct aa_policydb {
	struct aa_dfa *dfa;
	struct {
		struct aa_perms *perms;
		u32 size;
	};
	struct aa_str_table trans;
	aa_state_t start[AA_CLASS_LAST + 1];
};

static inline void aa_destroy_policydb(struct aa_policydb *policy)
{
	aa_put_dfa(policy->dfa);
	if (policy->perms)
		kvfree(policy->perms);
	aa_free_str_table(&policy->trans);

}

static inline struct aa_perms *aa_lookup_perms(struct aa_policydb *policy,
					       aa_state_t state)
{
	unsigned int index = ACCEPT_TABLE(policy->dfa)[state];

	if (!(policy->perms))
		return &default_perms;

	return &(policy->perms[index]);
}


/* struct aa_data - generic data structure
 * key: name for retrieving this data
 * size: size of data in bytes
 * data: binary data
 * head: reserved for rhashtable
 */
struct aa_data {
	char *key;
	u32 size;
	char *data;
	struct rhash_head head;
};

/* struct aa_ruleset - data covering mediation rules
 * @list: list the rule is on
 * @size: the memory consumed by this ruleset
 * @policy: general match rules governing policy
 * @file: The set of rules governing basic file access and domain transitions
 * @caps: capabilities for the profile
 * @rlimits: rlimits for the profile
 * @secmark_count: number of secmark entries
 * @secmark: secmark label match info
 */
struct aa_ruleset {
	struct list_head list;

	int size;

	/* TODO: merge policy and file */
	struct aa_policydb policy;
	struct aa_policydb file;
	struct aa_caps caps;

	struct aa_rlimit rlimits;

	int secmark_count;
	struct aa_secmark *secmark;
};

/* struct aa_attachment - data and rules for a profiles attachment
 * @list:
 * @xmatch_str: human readable attachment string
 * @xmatch: optional extended matching for unconfined executables names
 * @xmatch_len: xmatch prefix len, used to determine xmatch priority
 * @xattr_count: number of xattrs in table
 * @xattrs: table of xattrs
 */
struct aa_attachment {
	const char *xmatch_str;
	struct aa_policydb xmatch;
	unsigned int xmatch_len;
	int xattr_count;
	char **xattrs;
};

/* struct aa_profile - basic confinement data
 * @base - base components of the profile (name, refcount, lists, lock ...)
 * @label - label this profile is an extension of
 * @parent: parent of profile
 * @ns: namespace the profile is in
 * @rename: optional profile name that this profile renamed
 *
 * @audit: the auditing mode of the profile
 * @mode: the enforcement mode of the profile
 * @path_flags: flags controlling path generation behavior
 * @disconnected: what to prepend if attach_disconnected is specified
 * @attach: attachment rules for the profile
 * @rules: rules to be enforced
 *
 * @dents: dentries for the profiles file entries in apparmorfs
 * @dirname: name of the profile dir in apparmorfs
 * @data: hashtable for free-form policy aa_data
 *
 * The AppArmor profile contains the basic confinement data.  Each profile
 * has a name, and exists in a namespace.  The @name and @exec_match are
 * used to determine profile attachment against unconfined tasks.  All other
 * attachments are determined by profile X transition rules.
 *
 * Profiles have a hierarchy where hats and children profiles keep
 * a reference to their parent.
 *
 * Profile names can not begin with a : and can not contain the \0
 * character.  If a profile name begins with / it will be considered when
 * determining profile attachment on "unconfined" tasks.
 */
struct aa_profile {
	struct aa_policy base;
	struct aa_profile __rcu *parent;

	struct aa_ns *ns;
	const char *rename;

	enum audit_mode audit;
	long mode;
	u32 path_flags;
	const char *disconnected;

	struct aa_attachment attach;
	struct list_head rules;

	struct aa_loaddata *rawdata;
	unsigned char *hash;
	char *dirname;
	struct dentry *dents[AAFS_PROF_SIZEOF];
	struct rhashtable *data;
	struct aa_label label;
};

extern enum profile_mode aa_g_profile_mode;

#define AA_MAY_LOAD_POLICY	AA_MAY_APPEND
#define AA_MAY_REPLACE_POLICY	AA_MAY_WRITE
#define AA_MAY_REMOVE_POLICY	AA_MAY_DELETE

#define profiles_ns(P) ((P)->ns)
#define name_is_shared(A, B) ((A)->hname && (A)->hname == (B)->hname)

void aa_add_profile(struct aa_policy *common, struct aa_profile *profile);


void aa_free_proxy_kref(struct kref *kref);
struct aa_ruleset *aa_alloc_ruleset(gfp_t gfp);
struct aa_profile *aa_alloc_profile(const char *name, struct aa_proxy *proxy,
				    gfp_t gfp);
struct aa_profile *aa_alloc_null(struct aa_profile *parent, const char *name,
				 gfp_t gfp);
struct aa_profile *aa_new_learning_profile(struct aa_profile *parent, bool hat,
					   const char *base, gfp_t gfp);
void aa_free_profile(struct aa_profile *profile);
void aa_free_profile_kref(struct kref *kref);
struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name);
struct aa_profile *aa_lookupn_profile(struct aa_ns *ns, const char *hname,
				      size_t n);
struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *name);
struct aa_profile *aa_fqlookupn_profile(struct aa_label *base,
					const char *fqname, size_t n);
struct aa_profile *aa_match_profile(struct aa_ns *ns, const char *name);

ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_label *label,
			    u32 mask, struct aa_loaddata *udata);
ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_label *label,
			   char *name, size_t size);
void __aa_profile_list_release(struct list_head *head);

#define PROF_ADD 1
#define PROF_REPLACE 0

#define profile_unconfined(X) ((X)->mode == APPARMOR_UNCONFINED)

/**
 * aa_get_newest_profile - simple wrapper fn to wrap the label version
 * @p: profile (NOT NULL)
 *
 * Returns refcount to newest version of the profile (maybe @p)
 *
 * Requires: @p must be held with a valid refcount
 */
static inline struct aa_profile *aa_get_newest_profile(struct aa_profile *p)
{
	return labels_profile(aa_get_newest_label(&p->label));
}

static inline aa_state_t RULE_MEDIATES(struct aa_ruleset *rules,
				       unsigned char class)
{
	if (class <= AA_CLASS_LAST)
		return rules->policy.start[class];
	else
		return aa_dfa_match_len(rules->policy.dfa,
					rules->policy.start[0], &class, 1);
}

static inline aa_state_t RULE_MEDIATES_AF(struct aa_ruleset *rules, u16 AF)
{
	aa_state_t state = RULE_MEDIATES(rules, AA_CLASS_NET);
	__be16 be_af = cpu_to_be16(AF);

	if (!state)
		return DFA_NOMATCH;
	return aa_dfa_match_len(rules->policy.dfa, state, (char *) &be_af, 2);
}

static inline aa_state_t ANY_RULE_MEDIATES(struct list_head *head,
					   unsigned char class)
{
	struct aa_ruleset *rule;

	/* TODO: change to list walk */
	rule = list_first_entry(head, typeof(*rule), list);
	return RULE_MEDIATES(rule, class);
}

/**
 * aa_get_profile - increment refcount on profile @p
 * @p: profile  (MAYBE NULL)
 *
 * Returns: pointer to @p if @p is NULL will return NULL
 * Requires: @p must be held with valid refcount when called
 */
static inline struct aa_profile *aa_get_profile(struct aa_profile *p)
{
	if (p)
		kref_get(&(p->label.count));

	return p;
}

/**
 * aa_get_profile_not0 - increment refcount on profile @p found via lookup
 * @p: profile  (MAYBE NULL)
 *
 * Returns: pointer to @p if @p is NULL will return NULL
 * Requires: @p must be held with valid refcount when called
 */
static inline struct aa_profile *aa_get_profile_not0(struct aa_profile *p)
{
	if (p && kref_get_unless_zero(&p->label.count))
		return p;

	return NULL;
}

/**
 * aa_get_profile_rcu - increment a refcount profile that can be replaced
 * @p: pointer to profile that can be replaced (NOT NULL)
 *
 * Returns: pointer to a refcounted profile.
 *     else NULL if no profile
 */
static inline struct aa_profile *aa_get_profile_rcu(struct aa_profile __rcu **p)
{
	struct aa_profile *c;

	rcu_read_lock();
	do {
		c = rcu_dereference(*p);
	} while (c && !kref_get_unless_zero(&c->label.count));
	rcu_read_unlock();

	return c;
}

/**
 * aa_put_profile - decrement refcount on profile @p
 * @p: profile  (MAYBE NULL)
 */
static inline void aa_put_profile(struct aa_profile *p)
{
	if (p)
		kref_put(&p->label.count, aa_label_kref);
}

static inline int AUDIT_MODE(struct aa_profile *profile)
{
	if (aa_g_audit != AUDIT_NORMAL)
		return aa_g_audit;

	return profile->audit;
}

bool aa_policy_view_capable(struct aa_label *label, struct aa_ns *ns);
bool aa_policy_admin_capable(struct aa_label *label, struct aa_ns *ns);
int aa_may_manage_policy(struct aa_label *label, struct aa_ns *ns,
			 u32 mask);
bool aa_current_policy_view_capable(struct aa_ns *ns);
bool aa_current_policy_admin_capable(struct aa_ns *ns);

#endif /* __AA_POLICY_H */