1 // SPDX-License-Identifier: GPL-2.0-only
3 * AppArmor security module
5 * This file contains AppArmor mediation of files
7 * Copyright (C) 1998-2008 Novell/SUSE
8 * Copyright 2009-2017 Canonical Ltd.
12 #include <linux/mount.h>
13 #include <linux/namei.h>
14 #include <uapi/linux/mount.h>
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"
27 static void audit_mnt_flags(struct audit_buffer
*ab
, unsigned long flags
)
29 if (flags
& MS_RDONLY
)
30 audit_log_format(ab
, "ro");
32 audit_log_format(ab
, "rw");
33 if (flags
& MS_NOSUID
)
34 audit_log_format(ab
, ", nosuid");
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");
54 audit_log_format(ab
, flags
& MS_REC
? ", rbind" : ", bind");
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" :
64 if (flags
& MS_PRIVATE
)
65 audit_log_format(ab
, flags
& MS_REC
? ", rprivate" :
68 audit_log_format(ab
, flags
& MS_REC
? ", rslave" :
70 if (flags
& MS_SHARED
)
71 audit_log_format(ab
, flags
& MS_REC
? ", rshared" :
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");
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)
88 static void audit_cb(struct audit_buffer
*ab
, void *va
)
90 struct common_audit_data
*sa
= va
;
91 struct apparmor_audit_data
*ad
= aad(sa
);
94 audit_log_format(ab
, " fstype=");
95 audit_log_untrustedstring(ab
, ad
->mnt
.type
);
97 if (ad
->mnt
.src_name
) {
98 audit_log_format(ab
, " srcname=");
99 audit_log_untrustedstring(ab
, ad
->mnt
.src_name
);
102 audit_log_format(ab
, " trans=");
103 audit_log_untrustedstring(ab
, ad
->mnt
.trans
);
106 audit_log_format(ab
, " flags=\"");
107 audit_mnt_flags(ab
, ad
->mnt
.flags
);
108 audit_log_format(ab
, "\"");
111 audit_log_format(ab
, " options=");
112 audit_log_untrustedstring(ab
, ad
->mnt
.data
);
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
132 * Returns: %0 or error on failure
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
)
141 int audit_type
= AUDIT_APPARMOR_AUTO
;
142 DEFINE_AUDIT_DATA(ad
, LSM_AUDIT_DATA_NONE
, AA_CLASS_MOUNT
, op
);
144 if (likely(!error
)) {
145 u32 mask
= perms
->audit
;
147 if (unlikely(AUDIT_MODE(profile
) == AUDIT_ALL
))
150 /* mask off perms that are not being force audited */
153 if (likely(!request
))
155 audit_type
= AUDIT_APPARMOR_AUDIT
;
157 /* only report permissions that were denied */
158 request
= request
& ~perms
->allow
;
160 if (request
& perms
->kill
)
161 audit_type
= AUDIT_APPARMOR_KILL
;
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
;
173 ad
.subj_cred
= subj_cred
;
175 ad
.mnt
.src_name
= src_name
;
177 ad
.mnt
.trans
= trans
;
178 ad
.mnt
.flags
= flags
;
179 if (data
&& (perms
->audit
& AA_AUDIT_DATA
))
184 return aa_audit(audit_type
, profile
, &ad
, audit_cb
);
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
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
197 * Returns: next state after flags match
199 static aa_state_t
match_mnt_flags(struct aa_dfa
*dfa
, aa_state_t state
,
204 for (i
= 0; i
<= 31 ; ++i
) {
205 if ((1 << i
) & flags
)
206 state
= aa_dfa_next(dfa
, state
, i
+ 1);
212 static const char * const mnt_info_table
[] = {
214 "failed mntpnt match",
215 "failed srcname match",
217 "failed flags match",
223 * Returns 0 on success else element that match failed in, this is the
224 * index into the mnt_info_table above
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
)
234 AA_BUG(!policy
->dfa
);
235 AA_BUG(!policy
->perms
);
238 state
= aa_dfa_match(policy
->dfa
, start
, mntpnt
);
239 state
= aa_dfa_null_transition(policy
->dfa
, state
);
244 state
= aa_dfa_match(policy
->dfa
, state
, devname
);
245 state
= aa_dfa_null_transition(policy
->dfa
, state
);
250 state
= aa_dfa_match(policy
->dfa
, state
, type
);
251 state
= aa_dfa_null_transition(policy
->dfa
, state
);
255 state
= match_mnt_flags(policy
->dfa
, state
, flags
);
258 *perms
= *aa_lookup_perms(policy
, state
);
259 if (perms
->allow
& AA_MAY_MOUNT
)
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
);
268 state
= aa_dfa_match(policy
->dfa
, state
, data
);
271 *perms
= *aa_lookup_perms(policy
, state
);
272 if (perms
->allow
& AA_MAY_MOUNT
)
276 /* failed at perms check, don't confuse with flags match */
281 static int path_flags(struct aa_profile
*profile
, const struct path
*path
)
286 return profile
->path_flags
|
287 (S_ISDIR(path
->dentry
->d_inode
->i_mode
) ? PATH_IS_DIR
: 0);
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))
303 * Returns: 0 on success else error
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
,
312 struct aa_perms perms
= { };
313 const char *mntpnt
= NULL
, *info
= NULL
;
314 struct aa_ruleset
*rules
= list_first_entry(&profile
->rules
,
315 typeof(*rules
), list
);
322 if (!RULE_MEDIATES(rules
, AA_CLASS_MOUNT
))
325 error
= aa_path_name(mntpath
, path_flags(profile
, mntpath
), buffer
,
326 &mntpnt
, &info
, profile
->disconnected
);
329 if (IS_ERR(devname
)) {
330 error
= PTR_ERR(devname
);
337 pos
= do_match_mnt(rules
->policy
,
338 rules
->policy
->start
[AA_CLASS_MOUNT
],
339 mntpnt
, devname
, type
, flags
, data
, binary
, &perms
);
341 info
= mnt_info_table
[pos
];
347 return audit_mount(subj_cred
, profile
, OP_MOUNT
, mntpnt
, devname
,
349 flags
, data
, AA_MAY_MOUNT
, &perms
, info
, error
);
353 * match_mnt - handle path matching for mount
354 * @subj_cred: cred of the subject
355 * @profile: the confining profile
356 * @path: for the mntpnt (NOT NULL)
357 * @buffer: buffer to be used to lookup mntpath
358 * @devpath: path devname/src_name (MAYBE NULL)
359 * @devbuffer: buffer to be used to lookup devname/src_name
360 * @type: string for the dev type (MAYBE NULL)
361 * @flags: mount flags to match
362 * @data: fs mount data (MAYBE NULL)
363 * @binary: whether @data is binary
365 * Returns: 0 on success else error
367 static int match_mnt(const struct cred
*subj_cred
,
368 struct aa_profile
*profile
, const struct path
*path
,
369 char *buffer
, const struct path
*devpath
, char *devbuffer
,
370 const char *type
, unsigned long flags
, void *data
,
373 const char *devname
= NULL
, *info
= NULL
;
374 struct aa_ruleset
*rules
= list_first_entry(&profile
->rules
,
375 typeof(*rules
), list
);
379 AA_BUG(devpath
&& !devbuffer
);
381 if (!RULE_MEDIATES(rules
, AA_CLASS_MOUNT
))
385 error
= aa_path_name(devpath
, path_flags(profile
, devpath
),
386 devbuffer
, &devname
, &info
,
387 profile
->disconnected
);
389 devname
= ERR_PTR(error
);
392 return match_mnt_path_str(subj_cred
, profile
, path
, buffer
, devname
,
393 type
, flags
, data
, binary
, info
);
396 int aa_remount(const struct cred
*subj_cred
,
397 struct aa_label
*label
, const struct path
*path
,
398 unsigned long flags
, void *data
)
400 struct aa_profile
*profile
;
408 binary
= path
->dentry
->d_sb
->s_type
->fs_flags
& FS_BINARY_MOUNTDATA
;
410 buffer
= aa_get_buffer(false);
413 error
= fn_for_each_confined(label
, profile
,
414 match_mnt(subj_cred
, profile
, path
, buffer
, NULL
,
416 flags
, data
, binary
));
417 aa_put_buffer(buffer
);
422 int aa_bind_mount(const struct cred
*subj_cred
,
423 struct aa_label
*label
, const struct path
*path
,
424 const char *dev_name
, unsigned long flags
)
426 struct aa_profile
*profile
;
427 char *buffer
= NULL
, *old_buffer
= NULL
;
428 struct path old_path
;
434 if (!dev_name
|| !*dev_name
)
437 flags
&= MS_REC
| MS_BIND
;
439 error
= kern_path(dev_name
, LOOKUP_FOLLOW
|LOOKUP_AUTOMOUNT
, &old_path
);
443 buffer
= aa_get_buffer(false);
444 old_buffer
= aa_get_buffer(false);
446 if (!buffer
|| !old_buffer
)
449 error
= fn_for_each_confined(label
, profile
,
450 match_mnt(subj_cred
, profile
, path
, buffer
, &old_path
,
451 old_buffer
, NULL
, flags
, NULL
, false));
453 aa_put_buffer(buffer
);
454 aa_put_buffer(old_buffer
);
460 int aa_mount_change_type(const struct cred
*subj_cred
,
461 struct aa_label
*label
, const struct path
*path
,
464 struct aa_profile
*profile
;
471 /* These are the flags allowed by do_change_type() */
472 flags
&= (MS_REC
| MS_SILENT
| MS_SHARED
| MS_PRIVATE
| MS_SLAVE
|
475 buffer
= aa_get_buffer(false);
478 error
= fn_for_each_confined(label
, profile
,
479 match_mnt(subj_cred
, profile
, path
, buffer
, NULL
,
481 flags
, NULL
, false));
482 aa_put_buffer(buffer
);
487 int aa_move_mount(const struct cred
*subj_cred
,
488 struct aa_label
*label
, const struct path
*from_path
,
489 const struct path
*to_path
)
491 struct aa_profile
*profile
;
492 char *to_buffer
= NULL
, *from_buffer
= NULL
;
499 to_buffer
= aa_get_buffer(false);
500 from_buffer
= aa_get_buffer(false);
502 if (!to_buffer
|| !from_buffer
)
505 if (!our_mnt(from_path
->mnt
))
506 /* moving a mount detached from the namespace */
508 error
= fn_for_each_confined(label
, profile
,
509 match_mnt(subj_cred
, profile
, to_path
, to_buffer
,
510 from_path
, from_buffer
,
511 NULL
, MS_MOVE
, NULL
, false));
513 aa_put_buffer(to_buffer
);
514 aa_put_buffer(from_buffer
);
519 int aa_move_mount_old(const struct cred
*subj_cred
, struct aa_label
*label
,
520 const struct path
*path
, const char *orig_name
)
522 struct path old_path
;
525 if (!orig_name
|| !*orig_name
)
527 error
= kern_path(orig_name
, LOOKUP_FOLLOW
, &old_path
);
531 error
= aa_move_mount(subj_cred
, label
, &old_path
, path
);
537 int aa_new_mount(const struct cred
*subj_cred
, struct aa_label
*label
,
538 const char *dev_name
, const struct path
*path
,
539 const char *type
, unsigned long flags
, void *data
)
541 struct aa_profile
*profile
;
542 char *buffer
= NULL
, *dev_buffer
= NULL
;
545 int requires_dev
= 0;
546 struct path tmp_path
, *dev_path
= NULL
;
552 struct file_system_type
*fstype
;
554 fstype
= get_fs_type(type
);
557 binary
= fstype
->fs_flags
& FS_BINARY_MOUNTDATA
;
558 requires_dev
= fstype
->fs_flags
& FS_REQUIRES_DEV
;
559 put_filesystem(fstype
);
562 if (!dev_name
|| !*dev_name
)
565 error
= kern_path(dev_name
, LOOKUP_FOLLOW
, &tmp_path
);
568 dev_path
= &tmp_path
;
572 buffer
= aa_get_buffer(false);
578 dev_buffer
= aa_get_buffer(false);
583 error
= fn_for_each_confined(label
, profile
,
584 match_mnt(subj_cred
, profile
, path
, buffer
,
585 dev_path
, dev_buffer
,
586 type
, flags
, data
, binary
));
588 error
= fn_for_each_confined(label
, profile
,
589 match_mnt_path_str(subj_cred
, profile
, path
,
591 type
, flags
, data
, binary
, NULL
));
595 aa_put_buffer(buffer
);
596 aa_put_buffer(dev_buffer
);
603 static int profile_umount(const struct cred
*subj_cred
,
604 struct aa_profile
*profile
, const struct path
*path
,
607 struct aa_ruleset
*rules
= list_first_entry(&profile
->rules
,
608 typeof(*rules
), list
);
609 struct aa_perms perms
= { };
610 const char *name
= NULL
, *info
= NULL
;
617 if (!RULE_MEDIATES(rules
, AA_CLASS_MOUNT
))
620 error
= aa_path_name(path
, path_flags(profile
, path
), buffer
, &name
,
621 &info
, profile
->disconnected
);
625 state
= aa_dfa_match(rules
->policy
->dfa
,
626 rules
->policy
->start
[AA_CLASS_MOUNT
],
628 perms
= *aa_lookup_perms(rules
->policy
, state
);
629 if (AA_MAY_UMOUNT
& ~perms
.allow
)
633 return audit_mount(subj_cred
, profile
, OP_UMOUNT
, name
, NULL
, NULL
,
635 AA_MAY_UMOUNT
, &perms
, info
, error
);
638 int aa_umount(const struct cred
*subj_cred
, struct aa_label
*label
,
639 struct vfsmount
*mnt
, int flags
)
641 struct aa_profile
*profile
;
644 struct path path
= { .mnt
= mnt
, .dentry
= mnt
->mnt_root
};
649 buffer
= aa_get_buffer(false);
653 error
= fn_for_each_confined(label
, profile
,
654 profile_umount(subj_cred
, profile
, &path
, buffer
));
655 aa_put_buffer(buffer
);
660 /* helper fn for transition on pivotroot
662 * Returns: label for transition or ERR_PTR. Does not return NULL
664 static struct aa_label
*build_pivotroot(const struct cred
*subj_cred
,
665 struct aa_profile
*profile
,
666 const struct path
*new_path
,
668 const struct path
*old_path
,
671 struct aa_ruleset
*rules
= list_first_entry(&profile
->rules
,
672 typeof(*rules
), list
);
673 const char *old_name
, *new_name
= NULL
, *info
= NULL
;
674 const char *trans_name
= NULL
;
675 struct aa_perms perms
= { };
683 if (profile_unconfined(profile
) ||
684 !RULE_MEDIATES(rules
, AA_CLASS_MOUNT
))
685 return aa_get_newest_label(&profile
->label
);
687 error
= aa_path_name(old_path
, path_flags(profile
, old_path
),
688 old_buffer
, &old_name
, &info
,
689 profile
->disconnected
);
692 error
= aa_path_name(new_path
, path_flags(profile
, new_path
),
693 new_buffer
, &new_name
, &info
,
694 profile
->disconnected
);
699 state
= aa_dfa_match(rules
->policy
->dfa
,
700 rules
->policy
->start
[AA_CLASS_MOUNT
],
702 state
= aa_dfa_null_transition(rules
->policy
->dfa
, state
);
703 state
= aa_dfa_match(rules
->policy
->dfa
, state
, old_name
);
704 perms
= *aa_lookup_perms(rules
->policy
, state
);
706 if (AA_MAY_PIVOTROOT
& perms
.allow
)
710 error
= audit_mount(subj_cred
, profile
, OP_PIVOTROOT
, new_name
,
712 NULL
, trans_name
, 0, NULL
, AA_MAY_PIVOTROOT
,
713 &perms
, info
, error
);
715 return ERR_PTR(error
);
717 return aa_get_newest_label(&profile
->label
);
720 int aa_pivotroot(const struct cred
*subj_cred
, struct aa_label
*label
,
721 const struct path
*old_path
,
722 const struct path
*new_path
)
724 struct aa_profile
*profile
;
725 struct aa_label
*target
= NULL
;
726 char *old_buffer
= NULL
, *new_buffer
= NULL
, *info
= NULL
;
733 old_buffer
= aa_get_buffer(false);
734 new_buffer
= aa_get_buffer(false);
736 if (!old_buffer
|| !new_buffer
)
738 target
= fn_label_build(label
, profile
, GFP_KERNEL
,
739 build_pivotroot(subj_cred
, profile
, new_path
,
741 old_path
, old_buffer
));
743 info
= "label build failed";
746 } else if (!IS_ERR(target
)) {
747 error
= aa_replace_current_label(target
);
749 /* TODO: audit target */
750 aa_put_label(target
);
753 aa_put_label(target
);
755 /* already audited error */
756 error
= PTR_ERR(target
);
758 aa_put_buffer(old_buffer
);
759 aa_put_buffer(new_buffer
);
764 /* TODO: add back in auditing of new_name and old_name */
765 error
= fn_for_each(label
, profile
,
766 audit_mount(subj_cred
, profile
, OP_PIVOTROOT
,
770 0, NULL
, AA_MAY_PIVOTROOT
, &nullperms
, info
,