xref: /OK3568_Linux_fs/kernel/security/apparmor/mount.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * AppArmor security module
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * This file contains AppArmor mediation of files
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Copyright (C) 1998-2008 Novell/SUSE
8*4882a593Smuzhiyun  * Copyright 2009-2017 Canonical Ltd.
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/fs.h>
12*4882a593Smuzhiyun #include <linux/mount.h>
13*4882a593Smuzhiyun #include <linux/namei.h>
14*4882a593Smuzhiyun #include <uapi/linux/mount.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include "include/apparmor.h"
17*4882a593Smuzhiyun #include "include/audit.h"
18*4882a593Smuzhiyun #include "include/cred.h"
19*4882a593Smuzhiyun #include "include/domain.h"
20*4882a593Smuzhiyun #include "include/file.h"
21*4882a593Smuzhiyun #include "include/match.h"
22*4882a593Smuzhiyun #include "include/mount.h"
23*4882a593Smuzhiyun #include "include/path.h"
24*4882a593Smuzhiyun #include "include/policy.h"
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun 
audit_mnt_flags(struct audit_buffer * ab,unsigned long flags)27*4882a593Smuzhiyun static void audit_mnt_flags(struct audit_buffer *ab, unsigned long flags)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun 	if (flags & MS_RDONLY)
30*4882a593Smuzhiyun 		audit_log_format(ab, "ro");
31*4882a593Smuzhiyun 	else
32*4882a593Smuzhiyun 		audit_log_format(ab, "rw");
33*4882a593Smuzhiyun 	if (flags & MS_NOSUID)
34*4882a593Smuzhiyun 		audit_log_format(ab, ", nosuid");
35*4882a593Smuzhiyun 	if (flags & MS_NODEV)
36*4882a593Smuzhiyun 		audit_log_format(ab, ", nodev");
37*4882a593Smuzhiyun 	if (flags & MS_NOEXEC)
38*4882a593Smuzhiyun 		audit_log_format(ab, ", noexec");
39*4882a593Smuzhiyun 	if (flags & MS_SYNCHRONOUS)
40*4882a593Smuzhiyun 		audit_log_format(ab, ", sync");
41*4882a593Smuzhiyun 	if (flags & MS_REMOUNT)
42*4882a593Smuzhiyun 		audit_log_format(ab, ", remount");
43*4882a593Smuzhiyun 	if (flags & MS_MANDLOCK)
44*4882a593Smuzhiyun 		audit_log_format(ab, ", mand");
45*4882a593Smuzhiyun 	if (flags & MS_DIRSYNC)
46*4882a593Smuzhiyun 		audit_log_format(ab, ", dirsync");
47*4882a593Smuzhiyun 	if (flags & MS_NOATIME)
48*4882a593Smuzhiyun 		audit_log_format(ab, ", noatime");
49*4882a593Smuzhiyun 	if (flags & MS_NODIRATIME)
50*4882a593Smuzhiyun 		audit_log_format(ab, ", nodiratime");
51*4882a593Smuzhiyun 	if (flags & MS_BIND)
52*4882a593Smuzhiyun 		audit_log_format(ab, flags & MS_REC ? ", rbind" : ", bind");
53*4882a593Smuzhiyun 	if (flags & MS_MOVE)
54*4882a593Smuzhiyun 		audit_log_format(ab, ", move");
55*4882a593Smuzhiyun 	if (flags & MS_SILENT)
56*4882a593Smuzhiyun 		audit_log_format(ab, ", silent");
57*4882a593Smuzhiyun 	if (flags & MS_POSIXACL)
58*4882a593Smuzhiyun 		audit_log_format(ab, ", acl");
59*4882a593Smuzhiyun 	if (flags & MS_UNBINDABLE)
60*4882a593Smuzhiyun 		audit_log_format(ab, flags & MS_REC ? ", runbindable" :
61*4882a593Smuzhiyun 				 ", unbindable");
62*4882a593Smuzhiyun 	if (flags & MS_PRIVATE)
63*4882a593Smuzhiyun 		audit_log_format(ab, flags & MS_REC ? ", rprivate" :
64*4882a593Smuzhiyun 				 ", private");
65*4882a593Smuzhiyun 	if (flags & MS_SLAVE)
66*4882a593Smuzhiyun 		audit_log_format(ab, flags & MS_REC ? ", rslave" :
67*4882a593Smuzhiyun 				 ", slave");
68*4882a593Smuzhiyun 	if (flags & MS_SHARED)
69*4882a593Smuzhiyun 		audit_log_format(ab, flags & MS_REC ? ", rshared" :
70*4882a593Smuzhiyun 				 ", shared");
71*4882a593Smuzhiyun 	if (flags & MS_RELATIME)
72*4882a593Smuzhiyun 		audit_log_format(ab, ", relatime");
73*4882a593Smuzhiyun 	if (flags & MS_I_VERSION)
74*4882a593Smuzhiyun 		audit_log_format(ab, ", iversion");
75*4882a593Smuzhiyun 	if (flags & MS_STRICTATIME)
76*4882a593Smuzhiyun 		audit_log_format(ab, ", strictatime");
77*4882a593Smuzhiyun 	if (flags & MS_NOUSER)
78*4882a593Smuzhiyun 		audit_log_format(ab, ", nouser");
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun /**
82*4882a593Smuzhiyun  * audit_cb - call back for mount specific audit fields
83*4882a593Smuzhiyun  * @ab: audit_buffer  (NOT NULL)
84*4882a593Smuzhiyun  * @va: audit struct to audit values of  (NOT NULL)
85*4882a593Smuzhiyun  */
audit_cb(struct audit_buffer * ab,void * va)86*4882a593Smuzhiyun static void audit_cb(struct audit_buffer *ab, void *va)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	struct common_audit_data *sa = va;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	if (aad(sa)->mnt.type) {
91*4882a593Smuzhiyun 		audit_log_format(ab, " fstype=");
92*4882a593Smuzhiyun 		audit_log_untrustedstring(ab, aad(sa)->mnt.type);
93*4882a593Smuzhiyun 	}
94*4882a593Smuzhiyun 	if (aad(sa)->mnt.src_name) {
95*4882a593Smuzhiyun 		audit_log_format(ab, " srcname=");
96*4882a593Smuzhiyun 		audit_log_untrustedstring(ab, aad(sa)->mnt.src_name);
97*4882a593Smuzhiyun 	}
98*4882a593Smuzhiyun 	if (aad(sa)->mnt.trans) {
99*4882a593Smuzhiyun 		audit_log_format(ab, " trans=");
100*4882a593Smuzhiyun 		audit_log_untrustedstring(ab, aad(sa)->mnt.trans);
101*4882a593Smuzhiyun 	}
102*4882a593Smuzhiyun 	if (aad(sa)->mnt.flags) {
103*4882a593Smuzhiyun 		audit_log_format(ab, " flags=\"");
104*4882a593Smuzhiyun 		audit_mnt_flags(ab, aad(sa)->mnt.flags);
105*4882a593Smuzhiyun 		audit_log_format(ab, "\"");
106*4882a593Smuzhiyun 	}
107*4882a593Smuzhiyun 	if (aad(sa)->mnt.data) {
108*4882a593Smuzhiyun 		audit_log_format(ab, " options=");
109*4882a593Smuzhiyun 		audit_log_untrustedstring(ab, aad(sa)->mnt.data);
110*4882a593Smuzhiyun 	}
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun /**
114*4882a593Smuzhiyun  * audit_mount - handle the auditing of mount operations
115*4882a593Smuzhiyun  * @profile: the profile being enforced  (NOT NULL)
116*4882a593Smuzhiyun  * @op: operation being mediated (NOT NULL)
117*4882a593Smuzhiyun  * @name: name of object being mediated (MAYBE NULL)
118*4882a593Smuzhiyun  * @src_name: src_name of object being mediated (MAYBE_NULL)
119*4882a593Smuzhiyun  * @type: type of filesystem (MAYBE_NULL)
120*4882a593Smuzhiyun  * @trans: name of trans (MAYBE NULL)
121*4882a593Smuzhiyun  * @flags: filesystem independent mount flags
122*4882a593Smuzhiyun  * @data: filesystem mount flags
123*4882a593Smuzhiyun  * @request: permissions requested
124*4882a593Smuzhiyun  * @perms: the permissions computed for the request (NOT NULL)
125*4882a593Smuzhiyun  * @info: extra information message (MAYBE NULL)
126*4882a593Smuzhiyun  * @error: 0 if operation allowed else failure error code
127*4882a593Smuzhiyun  *
128*4882a593Smuzhiyun  * Returns: %0 or error on failure
129*4882a593Smuzhiyun  */
audit_mount(struct aa_profile * profile,const char * op,const char * name,const char * src_name,const char * type,const char * trans,unsigned long flags,const void * data,u32 request,struct aa_perms * perms,const char * info,int error)130*4882a593Smuzhiyun static int audit_mount(struct aa_profile *profile, const char *op,
131*4882a593Smuzhiyun 		       const char *name, const char *src_name,
132*4882a593Smuzhiyun 		       const char *type, const char *trans,
133*4882a593Smuzhiyun 		       unsigned long flags, const void *data, u32 request,
134*4882a593Smuzhiyun 		       struct aa_perms *perms, const char *info, int error)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun 	int audit_type = AUDIT_APPARMOR_AUTO;
137*4882a593Smuzhiyun 	DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, op);
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	if (likely(!error)) {
140*4882a593Smuzhiyun 		u32 mask = perms->audit;
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 		if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
143*4882a593Smuzhiyun 			mask = 0xffff;
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 		/* mask off perms that are not being force audited */
146*4882a593Smuzhiyun 		request &= mask;
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 		if (likely(!request))
149*4882a593Smuzhiyun 			return 0;
150*4882a593Smuzhiyun 		audit_type = AUDIT_APPARMOR_AUDIT;
151*4882a593Smuzhiyun 	} else {
152*4882a593Smuzhiyun 		/* only report permissions that were denied */
153*4882a593Smuzhiyun 		request = request & ~perms->allow;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 		if (request & perms->kill)
156*4882a593Smuzhiyun 			audit_type = AUDIT_APPARMOR_KILL;
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 		/* quiet known rejects, assumes quiet and kill do not overlap */
159*4882a593Smuzhiyun 		if ((request & perms->quiet) &&
160*4882a593Smuzhiyun 		    AUDIT_MODE(profile) != AUDIT_NOQUIET &&
161*4882a593Smuzhiyun 		    AUDIT_MODE(profile) != AUDIT_ALL)
162*4882a593Smuzhiyun 			request &= ~perms->quiet;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 		if (!request)
165*4882a593Smuzhiyun 			return error;
166*4882a593Smuzhiyun 	}
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	aad(&sa)->name = name;
169*4882a593Smuzhiyun 	aad(&sa)->mnt.src_name = src_name;
170*4882a593Smuzhiyun 	aad(&sa)->mnt.type = type;
171*4882a593Smuzhiyun 	aad(&sa)->mnt.trans = trans;
172*4882a593Smuzhiyun 	aad(&sa)->mnt.flags = flags;
173*4882a593Smuzhiyun 	if (data && (perms->audit & AA_AUDIT_DATA))
174*4882a593Smuzhiyun 		aad(&sa)->mnt.data = data;
175*4882a593Smuzhiyun 	aad(&sa)->info = info;
176*4882a593Smuzhiyun 	aad(&sa)->error = error;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	return aa_audit(audit_type, profile, &sa, audit_cb);
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun /**
182*4882a593Smuzhiyun  * match_mnt_flags - Do an ordered match on mount flags
183*4882a593Smuzhiyun  * @dfa: dfa to match against
184*4882a593Smuzhiyun  * @state: state to start in
185*4882a593Smuzhiyun  * @flags: mount flags to match against
186*4882a593Smuzhiyun  *
187*4882a593Smuzhiyun  * Mount flags are encoded as an ordered match. This is done instead of
188*4882a593Smuzhiyun  * checking against a simple bitmask, to allow for logical operations
189*4882a593Smuzhiyun  * on the flags.
190*4882a593Smuzhiyun  *
191*4882a593Smuzhiyun  * Returns: next state after flags match
192*4882a593Smuzhiyun  */
match_mnt_flags(struct aa_dfa * dfa,unsigned int state,unsigned long flags)193*4882a593Smuzhiyun static unsigned int match_mnt_flags(struct aa_dfa *dfa, unsigned int state,
194*4882a593Smuzhiyun 				    unsigned long flags)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun 	unsigned int i;
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	for (i = 0; i <= 31 ; ++i) {
199*4882a593Smuzhiyun 		if ((1 << i) & flags)
200*4882a593Smuzhiyun 			state = aa_dfa_next(dfa, state, i + 1);
201*4882a593Smuzhiyun 	}
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	return state;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun /**
207*4882a593Smuzhiyun  * compute_mnt_perms - compute mount permission associated with @state
208*4882a593Smuzhiyun  * @dfa: dfa to match against (NOT NULL)
209*4882a593Smuzhiyun  * @state: state match finished in
210*4882a593Smuzhiyun  *
211*4882a593Smuzhiyun  * Returns: mount permissions
212*4882a593Smuzhiyun  */
compute_mnt_perms(struct aa_dfa * dfa,unsigned int state)213*4882a593Smuzhiyun static struct aa_perms compute_mnt_perms(struct aa_dfa *dfa,
214*4882a593Smuzhiyun 					   unsigned int state)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun 	struct aa_perms perms = {
217*4882a593Smuzhiyun 		.allow = dfa_user_allow(dfa, state),
218*4882a593Smuzhiyun 		.audit = dfa_user_audit(dfa, state),
219*4882a593Smuzhiyun 		.quiet = dfa_user_quiet(dfa, state),
220*4882a593Smuzhiyun 		.xindex = dfa_user_xindex(dfa, state),
221*4882a593Smuzhiyun 	};
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	return perms;
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun static const char * const mnt_info_table[] = {
227*4882a593Smuzhiyun 	"match succeeded",
228*4882a593Smuzhiyun 	"failed mntpnt match",
229*4882a593Smuzhiyun 	"failed srcname match",
230*4882a593Smuzhiyun 	"failed type match",
231*4882a593Smuzhiyun 	"failed flags match",
232*4882a593Smuzhiyun 	"failed data match",
233*4882a593Smuzhiyun 	"failed perms check"
234*4882a593Smuzhiyun };
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun /*
237*4882a593Smuzhiyun  * Returns 0 on success else element that match failed in, this is the
238*4882a593Smuzhiyun  * index into the mnt_info_table above
239*4882a593Smuzhiyun  */
do_match_mnt(struct aa_dfa * dfa,unsigned int start,const char * mntpnt,const char * devname,const char * type,unsigned long flags,void * data,bool binary,struct aa_perms * perms)240*4882a593Smuzhiyun static int do_match_mnt(struct aa_dfa *dfa, unsigned int start,
241*4882a593Smuzhiyun 			const char *mntpnt, const char *devname,
242*4882a593Smuzhiyun 			const char *type, unsigned long flags,
243*4882a593Smuzhiyun 			void *data, bool binary, struct aa_perms *perms)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun 	unsigned int state;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	AA_BUG(!dfa);
248*4882a593Smuzhiyun 	AA_BUG(!perms);
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	state = aa_dfa_match(dfa, start, mntpnt);
251*4882a593Smuzhiyun 	state = aa_dfa_null_transition(dfa, state);
252*4882a593Smuzhiyun 	if (!state)
253*4882a593Smuzhiyun 		return 1;
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	if (devname)
256*4882a593Smuzhiyun 		state = aa_dfa_match(dfa, state, devname);
257*4882a593Smuzhiyun 	state = aa_dfa_null_transition(dfa, state);
258*4882a593Smuzhiyun 	if (!state)
259*4882a593Smuzhiyun 		return 2;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	if (type)
262*4882a593Smuzhiyun 		state = aa_dfa_match(dfa, state, type);
263*4882a593Smuzhiyun 	state = aa_dfa_null_transition(dfa, state);
264*4882a593Smuzhiyun 	if (!state)
265*4882a593Smuzhiyun 		return 3;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	state = match_mnt_flags(dfa, state, flags);
268*4882a593Smuzhiyun 	if (!state)
269*4882a593Smuzhiyun 		return 4;
270*4882a593Smuzhiyun 	*perms = compute_mnt_perms(dfa, state);
271*4882a593Smuzhiyun 	if (perms->allow & AA_MAY_MOUNT)
272*4882a593Smuzhiyun 		return 0;
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	/* only match data if not binary and the DFA flags data is expected */
275*4882a593Smuzhiyun 	if (data && !binary && (perms->allow & AA_MNT_CONT_MATCH)) {
276*4882a593Smuzhiyun 		state = aa_dfa_null_transition(dfa, state);
277*4882a593Smuzhiyun 		if (!state)
278*4882a593Smuzhiyun 			return 4;
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 		state = aa_dfa_match(dfa, state, data);
281*4882a593Smuzhiyun 		if (!state)
282*4882a593Smuzhiyun 			return 5;
283*4882a593Smuzhiyun 		*perms = compute_mnt_perms(dfa, state);
284*4882a593Smuzhiyun 		if (perms->allow & AA_MAY_MOUNT)
285*4882a593Smuzhiyun 			return 0;
286*4882a593Smuzhiyun 	}
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	/* failed at perms check, don't confuse with flags match */
289*4882a593Smuzhiyun 	return 6;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 
path_flags(struct aa_profile * profile,const struct path * path)293*4882a593Smuzhiyun static int path_flags(struct aa_profile *profile, const struct path *path)
294*4882a593Smuzhiyun {
295*4882a593Smuzhiyun 	AA_BUG(!profile);
296*4882a593Smuzhiyun 	AA_BUG(!path);
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	return profile->path_flags |
299*4882a593Smuzhiyun 		(S_ISDIR(path->dentry->d_inode->i_mode) ? PATH_IS_DIR : 0);
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun /**
303*4882a593Smuzhiyun  * match_mnt_path_str - handle path matching for mount
304*4882a593Smuzhiyun  * @profile: the confining profile
305*4882a593Smuzhiyun  * @mntpath: for the mntpnt (NOT NULL)
306*4882a593Smuzhiyun  * @buffer: buffer to be used to lookup mntpath
307*4882a593Smuzhiyun  * @devnme: string for the devname/src_name (MAY BE NULL OR ERRPTR)
308*4882a593Smuzhiyun  * @type: string for the dev type (MAYBE NULL)
309*4882a593Smuzhiyun  * @flags: mount flags to match
310*4882a593Smuzhiyun  * @data: fs mount data (MAYBE NULL)
311*4882a593Smuzhiyun  * @binary: whether @data is binary
312*4882a593Smuzhiyun  * @devinfo: error str if (IS_ERR(@devname))
313*4882a593Smuzhiyun  *
314*4882a593Smuzhiyun  * Returns: 0 on success else error
315*4882a593Smuzhiyun  */
match_mnt_path_str(struct aa_profile * profile,const struct path * mntpath,char * buffer,const char * devname,const char * type,unsigned long flags,void * data,bool binary,const char * devinfo)316*4882a593Smuzhiyun static int match_mnt_path_str(struct aa_profile *profile,
317*4882a593Smuzhiyun 			      const struct path *mntpath, char *buffer,
318*4882a593Smuzhiyun 			      const char *devname, const char *type,
319*4882a593Smuzhiyun 			      unsigned long flags, void *data, bool binary,
320*4882a593Smuzhiyun 			      const char *devinfo)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun 	struct aa_perms perms = { };
323*4882a593Smuzhiyun 	const char *mntpnt = NULL, *info = NULL;
324*4882a593Smuzhiyun 	int pos, error;
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	AA_BUG(!profile);
327*4882a593Smuzhiyun 	AA_BUG(!mntpath);
328*4882a593Smuzhiyun 	AA_BUG(!buffer);
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	if (!PROFILE_MEDIATES(profile, AA_CLASS_MOUNT))
331*4882a593Smuzhiyun 		return 0;
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	error = aa_path_name(mntpath, path_flags(profile, mntpath), buffer,
334*4882a593Smuzhiyun 			     &mntpnt, &info, profile->disconnected);
335*4882a593Smuzhiyun 	if (error)
336*4882a593Smuzhiyun 		goto audit;
337*4882a593Smuzhiyun 	if (IS_ERR(devname)) {
338*4882a593Smuzhiyun 		error = PTR_ERR(devname);
339*4882a593Smuzhiyun 		devname = NULL;
340*4882a593Smuzhiyun 		info = devinfo;
341*4882a593Smuzhiyun 		goto audit;
342*4882a593Smuzhiyun 	}
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	error = -EACCES;
345*4882a593Smuzhiyun 	pos = do_match_mnt(profile->policy.dfa,
346*4882a593Smuzhiyun 			   profile->policy.start[AA_CLASS_MOUNT],
347*4882a593Smuzhiyun 			   mntpnt, devname, type, flags, data, binary, &perms);
348*4882a593Smuzhiyun 	if (pos) {
349*4882a593Smuzhiyun 		info = mnt_info_table[pos];
350*4882a593Smuzhiyun 		goto audit;
351*4882a593Smuzhiyun 	}
352*4882a593Smuzhiyun 	error = 0;
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun audit:
355*4882a593Smuzhiyun 	return audit_mount(profile, OP_MOUNT, mntpnt, devname, type, NULL,
356*4882a593Smuzhiyun 			   flags, data, AA_MAY_MOUNT, &perms, info, error);
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun /**
360*4882a593Smuzhiyun  * match_mnt - handle path matching for mount
361*4882a593Smuzhiyun  * @profile: the confining profile
362*4882a593Smuzhiyun  * @mntpath: for the mntpnt (NOT NULL)
363*4882a593Smuzhiyun  * @buffer: buffer to be used to lookup mntpath
364*4882a593Smuzhiyun  * @devpath: path devname/src_name (MAYBE NULL)
365*4882a593Smuzhiyun  * @devbuffer: buffer to be used to lookup devname/src_name
366*4882a593Smuzhiyun  * @type: string for the dev type (MAYBE NULL)
367*4882a593Smuzhiyun  * @flags: mount flags to match
368*4882a593Smuzhiyun  * @data: fs mount data (MAYBE NULL)
369*4882a593Smuzhiyun  * @binary: whether @data is binary
370*4882a593Smuzhiyun  *
371*4882a593Smuzhiyun  * Returns: 0 on success else error
372*4882a593Smuzhiyun  */
match_mnt(struct aa_profile * profile,const struct path * path,char * buffer,struct path * devpath,char * devbuffer,const char * type,unsigned long flags,void * data,bool binary)373*4882a593Smuzhiyun static int match_mnt(struct aa_profile *profile, const struct path *path,
374*4882a593Smuzhiyun 		     char *buffer, struct path *devpath, char *devbuffer,
375*4882a593Smuzhiyun 		     const char *type, unsigned long flags, void *data,
376*4882a593Smuzhiyun 		     bool binary)
377*4882a593Smuzhiyun {
378*4882a593Smuzhiyun 	const char *devname = NULL, *info = NULL;
379*4882a593Smuzhiyun 	int error = -EACCES;
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	AA_BUG(!profile);
382*4882a593Smuzhiyun 	AA_BUG(devpath && !devbuffer);
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	if (!PROFILE_MEDIATES(profile, AA_CLASS_MOUNT))
385*4882a593Smuzhiyun 		return 0;
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	if (devpath) {
388*4882a593Smuzhiyun 		error = aa_path_name(devpath, path_flags(profile, devpath),
389*4882a593Smuzhiyun 				     devbuffer, &devname, &info,
390*4882a593Smuzhiyun 				     profile->disconnected);
391*4882a593Smuzhiyun 		if (error)
392*4882a593Smuzhiyun 			devname = ERR_PTR(error);
393*4882a593Smuzhiyun 	}
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	return match_mnt_path_str(profile, path, buffer, devname, type, flags,
396*4882a593Smuzhiyun 				  data, binary, info);
397*4882a593Smuzhiyun }
398*4882a593Smuzhiyun 
aa_remount(struct aa_label * label,const struct path * path,unsigned long flags,void * data)399*4882a593Smuzhiyun int aa_remount(struct aa_label *label, const struct path *path,
400*4882a593Smuzhiyun 	       unsigned long flags, void *data)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun 	struct aa_profile *profile;
403*4882a593Smuzhiyun 	char *buffer = NULL;
404*4882a593Smuzhiyun 	bool binary;
405*4882a593Smuzhiyun 	int error;
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	AA_BUG(!label);
408*4882a593Smuzhiyun 	AA_BUG(!path);
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA;
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	buffer = aa_get_buffer(false);
413*4882a593Smuzhiyun 	if (!buffer)
414*4882a593Smuzhiyun 		return -ENOMEM;
415*4882a593Smuzhiyun 	error = fn_for_each_confined(label, profile,
416*4882a593Smuzhiyun 			match_mnt(profile, path, buffer, NULL, NULL, NULL,
417*4882a593Smuzhiyun 				  flags, data, binary));
418*4882a593Smuzhiyun 	aa_put_buffer(buffer);
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	return error;
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun 
aa_bind_mount(struct aa_label * label,const struct path * path,const char * dev_name,unsigned long flags)423*4882a593Smuzhiyun int aa_bind_mount(struct aa_label *label, const struct path *path,
424*4882a593Smuzhiyun 		  const char *dev_name, unsigned long flags)
425*4882a593Smuzhiyun {
426*4882a593Smuzhiyun 	struct aa_profile *profile;
427*4882a593Smuzhiyun 	char *buffer = NULL, *old_buffer = NULL;
428*4882a593Smuzhiyun 	struct path old_path;
429*4882a593Smuzhiyun 	int error;
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	AA_BUG(!label);
432*4882a593Smuzhiyun 	AA_BUG(!path);
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	if (!dev_name || !*dev_name)
435*4882a593Smuzhiyun 		return -EINVAL;
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	flags &= MS_REC | MS_BIND;
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	error = kern_path(dev_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
440*4882a593Smuzhiyun 	if (error)
441*4882a593Smuzhiyun 		return error;
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 	buffer = aa_get_buffer(false);
444*4882a593Smuzhiyun 	old_buffer = aa_get_buffer(false);
445*4882a593Smuzhiyun 	error = -ENOMEM;
446*4882a593Smuzhiyun 	if (!buffer || !old_buffer)
447*4882a593Smuzhiyun 		goto out;
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	error = fn_for_each_confined(label, profile,
450*4882a593Smuzhiyun 			match_mnt(profile, path, buffer, &old_path, old_buffer,
451*4882a593Smuzhiyun 				  NULL, flags, NULL, false));
452*4882a593Smuzhiyun out:
453*4882a593Smuzhiyun 	aa_put_buffer(buffer);
454*4882a593Smuzhiyun 	aa_put_buffer(old_buffer);
455*4882a593Smuzhiyun 	path_put(&old_path);
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	return error;
458*4882a593Smuzhiyun }
459*4882a593Smuzhiyun 
aa_mount_change_type(struct aa_label * label,const struct path * path,unsigned long flags)460*4882a593Smuzhiyun int aa_mount_change_type(struct aa_label *label, const struct path *path,
461*4882a593Smuzhiyun 			 unsigned long flags)
462*4882a593Smuzhiyun {
463*4882a593Smuzhiyun 	struct aa_profile *profile;
464*4882a593Smuzhiyun 	char *buffer = NULL;
465*4882a593Smuzhiyun 	int error;
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	AA_BUG(!label);
468*4882a593Smuzhiyun 	AA_BUG(!path);
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 	/* These are the flags allowed by do_change_type() */
471*4882a593Smuzhiyun 	flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE |
472*4882a593Smuzhiyun 		  MS_UNBINDABLE);
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	buffer = aa_get_buffer(false);
475*4882a593Smuzhiyun 	if (!buffer)
476*4882a593Smuzhiyun 		return -ENOMEM;
477*4882a593Smuzhiyun 	error = fn_for_each_confined(label, profile,
478*4882a593Smuzhiyun 			match_mnt(profile, path, buffer, NULL, NULL, NULL,
479*4882a593Smuzhiyun 				  flags, NULL, false));
480*4882a593Smuzhiyun 	aa_put_buffer(buffer);
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 	return error;
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun 
aa_move_mount(struct aa_label * label,const struct path * path,const char * orig_name)485*4882a593Smuzhiyun int aa_move_mount(struct aa_label *label, const struct path *path,
486*4882a593Smuzhiyun 		  const char *orig_name)
487*4882a593Smuzhiyun {
488*4882a593Smuzhiyun 	struct aa_profile *profile;
489*4882a593Smuzhiyun 	char *buffer = NULL, *old_buffer = NULL;
490*4882a593Smuzhiyun 	struct path old_path;
491*4882a593Smuzhiyun 	int error;
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	AA_BUG(!label);
494*4882a593Smuzhiyun 	AA_BUG(!path);
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	if (!orig_name || !*orig_name)
497*4882a593Smuzhiyun 		return -EINVAL;
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 	error = kern_path(orig_name, LOOKUP_FOLLOW, &old_path);
500*4882a593Smuzhiyun 	if (error)
501*4882a593Smuzhiyun 		return error;
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	buffer = aa_get_buffer(false);
504*4882a593Smuzhiyun 	old_buffer = aa_get_buffer(false);
505*4882a593Smuzhiyun 	error = -ENOMEM;
506*4882a593Smuzhiyun 	if (!buffer || !old_buffer)
507*4882a593Smuzhiyun 		goto out;
508*4882a593Smuzhiyun 	error = fn_for_each_confined(label, profile,
509*4882a593Smuzhiyun 			match_mnt(profile, path, buffer, &old_path, old_buffer,
510*4882a593Smuzhiyun 				  NULL, MS_MOVE, NULL, false));
511*4882a593Smuzhiyun out:
512*4882a593Smuzhiyun 	aa_put_buffer(buffer);
513*4882a593Smuzhiyun 	aa_put_buffer(old_buffer);
514*4882a593Smuzhiyun 	path_put(&old_path);
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	return error;
517*4882a593Smuzhiyun }
518*4882a593Smuzhiyun 
aa_new_mount(struct aa_label * label,const char * dev_name,const struct path * path,const char * type,unsigned long flags,void * data)519*4882a593Smuzhiyun int aa_new_mount(struct aa_label *label, const char *dev_name,
520*4882a593Smuzhiyun 		 const struct path *path, const char *type, unsigned long flags,
521*4882a593Smuzhiyun 		 void *data)
522*4882a593Smuzhiyun {
523*4882a593Smuzhiyun 	struct aa_profile *profile;
524*4882a593Smuzhiyun 	char *buffer = NULL, *dev_buffer = NULL;
525*4882a593Smuzhiyun 	bool binary = true;
526*4882a593Smuzhiyun 	int error;
527*4882a593Smuzhiyun 	int requires_dev = 0;
528*4882a593Smuzhiyun 	struct path tmp_path, *dev_path = NULL;
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	AA_BUG(!label);
531*4882a593Smuzhiyun 	AA_BUG(!path);
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun 	if (type) {
534*4882a593Smuzhiyun 		struct file_system_type *fstype;
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 		fstype = get_fs_type(type);
537*4882a593Smuzhiyun 		if (!fstype)
538*4882a593Smuzhiyun 			return -ENODEV;
539*4882a593Smuzhiyun 		binary = fstype->fs_flags & FS_BINARY_MOUNTDATA;
540*4882a593Smuzhiyun 		requires_dev = fstype->fs_flags & FS_REQUIRES_DEV;
541*4882a593Smuzhiyun 		put_filesystem(fstype);
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 		if (requires_dev) {
544*4882a593Smuzhiyun 			if (!dev_name || !*dev_name)
545*4882a593Smuzhiyun 				return -ENOENT;
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 			error = kern_path(dev_name, LOOKUP_FOLLOW, &tmp_path);
548*4882a593Smuzhiyun 			if (error)
549*4882a593Smuzhiyun 				return error;
550*4882a593Smuzhiyun 			dev_path = &tmp_path;
551*4882a593Smuzhiyun 		}
552*4882a593Smuzhiyun 	}
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	buffer = aa_get_buffer(false);
555*4882a593Smuzhiyun 	if (!buffer) {
556*4882a593Smuzhiyun 		error = -ENOMEM;
557*4882a593Smuzhiyun 		goto out;
558*4882a593Smuzhiyun 	}
559*4882a593Smuzhiyun 	if (dev_path) {
560*4882a593Smuzhiyun 		dev_buffer = aa_get_buffer(false);
561*4882a593Smuzhiyun 		if (!dev_buffer) {
562*4882a593Smuzhiyun 			error = -ENOMEM;
563*4882a593Smuzhiyun 			goto out;
564*4882a593Smuzhiyun 		}
565*4882a593Smuzhiyun 		error = fn_for_each_confined(label, profile,
566*4882a593Smuzhiyun 			match_mnt(profile, path, buffer, dev_path, dev_buffer,
567*4882a593Smuzhiyun 				  type, flags, data, binary));
568*4882a593Smuzhiyun 	} else {
569*4882a593Smuzhiyun 		error = fn_for_each_confined(label, profile,
570*4882a593Smuzhiyun 			match_mnt_path_str(profile, path, buffer, dev_name,
571*4882a593Smuzhiyun 					   type, flags, data, binary, NULL));
572*4882a593Smuzhiyun 	}
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun out:
575*4882a593Smuzhiyun 	aa_put_buffer(buffer);
576*4882a593Smuzhiyun 	aa_put_buffer(dev_buffer);
577*4882a593Smuzhiyun 	if (dev_path)
578*4882a593Smuzhiyun 		path_put(dev_path);
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 	return error;
581*4882a593Smuzhiyun }
582*4882a593Smuzhiyun 
profile_umount(struct aa_profile * profile,struct path * path,char * buffer)583*4882a593Smuzhiyun static int profile_umount(struct aa_profile *profile, struct path *path,
584*4882a593Smuzhiyun 			  char *buffer)
585*4882a593Smuzhiyun {
586*4882a593Smuzhiyun 	struct aa_perms perms = { };
587*4882a593Smuzhiyun 	const char *name = NULL, *info = NULL;
588*4882a593Smuzhiyun 	unsigned int state;
589*4882a593Smuzhiyun 	int error;
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun 	AA_BUG(!profile);
592*4882a593Smuzhiyun 	AA_BUG(!path);
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun 	if (!PROFILE_MEDIATES(profile, AA_CLASS_MOUNT))
595*4882a593Smuzhiyun 		return 0;
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 	error = aa_path_name(path, path_flags(profile, path), buffer, &name,
598*4882a593Smuzhiyun 			     &info, profile->disconnected);
599*4882a593Smuzhiyun 	if (error)
600*4882a593Smuzhiyun 		goto audit;
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	state = aa_dfa_match(profile->policy.dfa,
603*4882a593Smuzhiyun 			     profile->policy.start[AA_CLASS_MOUNT],
604*4882a593Smuzhiyun 			     name);
605*4882a593Smuzhiyun 	perms = compute_mnt_perms(profile->policy.dfa, state);
606*4882a593Smuzhiyun 	if (AA_MAY_UMOUNT & ~perms.allow)
607*4882a593Smuzhiyun 		error = -EACCES;
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun audit:
610*4882a593Smuzhiyun 	return audit_mount(profile, OP_UMOUNT, name, NULL, NULL, NULL, 0, NULL,
611*4882a593Smuzhiyun 			   AA_MAY_UMOUNT, &perms, info, error);
612*4882a593Smuzhiyun }
613*4882a593Smuzhiyun 
aa_umount(struct aa_label * label,struct vfsmount * mnt,int flags)614*4882a593Smuzhiyun int aa_umount(struct aa_label *label, struct vfsmount *mnt, int flags)
615*4882a593Smuzhiyun {
616*4882a593Smuzhiyun 	struct aa_profile *profile;
617*4882a593Smuzhiyun 	char *buffer = NULL;
618*4882a593Smuzhiyun 	int error;
619*4882a593Smuzhiyun 	struct path path = { .mnt = mnt, .dentry = mnt->mnt_root };
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun 	AA_BUG(!label);
622*4882a593Smuzhiyun 	AA_BUG(!mnt);
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun 	buffer = aa_get_buffer(false);
625*4882a593Smuzhiyun 	if (!buffer)
626*4882a593Smuzhiyun 		return -ENOMEM;
627*4882a593Smuzhiyun 
628*4882a593Smuzhiyun 	error = fn_for_each_confined(label, profile,
629*4882a593Smuzhiyun 			profile_umount(profile, &path, buffer));
630*4882a593Smuzhiyun 	aa_put_buffer(buffer);
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun 	return error;
633*4882a593Smuzhiyun }
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun /* helper fn for transition on pivotroot
636*4882a593Smuzhiyun  *
637*4882a593Smuzhiyun  * Returns: label for transition or ERR_PTR. Does not return NULL
638*4882a593Smuzhiyun  */
build_pivotroot(struct aa_profile * profile,const struct path * new_path,char * new_buffer,const struct path * old_path,char * old_buffer)639*4882a593Smuzhiyun static struct aa_label *build_pivotroot(struct aa_profile *profile,
640*4882a593Smuzhiyun 					const struct path *new_path,
641*4882a593Smuzhiyun 					char *new_buffer,
642*4882a593Smuzhiyun 					const struct path *old_path,
643*4882a593Smuzhiyun 					char *old_buffer)
644*4882a593Smuzhiyun {
645*4882a593Smuzhiyun 	const char *old_name, *new_name = NULL, *info = NULL;
646*4882a593Smuzhiyun 	const char *trans_name = NULL;
647*4882a593Smuzhiyun 	struct aa_perms perms = { };
648*4882a593Smuzhiyun 	unsigned int state;
649*4882a593Smuzhiyun 	int error;
650*4882a593Smuzhiyun 
651*4882a593Smuzhiyun 	AA_BUG(!profile);
652*4882a593Smuzhiyun 	AA_BUG(!new_path);
653*4882a593Smuzhiyun 	AA_BUG(!old_path);
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 	if (profile_unconfined(profile) ||
656*4882a593Smuzhiyun 	    !PROFILE_MEDIATES(profile, AA_CLASS_MOUNT))
657*4882a593Smuzhiyun 		return aa_get_newest_label(&profile->label);
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun 	error = aa_path_name(old_path, path_flags(profile, old_path),
660*4882a593Smuzhiyun 			     old_buffer, &old_name, &info,
661*4882a593Smuzhiyun 			     profile->disconnected);
662*4882a593Smuzhiyun 	if (error)
663*4882a593Smuzhiyun 		goto audit;
664*4882a593Smuzhiyun 	error = aa_path_name(new_path, path_flags(profile, new_path),
665*4882a593Smuzhiyun 			     new_buffer, &new_name, &info,
666*4882a593Smuzhiyun 			     profile->disconnected);
667*4882a593Smuzhiyun 	if (error)
668*4882a593Smuzhiyun 		goto audit;
669*4882a593Smuzhiyun 
670*4882a593Smuzhiyun 	error = -EACCES;
671*4882a593Smuzhiyun 	state = aa_dfa_match(profile->policy.dfa,
672*4882a593Smuzhiyun 			     profile->policy.start[AA_CLASS_MOUNT],
673*4882a593Smuzhiyun 			     new_name);
674*4882a593Smuzhiyun 	state = aa_dfa_null_transition(profile->policy.dfa, state);
675*4882a593Smuzhiyun 	state = aa_dfa_match(profile->policy.dfa, state, old_name);
676*4882a593Smuzhiyun 	perms = compute_mnt_perms(profile->policy.dfa, state);
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 	if (AA_MAY_PIVOTROOT & perms.allow)
679*4882a593Smuzhiyun 		error = 0;
680*4882a593Smuzhiyun 
681*4882a593Smuzhiyun audit:
682*4882a593Smuzhiyun 	error = audit_mount(profile, OP_PIVOTROOT, new_name, old_name,
683*4882a593Smuzhiyun 			    NULL, trans_name, 0, NULL, AA_MAY_PIVOTROOT,
684*4882a593Smuzhiyun 			    &perms, info, error);
685*4882a593Smuzhiyun 	if (error)
686*4882a593Smuzhiyun 		return ERR_PTR(error);
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun 	return aa_get_newest_label(&profile->label);
689*4882a593Smuzhiyun }
690*4882a593Smuzhiyun 
aa_pivotroot(struct aa_label * label,const struct path * old_path,const struct path * new_path)691*4882a593Smuzhiyun int aa_pivotroot(struct aa_label *label, const struct path *old_path,
692*4882a593Smuzhiyun 		 const struct path *new_path)
693*4882a593Smuzhiyun {
694*4882a593Smuzhiyun 	struct aa_profile *profile;
695*4882a593Smuzhiyun 	struct aa_label *target = NULL;
696*4882a593Smuzhiyun 	char *old_buffer = NULL, *new_buffer = NULL, *info = NULL;
697*4882a593Smuzhiyun 	int error;
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 	AA_BUG(!label);
700*4882a593Smuzhiyun 	AA_BUG(!old_path);
701*4882a593Smuzhiyun 	AA_BUG(!new_path);
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 	old_buffer = aa_get_buffer(false);
704*4882a593Smuzhiyun 	new_buffer = aa_get_buffer(false);
705*4882a593Smuzhiyun 	error = -ENOMEM;
706*4882a593Smuzhiyun 	if (!old_buffer || !new_buffer)
707*4882a593Smuzhiyun 		goto out;
708*4882a593Smuzhiyun 	target = fn_label_build(label, profile, GFP_KERNEL,
709*4882a593Smuzhiyun 			build_pivotroot(profile, new_path, new_buffer,
710*4882a593Smuzhiyun 					old_path, old_buffer));
711*4882a593Smuzhiyun 	if (!target) {
712*4882a593Smuzhiyun 		info = "label build failed";
713*4882a593Smuzhiyun 		error = -ENOMEM;
714*4882a593Smuzhiyun 		goto fail;
715*4882a593Smuzhiyun 	} else if (!IS_ERR(target)) {
716*4882a593Smuzhiyun 		error = aa_replace_current_label(target);
717*4882a593Smuzhiyun 		if (error) {
718*4882a593Smuzhiyun 			/* TODO: audit target */
719*4882a593Smuzhiyun 			aa_put_label(target);
720*4882a593Smuzhiyun 			goto out;
721*4882a593Smuzhiyun 		}
722*4882a593Smuzhiyun 		aa_put_label(target);
723*4882a593Smuzhiyun 	} else
724*4882a593Smuzhiyun 		/* already audited error */
725*4882a593Smuzhiyun 		error = PTR_ERR(target);
726*4882a593Smuzhiyun out:
727*4882a593Smuzhiyun 	aa_put_buffer(old_buffer);
728*4882a593Smuzhiyun 	aa_put_buffer(new_buffer);
729*4882a593Smuzhiyun 
730*4882a593Smuzhiyun 	return error;
731*4882a593Smuzhiyun 
732*4882a593Smuzhiyun fail:
733*4882a593Smuzhiyun 	/* TODO: add back in auditing of new_name and old_name */
734*4882a593Smuzhiyun 	error = fn_for_each(label, profile,
735*4882a593Smuzhiyun 			audit_mount(profile, OP_PIVOTROOT, NULL /*new_name */,
736*4882a593Smuzhiyun 				    NULL /* old_name */,
737*4882a593Smuzhiyun 				    NULL, NULL,
738*4882a593Smuzhiyun 				    0, NULL, AA_MAY_PIVOTROOT, &nullperms, info,
739*4882a593Smuzhiyun 				    error));
740*4882a593Smuzhiyun 	goto out;
741*4882a593Smuzhiyun }
742