]> git.pld-linux.org Git - packages/kernel.git/blob - 0007-apparmor-add-mount-mediation.patch
- up to 4.13.12
[packages/kernel.git] / 0007-apparmor-add-mount-mediation.patch
1 From f37356d0a41499f9222f9f2b9c0147b500ae4285 Mon Sep 17 00:00:00 2001
2 From: John Johansen <john.johansen@canonical.com>
3 Date: Tue, 18 Jul 2017 23:04:47 -0700
4 Subject: [PATCH 07/17] apparmor: add mount mediation
5
6 Add basic mount mediation. That allows controlling based on basic
7 mount parameters. It does not include special mount parameters for
8 apparmor, super block labeling, or any triggers for apparmor namespace
9 parameter modifications on pivot root.
10
11 default userspace policy rules have the form of
12   MOUNT RULE = ( MOUNT | REMOUNT | UMOUNT )
13
14   MOUNT = [ QUALIFIERS ] 'mount' [ MOUNT CONDITIONS ] [ SOURCE FILEGLOB ]
15           [ '->' MOUNTPOINT FILEGLOB ]
16
17   REMOUNT = [ QUALIFIERS ] 'remount' [ MOUNT CONDITIONS ]
18             MOUNTPOINT FILEGLOB
19
20   UMOUNT = [ QUALIFIERS ] 'umount' [ MOUNT CONDITIONS ] MOUNTPOINT FILEGLOB
21
22   MOUNT CONDITIONS = [ ( 'fstype' | 'vfstype' ) ( '=' | 'in' )
23                        MOUNT FSTYPE EXPRESSION ]
24                        [ 'options' ( '=' | 'in' ) MOUNT FLAGS EXPRESSION ]
25
26   MOUNT FSTYPE EXPRESSION = ( MOUNT FSTYPE LIST | MOUNT EXPRESSION )
27
28   MOUNT FSTYPE LIST = Comma separated list of valid filesystem and
29                       virtual filesystem types (eg ext4, debugfs, etc)
30
31   MOUNT FLAGS EXPRESSION = ( MOUNT FLAGS LIST | MOUNT EXPRESSION )
32
33   MOUNT FLAGS LIST = Comma separated list of MOUNT FLAGS.
34
35   MOUNT FLAGS = ( 'ro' | 'rw' | 'nosuid' | 'suid' | 'nodev' | 'dev' |
36                   'noexec' | 'exec' | 'sync' | 'async' | 'remount' |
37                   'mand' | 'nomand' | 'dirsync' | 'noatime' | 'atime' |
38                   'nodiratime' | 'diratime' | 'bind' | 'rbind' | 'move' |
39                   'verbose' | 'silent' | 'loud' | 'acl' | 'noacl' |
40                   'unbindable' | 'runbindable' | 'private' | 'rprivate' |
41                   'slave' | 'rslave' | 'shared' | 'rshared' |
42                   'relatime' | 'norelatime' | 'iversion' | 'noiversion' |
43                   'strictatime' | 'nouser' | 'user' )
44
45   MOUNT EXPRESSION = ( ALPHANUMERIC | AARE ) ...
46
47   PIVOT ROOT RULE = [ QUALIFIERS ] pivot_root [ oldroot=OLD PUT FILEGLOB ]
48                     [ NEW ROOT FILEGLOB ]
49
50   SOURCE FILEGLOB = FILEGLOB
51
52   MOUNTPOINT FILEGLOB = FILEGLOB
53
54 eg.
55   mount,
56   mount /dev/foo,
57   mount options=ro /dev/foo -> /mnt/,
58   mount options in (ro,atime) /dev/foo -> /mnt/,
59   mount options=ro options=atime,
60
61 Signed-off-by: John Johansen <john.johansen@canonical.com>
62 Acked-by: Seth Arnold <seth.arnold@canonical.com>
63 (cherry picked from commit fa488437d0f95b2e5db1e624341fe0d5a233f729)
64 ---
65  security/apparmor/Makefile           |   2 +-
66  security/apparmor/apparmorfs.c       |   8 +-
67  security/apparmor/domain.c           |   4 +-
68  security/apparmor/include/apparmor.h |   1 +
69  security/apparmor/include/audit.h    |  11 +
70  security/apparmor/include/domain.h   |   5 +
71  security/apparmor/include/mount.h    |  54 +++
72  security/apparmor/lsm.c              |  64 ++++
73  security/apparmor/mount.c            | 696 +++++++++++++++++++++++++++++++++++
74  9 files changed, 841 insertions(+), 4 deletions(-)
75  create mode 100644 security/apparmor/include/mount.h
76  create mode 100644 security/apparmor/mount.c
77
78 diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
79 index a16b195274de..81a34426d024 100644
80 --- a/security/apparmor/Makefile
81 +++ b/security/apparmor/Makefile
82 @@ -4,7 +4,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
83  
84  apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
85                path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
86 -              resource.o secid.o file.o policy_ns.o label.o
87 +              resource.o secid.o file.o policy_ns.o label.o mount.o
88  apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
89  
90  clean-files := capability_names.h rlim_names.h
91 diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
92 index a5f9e1aa51f7..8fa6c898c44b 100644
93 --- a/security/apparmor/apparmorfs.c
94 +++ b/security/apparmor/apparmorfs.c
95 @@ -2159,9 +2159,14 @@ static struct aa_sfs_entry aa_sfs_entry_policy[] = {
96         { }
97  };
98  
99 +static struct aa_sfs_entry aa_sfs_entry_mount[] = {
100 +       AA_SFS_FILE_STRING("mask", "mount umount pivot_root"),
101 +       { }
102 +};
103 +
104  static struct aa_sfs_entry aa_sfs_entry_ns[] = {
105         AA_SFS_FILE_BOOLEAN("profile",          1),
106 -       AA_SFS_FILE_BOOLEAN("pivot_root",       1),
107 +       AA_SFS_FILE_BOOLEAN("pivot_root",       0),
108         { }
109  };
110  
111 @@ -2180,6 +2185,7 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = {
112         AA_SFS_DIR("policy",                    aa_sfs_entry_policy),
113         AA_SFS_DIR("domain",                    aa_sfs_entry_domain),
114         AA_SFS_DIR("file",                      aa_sfs_entry_file),
115 +       AA_SFS_DIR("mount",                     aa_sfs_entry_mount),
116         AA_SFS_DIR("namespaces",                aa_sfs_entry_ns),
117         AA_SFS_FILE_U64("capability",           VFS_CAP_FLAGS_MASK),
118         AA_SFS_DIR("rlimit",                    aa_sfs_entry_rlimit),
119 diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
120 index d0594446ae3f..ffc8c75a6785 100644
121 --- a/security/apparmor/domain.c
122 +++ b/security/apparmor/domain.c
123 @@ -374,8 +374,8 @@ static const char *next_name(int xtype, const char *name)
124   *
125   * Returns: refcounted label, or NULL on failure (MAYBE NULL)
126   */
127 -static struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex,
128 -                                      const char **name)
129 +struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex,
130 +                               const char **name)
131  {
132         struct aa_label *label = NULL;
133         u32 xtype = xindex & AA_X_TYPE_MASK;
134 diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
135 index 962a20a75e01..829082c35faa 100644
136 --- a/security/apparmor/include/apparmor.h
137 +++ b/security/apparmor/include/apparmor.h
138 @@ -27,6 +27,7 @@
139  #define AA_CLASS_NET           4
140  #define AA_CLASS_RLIMITS       5
141  #define AA_CLASS_DOMAIN                6
142 +#define AA_CLASS_MOUNT         7
143  #define AA_CLASS_PTRACE                9
144  #define AA_CLASS_SIGNAL                10
145  #define AA_CLASS_LABEL         16
146 diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
147 index d9a156ae11b9..c3fe1c5ef3bc 100644
148 --- a/security/apparmor/include/audit.h
149 +++ b/security/apparmor/include/audit.h
150 @@ -71,6 +71,10 @@ enum audit_type {
151  #define OP_FMPROT "file_mprotect"
152  #define OP_INHERIT "file_inherit"
153  
154 +#define OP_PIVOTROOT "pivotroot"
155 +#define OP_MOUNT "mount"
156 +#define OP_UMOUNT "umount"
157 +
158  #define OP_CREATE "create"
159  #define OP_POST_CREATE "post_create"
160  #define OP_BIND "bind"
161 @@ -132,6 +136,13 @@ struct apparmor_audit_data {
162                         int rlim;
163                         unsigned long max;
164                 } rlim;
165 +               struct {
166 +                       const char *src_name;
167 +                       const char *type;
168 +                       const char *trans;
169 +                       const char *data;
170 +                       unsigned long flags;
171 +               } mnt;
172         };
173  };
174  
175 diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h
176 index bab5810b6e9a..db27403346c5 100644
177 --- a/security/apparmor/include/domain.h
178 +++ b/security/apparmor/include/domain.h
179 @@ -15,6 +15,8 @@
180  #include <linux/binfmts.h>
181  #include <linux/types.h>
182  
183 +#include "label.h"
184 +
185  #ifndef __AA_DOMAIN_H
186  #define __AA_DOMAIN_H
187  
188 @@ -29,6 +31,9 @@ struct aa_domain {
189  #define AA_CHANGE_ONEXEC  4
190  #define AA_CHANGE_STACK 8
191  
192 +struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex,
193 +                               const char **name);
194 +
195  int apparmor_bprm_set_creds(struct linux_binprm *bprm);
196  int apparmor_bprm_secureexec(struct linux_binprm *bprm);
197  
198 diff --git a/security/apparmor/include/mount.h b/security/apparmor/include/mount.h
199 new file mode 100644
200 index 000000000000..25d6067fa6ef
201 --- /dev/null
202 +++ b/security/apparmor/include/mount.h
203 @@ -0,0 +1,54 @@
204 +/*
205 + * AppArmor security module
206 + *
207 + * This file contains AppArmor file mediation function definitions.
208 + *
209 + * Copyright 2017 Canonical Ltd.
210 + *
211 + * This program is free software; you can redistribute it and/or
212 + * modify it under the terms of the GNU General Public License as
213 + * published by the Free Software Foundation, version 2 of the
214 + * License.
215 + */
216 +
217 +#ifndef __AA_MOUNT_H
218 +#define __AA_MOUNT_H
219 +
220 +#include <linux/fs.h>
221 +#include <linux/path.h>
222 +
223 +#include "domain.h"
224 +#include "policy.h"
225 +
226 +/* mount perms */
227 +#define AA_MAY_PIVOTROOT       0x01
228 +#define AA_MAY_MOUNT           0x02
229 +#define AA_MAY_UMOUNT          0x04
230 +#define AA_AUDIT_DATA          0x40
231 +#define AA_MNT_CONT_MATCH      0x40
232 +
233 +#define AA_MS_IGNORE_MASK (MS_KERNMOUNT | MS_NOSEC | MS_ACTIVE | MS_BORN)
234 +
235 +int aa_remount(struct aa_label *label, const struct path *path,
236 +              unsigned long flags, void *data);
237 +
238 +int aa_bind_mount(struct aa_label *label, const struct path *path,
239 +                 const char *old_name, unsigned long flags);
240 +
241 +
242 +int aa_mount_change_type(struct aa_label *label, const struct path *path,
243 +                        unsigned long flags);
244 +
245 +int aa_move_mount(struct aa_label *label, const struct path *path,
246 +                 const char *old_name);
247 +
248 +int aa_new_mount(struct aa_label *label, const char *dev_name,
249 +                const struct path *path, const char *type, unsigned long flags,
250 +                void *data);
251 +
252 +int aa_umount(struct aa_label *label, struct vfsmount *mnt, int flags);
253 +
254 +int aa_pivotroot(struct aa_label *label, const struct path *old_path,
255 +                const struct path *new_path);
256 +
257 +#endif /* __AA_MOUNT_H */
258 diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
259 index af22f3dfbcce..4ad0b3a45142 100644
260 --- a/security/apparmor/lsm.c
261 +++ b/security/apparmor/lsm.c
262 @@ -38,6 +38,7 @@
263  #include "include/policy.h"
264  #include "include/policy_ns.h"
265  #include "include/procattr.h"
266 +#include "include/mount.h"
267  
268  /* Flag indicating whether initialization completed */
269  int apparmor_initialized;
270 @@ -511,6 +512,65 @@ static int apparmor_file_mprotect(struct vm_area_struct *vma,
271                            !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
272  }
273  
274 +static int apparmor_sb_mount(const char *dev_name, const struct path *path,
275 +                            const char *type, unsigned long flags, void *data)
276 +{
277 +       struct aa_label *label;
278 +       int error = 0;
279 +
280 +       /* Discard magic */
281 +       if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
282 +               flags &= ~MS_MGC_MSK;
283 +
284 +       flags &= ~AA_MS_IGNORE_MASK;
285 +
286 +       label = __begin_current_label_crit_section();
287 +       if (!unconfined(label)) {
288 +               if (flags & MS_REMOUNT)
289 +                       error = aa_remount(label, path, flags, data);
290 +               else if (flags & MS_BIND)
291 +                       error = aa_bind_mount(label, path, dev_name, flags);
292 +               else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE |
293 +                                 MS_UNBINDABLE))
294 +                       error = aa_mount_change_type(label, path, flags);
295 +               else if (flags & MS_MOVE)
296 +                       error = aa_move_mount(label, path, dev_name);
297 +               else
298 +                       error = aa_new_mount(label, dev_name, path, type,
299 +                                            flags, data);
300 +       }
301 +       __end_current_label_crit_section(label);
302 +
303 +       return error;
304 +}
305 +
306 +static int apparmor_sb_umount(struct vfsmount *mnt, int flags)
307 +{
308 +       struct aa_label *label;
309 +       int error = 0;
310 +
311 +       label = __begin_current_label_crit_section();
312 +       if (!unconfined(label))
313 +               error = aa_umount(label, mnt, flags);
314 +       __end_current_label_crit_section(label);
315 +
316 +       return error;
317 +}
318 +
319 +static int apparmor_sb_pivotroot(const struct path *old_path,
320 +                                const struct path *new_path)
321 +{
322 +       struct aa_label *label;
323 +       int error = 0;
324 +
325 +       label = aa_get_current_label();
326 +       if (!unconfined(label))
327 +               error = aa_pivotroot(label, old_path, new_path);
328 +       aa_put_label(label);
329 +
330 +       return error;
331 +}
332 +
333  static int apparmor_getprocattr(struct task_struct *task, char *name,
334                                 char **value)
335  {
336 @@ -682,6 +742,10 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
337         LSM_HOOK_INIT(capget, apparmor_capget),
338         LSM_HOOK_INIT(capable, apparmor_capable),
339  
340 +       LSM_HOOK_INIT(sb_mount, apparmor_sb_mount),
341 +       LSM_HOOK_INIT(sb_umount, apparmor_sb_umount),
342 +       LSM_HOOK_INIT(sb_pivotroot, apparmor_sb_pivotroot),
343 +
344         LSM_HOOK_INIT(path_link, apparmor_path_link),
345         LSM_HOOK_INIT(path_unlink, apparmor_path_unlink),
346         LSM_HOOK_INIT(path_symlink, apparmor_path_symlink),
347 diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c
348 new file mode 100644
349 index 000000000000..82a64b58041d
350 --- /dev/null
351 +++ b/security/apparmor/mount.c
352 @@ -0,0 +1,696 @@
353 +/*
354 + * AppArmor security module
355 + *
356 + * This file contains AppArmor mediation of files
357 + *
358 + * Copyright (C) 1998-2008 Novell/SUSE
359 + * Copyright 2009-2017 Canonical Ltd.
360 + *
361 + * This program is free software; you can redistribute it and/or
362 + * modify it under the terms of the GNU General Public License as
363 + * published by the Free Software Foundation, version 2 of the
364 + * License.
365 + */
366 +
367 +#include <linux/fs.h>
368 +#include <linux/mount.h>
369 +#include <linux/namei.h>
370 +
371 +#include "include/apparmor.h"
372 +#include "include/audit.h"
373 +#include "include/context.h"
374 +#include "include/domain.h"
375 +#include "include/file.h"
376 +#include "include/match.h"
377 +#include "include/mount.h"
378 +#include "include/path.h"
379 +#include "include/policy.h"
380 +
381 +
382 +static void audit_mnt_flags(struct audit_buffer *ab, unsigned long flags)
383 +{
384 +       if (flags & MS_RDONLY)
385 +               audit_log_format(ab, "ro");
386 +       else
387 +               audit_log_format(ab, "rw");
388 +       if (flags & MS_NOSUID)
389 +               audit_log_format(ab, ", nosuid");
390 +       if (flags & MS_NODEV)
391 +               audit_log_format(ab, ", nodev");
392 +       if (flags & MS_NOEXEC)
393 +               audit_log_format(ab, ", noexec");
394 +       if (flags & MS_SYNCHRONOUS)
395 +               audit_log_format(ab, ", sync");
396 +       if (flags & MS_REMOUNT)
397 +               audit_log_format(ab, ", remount");
398 +       if (flags & MS_MANDLOCK)
399 +               audit_log_format(ab, ", mand");
400 +       if (flags & MS_DIRSYNC)
401 +               audit_log_format(ab, ", dirsync");
402 +       if (flags & MS_NOATIME)
403 +               audit_log_format(ab, ", noatime");
404 +       if (flags & MS_NODIRATIME)
405 +               audit_log_format(ab, ", nodiratime");
406 +       if (flags & MS_BIND)
407 +               audit_log_format(ab, flags & MS_REC ? ", rbind" : ", bind");
408 +       if (flags & MS_MOVE)
409 +               audit_log_format(ab, ", move");
410 +       if (flags & MS_SILENT)
411 +               audit_log_format(ab, ", silent");
412 +       if (flags & MS_POSIXACL)
413 +               audit_log_format(ab, ", acl");
414 +       if (flags & MS_UNBINDABLE)
415 +               audit_log_format(ab, flags & MS_REC ? ", runbindable" :
416 +                                ", unbindable");
417 +       if (flags & MS_PRIVATE)
418 +               audit_log_format(ab, flags & MS_REC ? ", rprivate" :
419 +                                ", private");
420 +       if (flags & MS_SLAVE)
421 +               audit_log_format(ab, flags & MS_REC ? ", rslave" :
422 +                                ", slave");
423 +       if (flags & MS_SHARED)
424 +               audit_log_format(ab, flags & MS_REC ? ", rshared" :
425 +                                ", shared");
426 +       if (flags & MS_RELATIME)
427 +               audit_log_format(ab, ", relatime");
428 +       if (flags & MS_I_VERSION)
429 +               audit_log_format(ab, ", iversion");
430 +       if (flags & MS_STRICTATIME)
431 +               audit_log_format(ab, ", strictatime");
432 +       if (flags & MS_NOUSER)
433 +               audit_log_format(ab, ", nouser");
434 +}
435 +
436 +/**
437 + * audit_cb - call back for mount specific audit fields
438 + * @ab: audit_buffer  (NOT NULL)
439 + * @va: audit struct to audit values of  (NOT NULL)
440 + */
441 +static void audit_cb(struct audit_buffer *ab, void *va)
442 +{
443 +       struct common_audit_data *sa = va;
444 +
445 +       if (aad(sa)->mnt.type) {
446 +               audit_log_format(ab, " fstype=");
447 +               audit_log_untrustedstring(ab, aad(sa)->mnt.type);
448 +       }
449 +       if (aad(sa)->mnt.src_name) {
450 +               audit_log_format(ab, " srcname=");
451 +               audit_log_untrustedstring(ab, aad(sa)->mnt.src_name);
452 +       }
453 +       if (aad(sa)->mnt.trans) {
454 +               audit_log_format(ab, " trans=");
455 +               audit_log_untrustedstring(ab, aad(sa)->mnt.trans);
456 +       }
457 +       if (aad(sa)->mnt.flags) {
458 +               audit_log_format(ab, " flags=\"");
459 +               audit_mnt_flags(ab, aad(sa)->mnt.flags);
460 +               audit_log_format(ab, "\"");
461 +       }
462 +       if (aad(sa)->mnt.data) {
463 +               audit_log_format(ab, " options=");
464 +               audit_log_untrustedstring(ab, aad(sa)->mnt.data);
465 +       }
466 +}
467 +
468 +/**
469 + * audit_mount - handle the auditing of mount operations
470 + * @profile: the profile being enforced  (NOT NULL)
471 + * @op: operation being mediated (NOT NULL)
472 + * @name: name of object being mediated (MAYBE NULL)
473 + * @src_name: src_name of object being mediated (MAYBE_NULL)
474 + * @type: type of filesystem (MAYBE_NULL)
475 + * @trans: name of trans (MAYBE NULL)
476 + * @flags: filesystem idependent mount flags
477 + * @data: filesystem mount flags
478 + * @request: permissions requested
479 + * @perms: the permissions computed for the request (NOT NULL)
480 + * @info: extra information message (MAYBE NULL)
481 + * @error: 0 if operation allowed else failure error code
482 + *
483 + * Returns: %0 or error on failure
484 + */
485 +static int audit_mount(struct aa_profile *profile, const char *op,
486 +                      const char *name, const char *src_name,
487 +                      const char *type, const char *trans,
488 +                      unsigned long flags, const void *data, u32 request,
489 +                      struct aa_perms *perms, const char *info, int error)
490 +{
491 +       int audit_type = AUDIT_APPARMOR_AUTO;
492 +       DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, op);
493 +
494 +       if (likely(!error)) {
495 +               u32 mask = perms->audit;
496 +
497 +               if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
498 +                       mask = 0xffff;
499 +
500 +               /* mask off perms that are not being force audited */
501 +               request &= mask;
502 +
503 +               if (likely(!request))
504 +                       return 0;
505 +               audit_type = AUDIT_APPARMOR_AUDIT;
506 +       } else {
507 +               /* only report permissions that were denied */
508 +               request = request & ~perms->allow;
509 +
510 +               if (request & perms->kill)
511 +                       audit_type = AUDIT_APPARMOR_KILL;
512 +
513 +               /* quiet known rejects, assumes quiet and kill do not overlap */
514 +               if ((request & perms->quiet) &&
515 +                   AUDIT_MODE(profile) != AUDIT_NOQUIET &&
516 +                   AUDIT_MODE(profile) != AUDIT_ALL)
517 +                       request &= ~perms->quiet;
518 +
519 +               if (!request)
520 +                       return error;
521 +       }
522 +
523 +       aad(&sa)->name = name;
524 +       aad(&sa)->mnt.src_name = src_name;
525 +       aad(&sa)->mnt.type = type;
526 +       aad(&sa)->mnt.trans = trans;
527 +       aad(&sa)->mnt.flags = flags;
528 +       if (data && (perms->audit & AA_AUDIT_DATA))
529 +               aad(&sa)->mnt.data = data;
530 +       aad(&sa)->info = info;
531 +       aad(&sa)->error = error;
532 +
533 +       return aa_audit(audit_type, profile, &sa, audit_cb);
534 +}
535 +
536 +/**
537 + * match_mnt_flags - Do an ordered match on mount flags
538 + * @dfa: dfa to match against
539 + * @state: state to start in
540 + * @flags: mount flags to match against
541 + *
542 + * Mount flags are encoded as an ordered match. This is done instead of
543 + * checking against a simple bitmask, to allow for logical operations
544 + * on the flags.
545 + *
546 + * Returns: next state after flags match
547 + */
548 +static unsigned int match_mnt_flags(struct aa_dfa *dfa, unsigned int state,
549 +                                   unsigned long flags)
550 +{
551 +       unsigned int i;
552 +
553 +       for (i = 0; i <= 31 ; ++i) {
554 +               if ((1 << i) & flags)
555 +                       state = aa_dfa_next(dfa, state, i + 1);
556 +       }
557 +
558 +       return state;
559 +}
560 +
561 +/**
562 + * compute_mnt_perms - compute mount permission associated with @state
563 + * @dfa: dfa to match against (NOT NULL)
564 + * @state: state match finished in
565 + *
566 + * Returns: mount permissions
567 + */
568 +static struct aa_perms compute_mnt_perms(struct aa_dfa *dfa,
569 +                                          unsigned int state)
570 +{
571 +       struct aa_perms perms;
572 +
573 +       perms.kill = 0;
574 +       perms.allow = dfa_user_allow(dfa, state);
575 +       perms.audit = dfa_user_audit(dfa, state);
576 +       perms.quiet = dfa_user_quiet(dfa, state);
577 +       perms.xindex = dfa_user_xindex(dfa, state);
578 +
579 +       return perms;
580 +}
581 +
582 +static const char * const mnt_info_table[] = {
583 +       "match succeeded",
584 +       "failed mntpnt match",
585 +       "failed srcname match",
586 +       "failed type match",
587 +       "failed flags match",
588 +       "failed data match"
589 +};
590 +
591 +/*
592 + * Returns 0 on success else element that match failed in, this is the
593 + * index into the mnt_info_table above
594 + */
595 +static int do_match_mnt(struct aa_dfa *dfa, unsigned int start,
596 +                       const char *mntpnt, const char *devname,
597 +                       const char *type, unsigned long flags,
598 +                       void *data, bool binary, struct aa_perms *perms)
599 +{
600 +       unsigned int state;
601 +
602 +       AA_BUG(!dfa);
603 +       AA_BUG(!perms);
604 +
605 +       state = aa_dfa_match(dfa, start, mntpnt);
606 +       state = aa_dfa_null_transition(dfa, state);
607 +       if (!state)
608 +               return 1;
609 +
610 +       if (devname)
611 +               state = aa_dfa_match(dfa, state, devname);
612 +       state = aa_dfa_null_transition(dfa, state);
613 +       if (!state)
614 +               return 2;
615 +
616 +       if (type)
617 +               state = aa_dfa_match(dfa, state, type);
618 +       state = aa_dfa_null_transition(dfa, state);
619 +       if (!state)
620 +               return 3;
621 +
622 +       state = match_mnt_flags(dfa, state, flags);
623 +       if (!state)
624 +               return 4;
625 +       *perms = compute_mnt_perms(dfa, state);
626 +       if (perms->allow & AA_MAY_MOUNT)
627 +               return 0;
628 +
629 +       /* only match data if not binary and the DFA flags data is expected */
630 +       if (data && !binary && (perms->allow & AA_MNT_CONT_MATCH)) {
631 +               state = aa_dfa_null_transition(dfa, state);
632 +               if (!state)
633 +                       return 4;
634 +
635 +               state = aa_dfa_match(dfa, state, data);
636 +               if (!state)
637 +                       return 5;
638 +               *perms = compute_mnt_perms(dfa, state);
639 +               if (perms->allow & AA_MAY_MOUNT)
640 +                       return 0;
641 +       }
642 +
643 +       /* failed at end of flags match */
644 +       return 4;
645 +}
646 +
647 +
648 +static int path_flags(struct aa_profile *profile, const struct path *path)
649 +{
650 +       AA_BUG(!profile);
651 +       AA_BUG(!path);
652 +
653 +       return profile->path_flags |
654 +               (S_ISDIR(path->dentry->d_inode->i_mode) ? PATH_IS_DIR : 0);
655 +}
656 +
657 +/**
658 + * match_mnt_path_str - handle path matching for mount
659 + * @profile: the confining profile
660 + * @mntpath: for the mntpnt (NOT NULL)
661 + * @buffer: buffer to be used to lookup mntpath
662 + * @devnme: string for the devname/src_name (MAY BE NULL OR ERRPTR)
663 + * @type: string for the dev type (MAYBE NULL)
664 + * @flags: mount flags to match
665 + * @data: fs mount data (MAYBE NULL)
666 + * @binary: whether @data is binary
667 + * @devinfo: error str if (IS_ERR(@devname))
668 + *
669 + * Returns: 0 on success else error
670 + */
671 +static int match_mnt_path_str(struct aa_profile *profile,
672 +                             const struct path *mntpath, char *buffer,
673 +                             const char *devname, const char *type,
674 +                             unsigned long flags, void *data, bool binary,
675 +                             const char *devinfo)
676 +{
677 +       struct aa_perms perms = { };
678 +       const char *mntpnt = NULL, *info = NULL;
679 +       int pos, error;
680 +
681 +       AA_BUG(!profile);
682 +       AA_BUG(!mntpath);
683 +       AA_BUG(!buffer);
684 +
685 +       error = aa_path_name(mntpath, path_flags(profile, mntpath), buffer,
686 +                            &mntpnt, &info, profile->disconnected);
687 +       if (error)
688 +               goto audit;
689 +       if (IS_ERR(devname)) {
690 +               error = PTR_ERR(devname);
691 +               devname = NULL;
692 +               info = devinfo;
693 +               goto audit;
694 +       }
695 +
696 +       error = -EACCES;
697 +       pos = do_match_mnt(profile->policy.dfa,
698 +                          profile->policy.start[AA_CLASS_MOUNT],
699 +                          mntpnt, devname, type, flags, data, binary, &perms);
700 +       if (pos) {
701 +               info = mnt_info_table[pos];
702 +               goto audit;
703 +       }
704 +       error = 0;
705 +
706 +audit:
707 +       return audit_mount(profile, OP_MOUNT, mntpnt, devname, type, NULL,
708 +                          flags, data, AA_MAY_MOUNT, &perms, info, error);
709 +}
710 +
711 +/**
712 + * match_mnt - handle path matching for mount
713 + * @profile: the confining profile
714 + * @mntpath: for the mntpnt (NOT NULL)
715 + * @buffer: buffer to be used to lookup mntpath
716 + * @devpath: path devname/src_name (MAYBE NULL)
717 + * @devbuffer: buffer to be used to lookup devname/src_name
718 + * @type: string for the dev type (MAYBE NULL)
719 + * @flags: mount flags to match
720 + * @data: fs mount data (MAYBE NULL)
721 + * @binary: whether @data is binary
722 + *
723 + * Returns: 0 on success else error
724 + */
725 +static int match_mnt(struct aa_profile *profile, const struct path *path,
726 +                    char *buffer, struct path *devpath, char *devbuffer,
727 +                    const char *type, unsigned long flags, void *data,
728 +                    bool binary)
729 +{
730 +       const char *devname = NULL, *info = NULL;
731 +       int error = -EACCES;
732 +
733 +       AA_BUG(!profile);
734 +       AA_BUG(devpath && !devbuffer);
735 +
736 +       if (devpath) {
737 +               error = aa_path_name(devpath, path_flags(profile, devpath),
738 +                                    devbuffer, &devname, &info,
739 +                                    profile->disconnected);
740 +               if (error)
741 +                       devname = ERR_PTR(error);
742 +       }
743 +
744 +       return match_mnt_path_str(profile, path, buffer, devname, type, flags,
745 +                                 data, binary, info);
746 +}
747 +
748 +int aa_remount(struct aa_label *label, const struct path *path,
749 +              unsigned long flags, void *data)
750 +{
751 +       struct aa_profile *profile;
752 +       char *buffer = NULL;
753 +       bool binary;
754 +       int error;
755 +
756 +       AA_BUG(!label);
757 +       AA_BUG(!path);
758 +
759 +       binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA;
760 +
761 +       get_buffers(buffer);
762 +       error = fn_for_each_confined(label, profile,
763 +                       match_mnt(profile, path, buffer, NULL, NULL, NULL,
764 +                                 flags, data, binary));
765 +       put_buffers(buffer);
766 +
767 +       return error;
768 +}
769 +
770 +int aa_bind_mount(struct aa_label *label, const struct path *path,
771 +                 const char *dev_name, unsigned long flags)
772 +{
773 +       struct aa_profile *profile;
774 +       char *buffer = NULL, *old_buffer = NULL;
775 +       struct path old_path;
776 +       int error;
777 +
778 +       AA_BUG(!label);
779 +       AA_BUG(!path);
780 +
781 +       if (!dev_name || !*dev_name)
782 +               return -EINVAL;
783 +
784 +       flags &= MS_REC | MS_BIND;
785 +
786 +       error = kern_path(dev_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
787 +       if (error)
788 +               return error;
789 +
790 +       get_buffers(buffer, old_buffer);
791 +       error = fn_for_each_confined(label, profile,
792 +                       match_mnt(profile, path, buffer, &old_path, old_buffer,
793 +                                 NULL, flags, NULL, false));
794 +       put_buffers(buffer, old_buffer);
795 +       path_put(&old_path);
796 +
797 +       return error;
798 +}
799 +
800 +int aa_mount_change_type(struct aa_label *label, const struct path *path,
801 +                        unsigned long flags)
802 +{
803 +       struct aa_profile *profile;
804 +       char *buffer = NULL;
805 +       int error;
806 +
807 +       AA_BUG(!label);
808 +       AA_BUG(!path);
809 +
810 +       /* These are the flags allowed by do_change_type() */
811 +       flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE |
812 +                 MS_UNBINDABLE);
813 +
814 +       get_buffers(buffer);
815 +       error = fn_for_each_confined(label, profile,
816 +                       match_mnt(profile, path, buffer, NULL, NULL, NULL,
817 +                                 flags, NULL, false));
818 +       put_buffers(buffer);
819 +
820 +       return error;
821 +}
822 +
823 +int aa_move_mount(struct aa_label *label, const struct path *path,
824 +                 const char *orig_name)
825 +{
826 +       struct aa_profile *profile;
827 +       char *buffer = NULL, *old_buffer = NULL;
828 +       struct path old_path;
829 +       int error;
830 +
831 +       AA_BUG(!label);
832 +       AA_BUG(!path);
833 +
834 +       if (!orig_name || !*orig_name)
835 +               return -EINVAL;
836 +
837 +       error = kern_path(orig_name, LOOKUP_FOLLOW, &old_path);
838 +       if (error)
839 +               return error;
840 +
841 +       get_buffers(buffer, old_buffer);
842 +       error = fn_for_each_confined(label, profile,
843 +                       match_mnt(profile, path, buffer, &old_path, old_buffer,
844 +                                 NULL, MS_MOVE, NULL, false));
845 +       put_buffers(buffer, old_buffer);
846 +       path_put(&old_path);
847 +
848 +       return error;
849 +}
850 +
851 +int aa_new_mount(struct aa_label *label, const char *dev_name,
852 +                const struct path *path, const char *type, unsigned long flags,
853 +                void *data)
854 +{
855 +       struct aa_profile *profile;
856 +       char *buffer = NULL, *dev_buffer = NULL;
857 +       bool binary = true;
858 +       int error;
859 +       int requires_dev = 0;
860 +       struct path tmp_path, *dev_path = NULL;
861 +
862 +       AA_BUG(!label);
863 +       AA_BUG(!path);
864 +
865 +       if (type) {
866 +               struct file_system_type *fstype;
867 +
868 +               fstype = get_fs_type(type);
869 +               if (!fstype)
870 +                       return -ENODEV;
871 +               binary = fstype->fs_flags & FS_BINARY_MOUNTDATA;
872 +               requires_dev = fstype->fs_flags & FS_REQUIRES_DEV;
873 +               put_filesystem(fstype);
874 +
875 +               if (requires_dev) {
876 +                       if (!dev_name || !*dev_name)
877 +                               return -ENOENT;
878 +
879 +                       error = kern_path(dev_name, LOOKUP_FOLLOW, &tmp_path);
880 +                       if (error)
881 +                               return error;
882 +                       dev_path = &tmp_path;
883 +               }
884 +       }
885 +
886 +       get_buffers(buffer, dev_buffer);
887 +       if (dev_path) {
888 +               error = fn_for_each_confined(label, profile,
889 +                       match_mnt(profile, path, buffer, dev_path, dev_buffer,
890 +                                 type, flags, data, binary));
891 +       } else {
892 +               error = fn_for_each_confined(label, profile,
893 +                       match_mnt_path_str(profile, path, buffer, dev_name,
894 +                                          type, flags, data, binary, NULL));
895 +       }
896 +       put_buffers(buffer, dev_buffer);
897 +       if (dev_path)
898 +               path_put(dev_path);
899 +
900 +       return error;
901 +}
902 +
903 +static int profile_umount(struct aa_profile *profile, struct path *path,
904 +                         char *buffer)
905 +{
906 +       struct aa_perms perms = { };
907 +       const char *name = NULL, *info = NULL;
908 +       unsigned int state;
909 +       int error;
910 +
911 +       AA_BUG(!profile);
912 +       AA_BUG(!path);
913 +
914 +       error = aa_path_name(path, path_flags(profile, path), buffer, &name,
915 +                            &info, profile->disconnected);
916 +       if (error)
917 +               goto audit;
918 +
919 +       state = aa_dfa_match(profile->policy.dfa,
920 +                            profile->policy.start[AA_CLASS_MOUNT],
921 +                            name);
922 +       perms = compute_mnt_perms(profile->policy.dfa, state);
923 +       if (AA_MAY_UMOUNT & ~perms.allow)
924 +               error = -EACCES;
925 +
926 +audit:
927 +       return audit_mount(profile, OP_UMOUNT, name, NULL, NULL, NULL, 0, NULL,
928 +                          AA_MAY_UMOUNT, &perms, info, error);
929 +}
930 +
931 +int aa_umount(struct aa_label *label, struct vfsmount *mnt, int flags)
932 +{
933 +       struct aa_profile *profile;
934 +       char *buffer = NULL;
935 +       int error;
936 +       struct path path = { .mnt = mnt, .dentry = mnt->mnt_root };
937 +
938 +       AA_BUG(!label);
939 +       AA_BUG(!mnt);
940 +
941 +       get_buffers(buffer);
942 +       error = fn_for_each_confined(label, profile,
943 +                       profile_umount(profile, &path, buffer));
944 +       put_buffers(buffer);
945 +
946 +       return error;
947 +}
948 +
949 +/* helper fn for transition on pivotroot
950 + *
951 + * Returns: label for transition or ERR_PTR. Does not return NULL
952 + */
953 +static struct aa_label *build_pivotroot(struct aa_profile *profile,
954 +                                       const struct path *new_path,
955 +                                       char *new_buffer,
956 +                                       const struct path *old_path,
957 +                                       char *old_buffer)
958 +{
959 +       const char *old_name, *new_name = NULL, *info = NULL;
960 +       const char *trans_name = NULL;
961 +       struct aa_perms perms = { };
962 +       unsigned int state;
963 +       int error;
964 +
965 +       AA_BUG(!profile);
966 +       AA_BUG(!new_path);
967 +       AA_BUG(!old_path);
968 +
969 +       if (profile_unconfined(profile))
970 +               return aa_get_newest_label(&profile->label);
971 +
972 +       error = aa_path_name(old_path, path_flags(profile, old_path),
973 +                            old_buffer, &old_name, &info,
974 +                            profile->disconnected);
975 +       if (error)
976 +               goto audit;
977 +       error = aa_path_name(new_path, path_flags(profile, new_path),
978 +                            new_buffer, &new_name, &info,
979 +                            profile->disconnected);
980 +       if (error)
981 +               goto audit;
982 +
983 +       error = -EACCES;
984 +       state = aa_dfa_match(profile->policy.dfa,
985 +                            profile->policy.start[AA_CLASS_MOUNT],
986 +                            new_name);
987 +       state = aa_dfa_null_transition(profile->policy.dfa, state);
988 +       state = aa_dfa_match(profile->policy.dfa, state, old_name);
989 +       perms = compute_mnt_perms(profile->policy.dfa, state);
990 +
991 +       if (AA_MAY_PIVOTROOT & perms.allow)
992 +               error = 0;
993 +
994 +audit:
995 +       error = audit_mount(profile, OP_PIVOTROOT, new_name, old_name,
996 +                           NULL, trans_name, 0, NULL, AA_MAY_PIVOTROOT,
997 +                           &perms, info, error);
998 +       if (error)
999 +               return ERR_PTR(error);
1000 +
1001 +       return aa_get_newest_label(&profile->label);
1002 +}
1003 +
1004 +int aa_pivotroot(struct aa_label *label, const struct path *old_path,
1005 +                const struct path *new_path)
1006 +{
1007 +       struct aa_profile *profile;
1008 +       struct aa_label *target = NULL;
1009 +       char *old_buffer = NULL, *new_buffer = NULL, *info = NULL;
1010 +       int error;
1011 +
1012 +       AA_BUG(!label);
1013 +       AA_BUG(!old_path);
1014 +       AA_BUG(!new_path);
1015 +
1016 +       get_buffers(old_buffer, new_buffer);
1017 +       target = fn_label_build(label, profile, GFP_ATOMIC,
1018 +                       build_pivotroot(profile, new_path, new_buffer,
1019 +                                       old_path, old_buffer));
1020 +       if (!target) {
1021 +               info = "label build failed";
1022 +               error = -ENOMEM;
1023 +               goto fail;
1024 +       } else if (!IS_ERR(target)) {
1025 +               error = aa_replace_current_label(target);
1026 +               if (error) {
1027 +                       /* TODO: audit target */
1028 +                       aa_put_label(target);
1029 +                       goto out;
1030 +               }
1031 +       } else
1032 +               /* already audited error */
1033 +               error = PTR_ERR(target);
1034 +out:
1035 +       put_buffers(old_buffer, new_buffer);
1036 +
1037 +       return error;
1038 +
1039 +fail:
1040 +       /* TODO: add back in auditing of new_name and old_name */
1041 +       error = fn_for_each(label, profile,
1042 +                       audit_mount(profile, OP_PIVOTROOT, NULL /*new_name */,
1043 +                                   NULL /* old_name */,
1044 +                                   NULL, NULL,
1045 +                                   0, NULL, AA_MAY_PIVOTROOT, &nullperms, info,
1046 +                                   error));
1047 +       goto out;
1048 +}
1049 -- 
1050 2.11.0
1051
This page took 0.108362 seconds and 3 git commands to generate.