• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/security/apparmor/
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor mediation of files
5 *
6 * Copyright (C) 1998-2008 Novell/SUSE
7 * Copyright 2009-2010 Canonical Ltd.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation, version 2 of the
12 * License.
13 */
14
15#include "include/apparmor.h"
16#include "include/audit.h"
17#include "include/file.h"
18#include "include/match.h"
19#include "include/path.h"
20#include "include/policy.h"
21
22struct file_perms nullperms;
23
24
25/**
26 * audit_file_mask - convert mask to permission string
27 * @buffer: buffer to write string to (NOT NULL)
28 * @mask: permission mask to convert
29 */
30static void audit_file_mask(struct audit_buffer *ab, u32 mask)
31{
32	char str[10];
33
34	char *m = str;
35
36	if (mask & AA_EXEC_MMAP)
37		*m++ = 'm';
38	if (mask & (MAY_READ | AA_MAY_META_READ))
39		*m++ = 'r';
40	if (mask & (MAY_WRITE | AA_MAY_META_WRITE | AA_MAY_CHMOD |
41		    AA_MAY_CHOWN))
42		*m++ = 'w';
43	else if (mask & MAY_APPEND)
44		*m++ = 'a';
45	if (mask & AA_MAY_CREATE)
46		*m++ = 'c';
47	if (mask & AA_MAY_DELETE)
48		*m++ = 'd';
49	if (mask & AA_MAY_LINK)
50		*m++ = 'l';
51	if (mask & AA_MAY_LOCK)
52		*m++ = 'k';
53	if (mask & MAY_EXEC)
54		*m++ = 'x';
55	*m = '\0';
56
57	audit_log_string(ab, str);
58}
59
60/**
61 * file_audit_cb - call back for file specific audit fields
62 * @ab: audit_buffer  (NOT NULL)
63 * @va: audit struct to audit values of  (NOT NULL)
64 */
65static void file_audit_cb(struct audit_buffer *ab, void *va)
66{
67	struct common_audit_data *sa = va;
68	uid_t fsuid = current_fsuid();
69
70	if (sa->aad.fs.request & AA_AUDIT_FILE_MASK) {
71		audit_log_format(ab, " requested_mask=");
72		audit_file_mask(ab, sa->aad.fs.request);
73	}
74	if (sa->aad.fs.denied & AA_AUDIT_FILE_MASK) {
75		audit_log_format(ab, " denied_mask=");
76		audit_file_mask(ab, sa->aad.fs.denied);
77	}
78	if (sa->aad.fs.request & AA_AUDIT_FILE_MASK) {
79		audit_log_format(ab, " fsuid=%d", fsuid);
80		audit_log_format(ab, " ouid=%d", sa->aad.fs.ouid);
81	}
82
83	if (sa->aad.fs.target) {
84		audit_log_format(ab, " target=");
85		audit_log_untrustedstring(ab, sa->aad.fs.target);
86	}
87}
88
89/**
90 * aa_audit_file - handle the auditing of file operations
91 * @profile: the profile being enforced  (NOT NULL)
92 * @perms: the permissions computed for the request (NOT NULL)
93 * @gfp: allocation flags
94 * @op: operation being mediated
95 * @request: permissions requested
96 * @name: name of object being mediated (MAYBE NULL)
97 * @target: name of target (MAYBE NULL)
98 * @ouid: object uid
99 * @info: extra information message (MAYBE NULL)
100 * @error: 0 if operation allowed else failure error code
101 *
102 * Returns: %0 or error on failure
103 */
104int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
105		  gfp_t gfp, int op, u32 request, const char *name,
106		  const char *target, uid_t ouid, const char *info, int error)
107{
108	int type = AUDIT_APPARMOR_AUTO;
109	struct common_audit_data sa;
110	COMMON_AUDIT_DATA_INIT(&sa, NONE);
111	sa.aad.op = op,
112	sa.aad.fs.request = request;
113	sa.aad.name = name;
114	sa.aad.fs.target = target;
115	sa.aad.fs.ouid = ouid;
116	sa.aad.info = info;
117	sa.aad.error = error;
118
119	if (likely(!sa.aad.error)) {
120		u32 mask = perms->audit;
121
122		if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
123			mask = 0xffff;
124
125		/* mask off perms that are not being force audited */
126		sa.aad.fs.request &= mask;
127
128		if (likely(!sa.aad.fs.request))
129			return 0;
130		type = AUDIT_APPARMOR_AUDIT;
131	} else {
132		/* only report permissions that were denied */
133		sa.aad.fs.request = sa.aad.fs.request & ~perms->allow;
134
135		if (sa.aad.fs.request & perms->kill)
136			type = AUDIT_APPARMOR_KILL;
137
138		/* quiet known rejects, assumes quiet and kill do not overlap */
139		if ((sa.aad.fs.request & perms->quiet) &&
140		    AUDIT_MODE(profile) != AUDIT_NOQUIET &&
141		    AUDIT_MODE(profile) != AUDIT_ALL)
142			sa.aad.fs.request &= ~perms->quiet;
143
144		if (!sa.aad.fs.request)
145			return COMPLAIN_MODE(profile) ? 0 : sa.aad.error;
146	}
147
148	sa.aad.fs.denied = sa.aad.fs.request & ~perms->allow;
149	return aa_audit(type, profile, gfp, &sa, file_audit_cb);
150}
151
152/**
153 * map_old_perms - map old file perms layout to the new layout
154 * @old: permission set in old mapping
155 *
156 * Returns: new permission mapping
157 */
158static u32 map_old_perms(u32 old)
159{
160	u32 new = old & 0xf;
161	if (old & MAY_READ)
162		new |= AA_MAY_META_READ;
163	if (old & MAY_WRITE)
164		new |= AA_MAY_META_WRITE | AA_MAY_CREATE | AA_MAY_DELETE |
165			AA_MAY_CHMOD | AA_MAY_CHOWN;
166	if (old & 0x10)
167		new |= AA_MAY_LINK;
168	/* the old mapping lock and link_subset flags where overlaid
169	 * and use was determined by part of a pair that they were in
170	 */
171	if (old & 0x20)
172		new |= AA_MAY_LOCK | AA_LINK_SUBSET;
173	if (old & 0x40)	/* AA_EXEC_MMAP */
174		new |= AA_EXEC_MMAP;
175
176	new |= AA_MAY_META_READ;
177
178	return new;
179}
180
181/**
182 * compute_perms - convert dfa compressed perms to internal perms
183 * @dfa: dfa to compute perms for   (NOT NULL)
184 * @state: state in dfa
185 * @cond:  conditions to consider  (NOT NULL)
186 *
187 * TODO: convert from dfa + state to permission entry, do computation conversion
188 *       at load time.
189 *
190 * Returns: computed permission set
191 */
192static struct file_perms compute_perms(struct aa_dfa *dfa, unsigned int state,
193				       struct path_cond *cond)
194{
195	struct file_perms perms;
196
197	perms.kill = 0;
198
199	if (current_fsuid() == cond->uid) {
200		perms.allow = map_old_perms(dfa_user_allow(dfa, state));
201		perms.audit = map_old_perms(dfa_user_audit(dfa, state));
202		perms.quiet = map_old_perms(dfa_user_quiet(dfa, state));
203		perms.xindex = dfa_user_xindex(dfa, state);
204	} else {
205		perms.allow = map_old_perms(dfa_other_allow(dfa, state));
206		perms.audit = map_old_perms(dfa_other_audit(dfa, state));
207		perms.quiet = map_old_perms(dfa_other_quiet(dfa, state));
208		perms.xindex = dfa_other_xindex(dfa, state);
209	}
210
211	/* change_profile wasn't determined by ownership in old mapping */
212	if (ACCEPT_TABLE(dfa)[state] & 0x80000000)
213		perms.allow |= AA_MAY_CHANGE_PROFILE;
214
215	return perms;
216}
217
218/**
219 * aa_str_perms - find permission that match @name
220 * @dfa: to match against  (MAYBE NULL)
221 * @state: state to start matching in
222 * @name: string to match against dfa  (NOT NULL)
223 * @cond: conditions to consider for permission set computation  (NOT NULL)
224 * @perms: Returns - the permissions found when matching @name
225 *
226 * Returns: the final state in @dfa when beginning @start and walking @name
227 */
228unsigned int aa_str_perms(struct aa_dfa *dfa, unsigned int start,
229			  const char *name, struct path_cond *cond,
230			  struct file_perms *perms)
231{
232	unsigned int state;
233	if (!dfa) {
234		*perms = nullperms;
235		return DFA_NOMATCH;
236	}
237
238	state = aa_dfa_match(dfa, start, name);
239	*perms = compute_perms(dfa, state, cond);
240
241	return state;
242}
243
244/**
245 * is_deleted - test if a file has been completely unlinked
246 * @dentry: dentry of file to test for deletion  (NOT NULL)
247 *
248 * Returns: %1 if deleted else %0
249 */
250static inline bool is_deleted(struct dentry *dentry)
251{
252	if (d_unlinked(dentry) && dentry->d_inode->i_nlink == 0)
253		return 1;
254	return 0;
255}
256
257/**
258 * aa_path_perm - do permissions check & audit for @path
259 * @op: operation being checked
260 * @profile: profile being enforced  (NOT NULL)
261 * @path: path to check permissions of  (NOT NULL)
262 * @flags: any additional path flags beyond what the profile specifies
263 * @request: requested permissions
264 * @cond: conditional info for this request  (NOT NULL)
265 *
266 * Returns: %0 else error if access denied or other error
267 */
268int aa_path_perm(int op, struct aa_profile *profile, struct path *path,
269		 int flags, u32 request, struct path_cond *cond)
270{
271	char *buffer = NULL;
272	struct file_perms perms = {};
273	const char *name, *info = NULL;
274	int error;
275
276	flags |= profile->path_flags | (S_ISDIR(cond->mode) ? PATH_IS_DIR : 0);
277	error = aa_get_name(path, flags, &buffer, &name);
278	if (error) {
279		if (error == -ENOENT && is_deleted(path->dentry)) {
280			/* Access to open files that are deleted are
281			 * give a pass (implicit delegation)
282			 */
283			error = 0;
284			perms.allow = request;
285		} else if (error == -ENOENT)
286			info = "Failed name lookup - deleted entry";
287		else if (error == -ESTALE)
288			info = "Failed name lookup - disconnected path";
289		else if (error == -ENAMETOOLONG)
290			info = "Failed name lookup - name too long";
291		else
292			info = "Failed name lookup";
293	} else {
294		aa_str_perms(profile->file.dfa, profile->file.start, name, cond,
295			     &perms);
296		if (request & ~perms.allow)
297			error = -EACCES;
298	}
299	error = aa_audit_file(profile, &perms, GFP_KERNEL, op, request, name,
300			      NULL, cond->uid, info, error);
301	kfree(buffer);
302
303	return error;
304}
305
306/**
307 * xindex_is_subset - helper for aa_path_link
308 * @link: link permission set
309 * @target: target permission set
310 *
311 * test target x permissions are equal OR a subset of link x permissions
312 * this is done as part of the subset test, where a hardlink must have
313 * a subset of permissions that the target has.
314 *
315 * Returns: %1 if subset else %0
316 */
317static inline bool xindex_is_subset(u32 link, u32 target)
318{
319	if (((link & ~AA_X_UNSAFE) != (target & ~AA_X_UNSAFE)) ||
320	    ((link & AA_X_UNSAFE) && !(target & AA_X_UNSAFE)))
321		return 0;
322
323	return 1;
324}
325
326/**
327 * aa_path_link - Handle hard link permission check
328 * @profile: the profile being enforced  (NOT NULL)
329 * @old_dentry: the target dentry  (NOT NULL)
330 * @new_dir: directory the new link will be created in  (NOT NULL)
331 * @new_dentry: the link being created  (NOT NULL)
332 *
333 * Handle the permission test for a link & target pair.  Permission
334 * is encoded as a pair where the link permission is determined
335 * first, and if allowed, the target is tested.  The target test
336 * is done from the point of the link match (not start of DFA)
337 * making the target permission dependent on the link permission match.
338 *
339 * The subset test if required forces that permissions granted
340 * on link are a subset of the permission granted to target.
341 *
342 * Returns: %0 if allowed else error
343 */
344int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry,
345		 struct path *new_dir, struct dentry *new_dentry)
346{
347	struct path link = { new_dir->mnt, new_dentry };
348	struct path target = { new_dir->mnt, old_dentry };
349	struct path_cond cond = {
350		old_dentry->d_inode->i_uid,
351		old_dentry->d_inode->i_mode
352	};
353	char *buffer = NULL, *buffer2 = NULL;
354	const char *lname, *tname = NULL, *info = NULL;
355	struct file_perms lperms, perms;
356	u32 request = AA_MAY_LINK;
357	unsigned int state;
358	int error;
359
360	lperms = nullperms;
361
362	/* buffer freed below, lname is pointer in buffer */
363	error = aa_get_name(&link, profile->path_flags, &buffer, &lname);
364	if (error)
365		goto audit;
366
367	/* buffer2 freed below, tname is pointer in buffer2 */
368	error = aa_get_name(&target, profile->path_flags, &buffer2, &tname);
369	if (error)
370		goto audit;
371
372	error = -EACCES;
373	/* aa_str_perms - handles the case of the dfa being NULL */
374	state = aa_str_perms(profile->file.dfa, profile->file.start, lname,
375			     &cond, &lperms);
376
377	if (!(lperms.allow & AA_MAY_LINK))
378		goto audit;
379
380	/* test to see if target can be paired with link */
381	state = aa_dfa_null_transition(profile->file.dfa, state);
382	aa_str_perms(profile->file.dfa, state, tname, &cond, &perms);
383
384	/* force audit/quiet masks for link are stored in the second entry
385	 * in the link pair.
386	 */
387	lperms.audit = perms.audit;
388	lperms.quiet = perms.quiet;
389	lperms.kill = perms.kill;
390
391	if (!(perms.allow & AA_MAY_LINK)) {
392		info = "target restricted";
393		goto audit;
394	}
395
396	/* done if link subset test is not required */
397	if (!(perms.allow & AA_LINK_SUBSET))
398		goto done_tests;
399
400	/* Do link perm subset test requiring allowed permission on link are a
401	 * subset of the allowed permissions on target.
402	 */
403	aa_str_perms(profile->file.dfa, profile->file.start, tname, &cond,
404		     &perms);
405
406	/* AA_MAY_LINK is not considered in the subset test */
407	request = lperms.allow & ~AA_MAY_LINK;
408	lperms.allow &= perms.allow | AA_MAY_LINK;
409
410	request |= AA_AUDIT_FILE_MASK & (lperms.allow & ~perms.allow);
411	if (request & ~lperms.allow) {
412		goto audit;
413	} else if ((lperms.allow & MAY_EXEC) &&
414		   !xindex_is_subset(lperms.xindex, perms.xindex)) {
415		lperms.allow &= ~MAY_EXEC;
416		request |= MAY_EXEC;
417		info = "link not subset of target";
418		goto audit;
419	}
420
421done_tests:
422	error = 0;
423
424audit:
425	error = aa_audit_file(profile, &lperms, GFP_KERNEL, OP_LINK, request,
426			      lname, tname, cond.uid, info, error);
427	kfree(buffer);
428	kfree(buffer2);
429
430	return error;
431}
432
433/**
434 * aa_file_perm - do permission revalidation check & audit for @file
435 * @op: operation being checked
436 * @profile: profile being enforced   (NOT NULL)
437 * @file: file to revalidate access permissions on  (NOT NULL)
438 * @request: requested permissions
439 *
440 * Returns: %0 if access allowed else error
441 */
442int aa_file_perm(int op, struct aa_profile *profile, struct file *file,
443		 u32 request)
444{
445	struct path_cond cond = {
446		.uid = file->f_path.dentry->d_inode->i_uid,
447		.mode = file->f_path.dentry->d_inode->i_mode
448	};
449
450	return aa_path_perm(op, profile, &file->f_path, PATH_DELEGATE_DELETED,
451			    request, &cond);
452}
453