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