]>
git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - security/apparmor/mount.c
2 * AppArmor security module
4 * This file contains AppArmor mediation of files
6 * Copyright (C) 1998-2008 Novell/SUSE
7 * Copyright 2009-2012 Canonical Ltd.
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation, version 2 of the
16 #include <linux/mount.h>
17 #include <linux/namei.h>
19 #include "include/apparmor.h"
20 #include "include/audit.h"
21 #include "include/context.h"
22 #include "include/domain.h"
23 #include "include/file.h"
24 #include "include/match.h"
25 #include "include/mount.h"
26 #include "include/path.h"
27 #include "include/policy.h"
30 static void audit_mnt_flags(struct audit_buffer
*ab
, unsigned long flags
)
32 if (flags
& MS_RDONLY
)
33 audit_log_format(ab
, "ro");
35 audit_log_format(ab
, "rw");
36 if (flags
& MS_NOSUID
)
37 audit_log_format(ab
, ", nosuid");
39 audit_log_format(ab
, ", nodev");
40 if (flags
& MS_NOEXEC
)
41 audit_log_format(ab
, ", noexec");
42 if (flags
& MS_SYNCHRONOUS
)
43 audit_log_format(ab
, ", sync");
44 if (flags
& MS_REMOUNT
)
45 audit_log_format(ab
, ", remount");
46 if (flags
& MS_MANDLOCK
)
47 audit_log_format(ab
, ", mand");
48 if (flags
& MS_DIRSYNC
)
49 audit_log_format(ab
, ", dirsync");
50 if (flags
& MS_NOATIME
)
51 audit_log_format(ab
, ", noatime");
52 if (flags
& MS_NODIRATIME
)
53 audit_log_format(ab
, ", nodiratime");
55 audit_log_format(ab
, flags
& MS_REC
? ", rbind" : ", bind");
57 audit_log_format(ab
, ", move");
58 if (flags
& MS_SILENT
)
59 audit_log_format(ab
, ", silent");
60 if (flags
& MS_POSIXACL
)
61 audit_log_format(ab
, ", acl");
62 if (flags
& MS_UNBINDABLE
)
63 audit_log_format(ab
, flags
& MS_REC
? ", runbindable" :
65 if (flags
& MS_PRIVATE
)
66 audit_log_format(ab
, flags
& MS_REC
? ", rprivate" :
69 audit_log_format(ab
, flags
& MS_REC
? ", rslave" :
71 if (flags
& MS_SHARED
)
72 audit_log_format(ab
, flags
& MS_REC
? ", rshared" :
74 if (flags
& MS_RELATIME
)
75 audit_log_format(ab
, ", relatime");
76 if (flags
& MS_I_VERSION
)
77 audit_log_format(ab
, ", iversion");
78 if (flags
& MS_STRICTATIME
)
79 audit_log_format(ab
, ", strictatime");
80 if (flags
& MS_NOUSER
)
81 audit_log_format(ab
, ", nouser");
85 * audit_cb - call back for mount specific audit fields
86 * @ab: audit_buffer (NOT NULL)
87 * @va: audit struct to audit values of (NOT NULL)
89 static void audit_cb(struct audit_buffer
*ab
, void *va
)
91 struct common_audit_data
*sa
= va
;
93 if (aad(sa
)->mnt
.type
) {
94 audit_log_format(ab
, " fstype=");
95 audit_log_untrustedstring(ab
, aad(sa
)->mnt
.type
);
97 if (aad(sa
)->mnt
.src_name
) {
98 audit_log_format(ab
, " srcname=");
99 audit_log_untrustedstring(ab
, aad(sa
)->mnt
.src_name
);
101 if (aad(sa
)->mnt
.trans
) {
102 audit_log_format(ab
, " trans=");
103 audit_log_untrustedstring(ab
, aad(sa
)->mnt
.trans
);
105 if (aad(sa
)->mnt
.flags
) {
106 audit_log_format(ab
, " flags=\"");
107 audit_mnt_flags(ab
, aad(sa
)->mnt
.flags
);
108 audit_log_format(ab
, "\"");
110 if (aad(sa
)->mnt
.data
) {
111 audit_log_format(ab
, " options=");
112 audit_log_untrustedstring(ab
, aad(sa
)->mnt
.data
);
117 * audit_mount - handle the auditing of mount operations
118 * @profile: the profile being enforced (NOT NULL)
119 * @op: operation being mediated (NOT NULL)
120 * @name: name of object being mediated (MAYBE NULL)
121 * @src_name: src_name of object being mediated (MAYBE_NULL)
122 * @type: type of filesystem (MAYBE_NULL)
123 * @trans: name of trans (MAYBE NULL)
124 * @flags: filesystem idependent mount flags
125 * @data: filesystem mount flags
126 * @request: permissions requested
127 * @perms: the permissions computed for the request (NOT NULL)
128 * @info: extra information message (MAYBE NULL)
129 * @error: 0 if operation allowed else failure error code
131 * Returns: %0 or error on failure
133 static int audit_mount(struct aa_profile
*profile
, const char *op
, const char *name
,
134 const char *src_name
, const char *type
,
135 const char *trans
, unsigned long flags
,
136 const void *data
, u32 request
, struct aa_perms
*perms
,
137 const char *info
, int error
)
139 int audit_type
= AUDIT_APPARMOR_AUTO
;
140 DEFINE_AUDIT_DATA(sa
, LSM_AUDIT_DATA_NONE
, op
);
142 if (likely(!error
)) {
143 u32 mask
= perms
->audit
;
145 if (unlikely(AUDIT_MODE(profile
) == AUDIT_ALL
))
148 /* mask off perms that are not being force audited */
151 if (likely(!request
))
153 audit_type
= AUDIT_APPARMOR_AUDIT
;
155 /* only report permissions that were denied */
156 request
= request
& ~perms
->allow
;
158 if (request
& perms
->kill
)
159 audit_type
= AUDIT_APPARMOR_KILL
;
161 /* quiet known rejects, assumes quiet and kill do not overlap */
162 if ((request
& perms
->quiet
) &&
163 AUDIT_MODE(profile
) != AUDIT_NOQUIET
&&
164 AUDIT_MODE(profile
) != AUDIT_ALL
)
165 request
&= ~perms
->quiet
;
171 aad(&sa
)->name
= name
;
172 aad(&sa
)->mnt
.src_name
= src_name
;
173 aad(&sa
)->mnt
.type
= type
;
174 aad(&sa
)->mnt
.trans
= trans
;
175 aad(&sa
)->mnt
.flags
= flags
;
176 if (data
&& (perms
->audit
& AA_AUDIT_DATA
))
177 aad(&sa
)->mnt
.data
= data
;
178 aad(&sa
)->info
= info
;
179 aad(&sa
)->error
= error
;
181 return aa_audit(audit_type
, profile
, &sa
, audit_cb
);
185 * match_mnt_flags - Do an ordered match on mount flags
186 * @dfa: dfa to match against
187 * @state: state to start in
188 * @flags: mount flags to match against
190 * Mount flags are encoded as an ordered match. This is done instead of
191 * checking against a simple bitmask, to allow for logical operations
194 * Returns: next state after flags match
196 static unsigned int match_mnt_flags(struct aa_dfa
*dfa
, unsigned int state
,
201 for (i
= 0; i
<= 31 ; ++i
) {
202 if ((1 << i
) & flags
)
203 state
= aa_dfa_next(dfa
, state
, i
+ 1);
210 * compute_mnt_perms - compute mount permission associated with @state
211 * @dfa: dfa to match against (NOT NULL)
212 * @state: state match finished in
214 * Returns: mount permissions
216 static struct aa_perms
compute_mnt_perms(struct aa_dfa
*dfa
,
219 struct aa_perms perms
;
222 perms
.allow
= dfa_user_allow(dfa
, state
);
223 perms
.audit
= dfa_user_audit(dfa
, state
);
224 perms
.quiet
= dfa_user_quiet(dfa
, state
);
225 perms
.xindex
= dfa_user_xindex(dfa
, state
);
230 static const char *mnt_info_table
[] = {
232 "failed mntpnt match",
233 "failed srcname match",
235 "failed flags match",
240 * Returns 0 on success else element that match failed in, this is the
241 * index into the mnt_info_table above
243 static int do_match_mnt(struct aa_dfa
*dfa
, unsigned int start
,
244 const char *mntpnt
, const char *devname
,
245 const char *type
, unsigned long flags
,
246 void *data
, bool binary
, struct aa_perms
*perms
)
253 state
= aa_dfa_match(dfa
, start
, mntpnt
);
254 state
= aa_dfa_null_transition(dfa
, state
);
259 state
= aa_dfa_match(dfa
, state
, devname
);
260 state
= aa_dfa_null_transition(dfa
, state
);
265 state
= aa_dfa_match(dfa
, state
, type
);
266 state
= aa_dfa_null_transition(dfa
, state
);
270 state
= match_mnt_flags(dfa
, state
, flags
);
273 *perms
= compute_mnt_perms(dfa
, state
);
274 if (perms
->allow
& AA_MAY_MOUNT
)
277 /* only match data if not binary and the DFA flags data is expected */
278 if (data
&& !binary
&& (perms
->allow
& AA_MNT_CONT_MATCH
)) {
279 state
= aa_dfa_null_transition(dfa
, state
);
283 state
= aa_dfa_match(dfa
, state
, data
);
286 *perms
= compute_mnt_perms(dfa
, state
);
287 if (perms
->allow
& AA_MAY_MOUNT
)
291 /* failed at end of flags match */
296 * match_mnt - handle path matching for mount
297 * @profile: the confining profile
298 * @mntpnt: string for the mntpnt (NOT NULL)
299 * @devname: string for the devname/src_name (MAYBE NULL)
300 * @type: string for the dev type (MAYBE NULL)
301 * @flags: mount flags to match
302 * @data: fs mount data (MAYBE NULL)
303 * @binary: whether @data is binary
304 * @perms: Returns: permission found by the match
305 * @info: Returns: infomation string about the match for logging
307 * Returns: 0 on success else error
309 static int match_mnt(struct aa_profile
*profile
, const char *mntpnt
,
310 const char *devname
, const char *type
,
311 unsigned long flags
, void *data
, bool binary
)
313 struct aa_perms perms
= { };
314 const char *info
= NULL
;
315 int pos
, error
= -EACCES
;
319 pos
= do_match_mnt(profile
->policy
.dfa
,
320 profile
->policy
.start
[AA_CLASS_MOUNT
],
321 mntpnt
, devname
, type
, flags
, data
, binary
, &perms
);
323 info
= mnt_info_table
[pos
];
329 return audit_mount(profile
, OP_MOUNT
, mntpnt
, devname
, type
, NULL
,
330 flags
, data
, AA_MAY_MOUNT
, &perms
, info
, error
);
333 static int path_flags(struct aa_profile
*profile
, struct path
*path
)
338 return profile
->path_flags
|
339 (S_ISDIR(path
->dentry
->d_inode
->i_mode
) ? PATH_IS_DIR
: 0);
342 int aa_remount(struct aa_label
*label
, struct path
*path
, unsigned long flags
,
345 struct aa_profile
*profile
;
346 const char *name
, *info
= NULL
;
354 binary
= path
->dentry
->d_sb
->s_type
->fs_flags
& FS_BINARY_MOUNTDATA
;
357 error
= aa_path_name(path
, path_flags(labels_profile(label
), path
),
358 buffer
, &name
, &info
,
359 labels_profile(label
)->disconnected
);
361 error
= audit_mount(labels_profile(label
), OP_MOUNT
, name
, NULL
,
362 NULL
, NULL
, flags
, data
, AA_MAY_MOUNT
,
363 &nullperms
, info
, error
);
367 error
= fn_for_each_confined(label
, profile
,
368 match_mnt(profile
, name
, NULL
, NULL
, flags
, data
,
377 int aa_bind_mount(struct aa_label
*label
, struct path
*path
,
378 const char *dev_name
, unsigned long flags
)
380 struct aa_profile
*profile
;
381 char *buffer
= NULL
, *old_buffer
= NULL
;
382 const char *name
, *old_name
= NULL
, *info
= NULL
;
383 struct path old_path
;
389 if (!dev_name
|| !*dev_name
)
392 flags
&= MS_REC
| MS_BIND
;
394 error
= kern_path(dev_name
, LOOKUP_FOLLOW
|LOOKUP_AUTOMOUNT
, &old_path
);
398 get_buffers(buffer
, old_buffer
);
399 error
= aa_path_name(path
, path_flags(labels_profile(label
), path
), buffer
, &name
,
400 &info
, labels_profile(label
)->disconnected
);
404 error
= aa_path_name(&old_path
, path_flags(labels_profile(label
),
406 old_buffer
, &old_name
, &info
,
407 labels_profile(label
)->disconnected
);
412 error
= fn_for_each_confined(label
, profile
,
413 match_mnt(profile
, name
, old_name
, NULL
, flags
, NULL
,
417 put_buffers(buffer
, old_buffer
);
422 error
= fn_for_each(label
, profile
,
423 audit_mount(profile
, OP_MOUNT
, name
, old_name
, NULL
,
424 NULL
, flags
, NULL
, AA_MAY_MOUNT
, &nullperms
,
429 int aa_mount_change_type(struct aa_label
*label
, struct path
*path
,
432 struct aa_profile
*profile
;
434 const char *name
, *info
= NULL
;
440 /* These are the flags allowed by do_change_type() */
441 flags
&= (MS_REC
| MS_SILENT
| MS_SHARED
| MS_PRIVATE
| MS_SLAVE
|
445 error
= aa_path_name(path
, path_flags(labels_profile(label
), path
),
446 buffer
, &name
, &info
,
447 labels_profile(label
)->disconnected
);
449 error
= fn_for_each(label
, profile
,
450 audit_mount(profile
, OP_MOUNT
, name
, NULL
,
451 NULL
, NULL
, flags
, NULL
,
452 AA_MAY_MOUNT
, &nullperms
, info
,
457 error
= fn_for_each_confined(label
, profile
,
458 match_mnt(profile
, name
, NULL
, NULL
, flags
, NULL
,
467 int aa_move_mount(struct aa_label
*label
, struct path
*path
,
468 const char *orig_name
)
470 struct aa_profile
*profile
;
471 char *buffer
= NULL
, *old_buffer
= NULL
;
472 const char *name
, *old_name
= NULL
, *info
= NULL
;
473 struct path old_path
;
479 if (!orig_name
|| !*orig_name
)
482 error
= kern_path(orig_name
, LOOKUP_FOLLOW
, &old_path
);
486 get_buffers(buffer
, old_buffer
);
487 error
= aa_path_name(path
, path_flags(labels_profile(label
), path
),
488 buffer
, &name
, &info
,
489 labels_profile(label
)->disconnected
);
493 error
= aa_path_name(&old_path
, path_flags(labels_profile(label
),
495 old_buffer
, &old_name
, &info
,
496 labels_profile(label
)->disconnected
);
501 error
= fn_for_each_confined(label
, profile
,
502 match_mnt(profile
, name
, old_name
, NULL
, MS_MOVE
, NULL
,
506 put_buffers(buffer
, old_buffer
);
511 error
= fn_for_each(label
, profile
,
512 audit_mount(profile
, OP_MOUNT
, name
, old_name
, NULL
,
513 NULL
, MS_MOVE
, NULL
, AA_MAY_MOUNT
,
514 &nullperms
, info
, error
));
518 int aa_new_mount(struct aa_label
*label
, const char *orig_dev_name
,
519 struct path
*path
, const char *type
, unsigned long flags
,
522 struct aa_profile
*profile
;
523 char *buffer
= NULL
, *dev_buffer
= NULL
;
524 const char *name
= NULL
, *dev_name
= NULL
, *info
= NULL
;
527 int requires_dev
= 0;
528 struct path dev_path
;
533 dev_name
= orig_dev_name
;
535 struct file_system_type
*fstype
;
536 fstype
= get_fs_type(type
);
539 binary
= fstype
->fs_flags
& FS_BINARY_MOUNTDATA
;
540 requires_dev
= fstype
->fs_flags
& FS_REQUIRES_DEV
;
541 put_filesystem(fstype
);
544 if (!dev_name
|| !*dev_name
)
547 error
= kern_path(dev_name
, LOOKUP_FOLLOW
, &dev_path
);
553 get_buffers(buffer
, dev_buffer
);
554 if (type
&& requires_dev
) {
555 error
= aa_path_name(&dev_path
,
556 path_flags(labels_profile(label
),
558 dev_buffer
, &dev_name
, &info
,
559 labels_profile(label
)->disconnected
);
565 error
= aa_path_name(path
, path_flags(labels_profile(label
), path
),
566 buffer
, &name
, &info
,
567 labels_profile(label
)->disconnected
);
571 error
= fn_for_each_confined(label
, profile
,
572 match_mnt(profile
, name
, dev_name
, type
, flags
, data
,
576 put_buffers(buffer
, dev_buffer
);
581 error
= fn_for_each(label
, profile
,
582 audit_mount(labels_profile(label
), OP_MOUNT
, name
,
583 dev_name
, type
, NULL
, flags
, data
,
584 AA_MAY_MOUNT
, &nullperms
, info
, error
));
588 static int profile_umount(struct aa_profile
*profile
, const char *name
)
590 struct aa_perms perms
= { };
591 const char *info
= NULL
;
598 state
= aa_dfa_match(profile
->policy
.dfa
,
599 profile
->policy
.start
[AA_CLASS_MOUNT
],
601 perms
= compute_mnt_perms(profile
->policy
.dfa
, state
);
602 if (AA_MAY_UMOUNT
& ~perms
.allow
)
605 return audit_mount(profile
, OP_UMOUNT
, name
, NULL
, NULL
, NULL
, 0, NULL
,
606 AA_MAY_UMOUNT
, &perms
, info
, e
);
609 int aa_umount(struct aa_label
*label
, struct vfsmount
*mnt
, int flags
)
611 struct aa_profile
*profile
;
613 const char *name
, *info
= NULL
;
615 struct path path
= { mnt
, mnt
->mnt_root
};
621 error
= aa_path_name(&path
, path_flags(labels_profile(label
), &path
),
622 buffer
, &name
, &info
,
623 labels_profile(label
)->disconnected
);
625 error
= fn_for_each(label
, profile
,
626 audit_mount(profile
, OP_UMOUNT
, name
, NULL
,
627 NULL
, NULL
, 0, NULL
, AA_MAY_UMOUNT
,
628 &nullperms
, info
, error
));
632 error
= fn_for_each_confined(label
, profile
,
633 profile_umount(profile
, name
));
641 static int profile_pivotroot(struct aa_profile
*profile
, const char *new_name
,
642 const char *old_name
, struct aa_label
**trans
)
644 struct aa_label
*target
= NULL
;
645 const char *trans_name
= NULL
;
646 struct aa_perms perms
= { };
647 const char *info
= NULL
;
656 /* TODO: actual domain transition computation for multiple
659 state
= aa_dfa_match(profile
->policy
.dfa
,
660 profile
->policy
.start
[AA_CLASS_MOUNT
],
662 state
= aa_dfa_null_transition(profile
->policy
.dfa
, state
);
663 state
= aa_dfa_match(profile
->policy
.dfa
, state
, old_name
);
664 perms
= compute_mnt_perms(profile
->policy
.dfa
, state
);
666 if (AA_MAY_PIVOTROOT
& perms
.allow
) {
667 if ((perms
.xindex
& AA_X_TYPE_MASK
) == AA_X_TABLE
) {
668 target
= x_table_lookup(profile
, perms
.xindex
,
678 error
= audit_mount(profile
, OP_PIVOTROOT
, new_name
, old_name
,
679 NULL
, trans_name
, 0, NULL
, AA_MAY_PIVOTROOT
,
680 &perms
, info
, error
);
682 aa_put_label(target
);
687 int aa_pivotroot(struct aa_label
*label
, struct path
*old_path
,
688 struct path
*new_path
)
690 struct aa_profile
*profile
;
691 struct aa_label
*target
= NULL
;
692 char *old_buffer
= NULL
, *new_buffer
= NULL
;
693 const char *old_name
, *new_name
= NULL
, *info
= NULL
;
700 get_buffers(old_buffer
, new_buffer
);
701 error
= aa_path_name(old_path
, path_flags(labels_profile(label
),
703 old_buffer
, &old_name
, &info
,
704 labels_profile(label
)->disconnected
);
707 error
= aa_path_name(new_path
, path_flags(labels_profile(label
),
709 new_buffer
, &new_name
, &info
,
710 labels_profile(label
)->disconnected
);
713 error
= fn_for_each(label
, profile
,
714 profile_pivotroot(profile
, new_name
, old_name
,
717 put_buffers(old_buffer
, new_buffer
);
720 error
= aa_replace_current_label(target
);
725 error
= fn_for_each(label
, profile
,
726 audit_mount(profile
, OP_PIVOTROOT
, new_name
, old_name
,
728 0, NULL
, AA_MAY_PIVOTROOT
, &nullperms
, info
,