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