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