]> git.pld-linux.org Git - packages/kernel.git/blob - kernel-apparmor.patch
- fix vserver patch for 3.14.5
[packages/kernel.git] / kernel-apparmor.patch
1 From d29d73fa5d7b5d016f9c17236fff2a741acea247 Mon Sep 17 00:00:00 2001
2 From: John Johansen <john.johansen@canonical.com>
3 Date: Mon, 4 Oct 2010 15:03:36 -0700
4 Subject: [PATCH 1/3] UBUNTU: SAUCE: AppArmor: basic networking rules
5
6 Base support for network mediation.
7
8 Signed-off-by: John Johansen <john.johansen@canonical.com>
9
10 Conflicts:
11         security/apparmor/Makefile
12         security/apparmor/policy.c
13 ---
14  security/apparmor/.gitignore       |   1 +
15  security/apparmor/Makefile         |  42 +++++++++-
16  security/apparmor/apparmorfs.c     |   1 +
17  security/apparmor/include/audit.h  |   4 +
18  security/apparmor/include/net.h    |  44 ++++++++++
19  security/apparmor/include/policy.h |   3 +
20  security/apparmor/lsm.c            | 112 +++++++++++++++++++++++++
21  security/apparmor/net.c            | 162 +++++++++++++++++++++++++++++++++++++
22  security/apparmor/policy.c         |   1 +
23  security/apparmor/policy_unpack.c  |  46 +++++++++++
24  10 files changed, 414 insertions(+), 2 deletions(-)
25  create mode 100644 security/apparmor/include/net.h
26  create mode 100644 security/apparmor/net.c
27
28 diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore
29 index 9cdec70..d5b291e 100644
30 --- a/security/apparmor/.gitignore
31 +++ b/security/apparmor/.gitignore
32 @@ -1,5 +1,6 @@
33  #
34  # Generated include files
35  #
36 +net_names.h
37  capability_names.h
38  rlim_names.h
39 diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
40 index d693df8..5dbb72f 100644
41 --- a/security/apparmor/Makefile
42 +++ b/security/apparmor/Makefile
43 @@ -4,10 +4,10 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
44  
45  apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
46                path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
47 -              resource.o sid.o file.o
48 +              resource.o sid.o file.o net.o
49  apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
50  
51 -clean-files := capability_names.h rlim_names.h
52 +clean-files := capability_names.h rlim_names.h net_names.h
53  
54  
55  # Build a lower case string table of capability names
56 @@ -25,6 +25,38 @@ cmd_make-caps = echo "static const char *const capability_names[] = {" > $@ ;\
57             -e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/\L\1/p' | \
58              tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
59  
60 +# Build a lower case string table of address family names
61 +# Transform lines from
62 +#    define AF_LOCAL   1       /* POSIX name for AF_UNIX       */
63 +#    #define AF_INET           2       /* Internet IP Protocol         */
64 +# to
65 +#    [1] = "local",
66 +#    [2] = "inet",
67 +#
68 +# and build the securityfs entries for the mapping.
69 +# Transforms lines from
70 +#    #define AF_INET           2       /* Internet IP Protocol         */
71 +# to
72 +#    #define AA_FS_AF_MASK "local inet"
73 +quiet_cmd_make-af = GEN     $@
74 +cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\
75 +       sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e \
76 +        's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
77 +       echo "};" >> $@ ;\
78 +       echo -n '\#define AA_FS_AF_MASK "' >> $@ ;\
79 +       sed -r -n 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\
80 +        $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
81 +
82 +# Build a lower case string table of sock type names
83 +# Transform lines from
84 +#    SOCK_STREAM       = 1,
85 +# to
86 +#    [1] = "stream",
87 +quiet_cmd_make-sock = GEN     $@
88 +cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\
89 +       sed $^ >>$@ -r -n \
90 +       -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
91 +       echo "};" >> $@
92  
93  # Build a lower case string table of rlimit names.
94  # Transforms lines from
95 @@ -61,6 +93,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \
96             tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
97  
98  $(obj)/capability.o : $(obj)/capability_names.h
99 +$(obj)/net.o : $(obj)/net_names.h
100  $(obj)/resource.o : $(obj)/rlim_names.h
101  $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
102                             $(src)/Makefile
103 @@ -68,3 +101,8 @@ $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
104  $(obj)/rlim_names.h : $(srctree)/include/uapi/asm-generic/resource.h \
105                       $(src)/Makefile
106         $(call cmd,make-rlim)
107 +$(obj)/net_names.h : $(srctree)/include/linux/socket.h \
108 +                    $(srctree)/include/linux/net.h \
109 +                    $(src)/Makefile
110 +       $(call cmd,make-af)
111 +       $(call cmd,make-sock)
112 diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
113 index 7db9954..18fc02c 100644
114 --- a/security/apparmor/apparmorfs.c
115 +++ b/security/apparmor/apparmorfs.c
116 @@ -806,6 +806,7 @@ static struct aa_fs_entry aa_fs_entry_features[] = {
117         AA_FS_DIR("policy",                     aa_fs_entry_policy),
118         AA_FS_DIR("domain",                     aa_fs_entry_domain),
119         AA_FS_DIR("file",                       aa_fs_entry_file),
120 +       AA_FS_DIR("network",                    aa_fs_entry_network),
121         AA_FS_FILE_U64("capability",            VFS_CAP_FLAGS_MASK),
122         AA_FS_DIR("rlimit",                     aa_fs_entry_rlimit),
123         AA_FS_DIR("caps",                       aa_fs_entry_caps),
124 diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
125 index 30e8d76..61abec5 100644
126 --- a/security/apparmor/include/audit.h
127 +++ b/security/apparmor/include/audit.h
128 @@ -126,6 +126,10 @@ struct apparmor_audit_data {
129                         u32 denied;
130                         kuid_t ouid;
131                 } fs;
132 +               struct {
133 +                       int type, protocol;
134 +                       struct sock *sk;
135 +               } net;
136         };
137  };
138  
139 diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
140 new file mode 100644
141 index 0000000..cb8a121
142 --- /dev/null
143 +++ b/security/apparmor/include/net.h
144 @@ -0,0 +1,44 @@
145 +/*
146 + * AppArmor security module
147 + *
148 + * This file contains AppArmor network mediation definitions.
149 + *
150 + * Copyright (C) 1998-2008 Novell/SUSE
151 + * Copyright 2009-2012 Canonical Ltd.
152 + *
153 + * This program is free software; you can redistribute it and/or
154 + * modify it under the terms of the GNU General Public License as
155 + * published by the Free Software Foundation, version 2 of the
156 + * License.
157 + */
158 +
159 +#ifndef __AA_NET_H
160 +#define __AA_NET_H
161 +
162 +#include <net/sock.h>
163 +
164 +#include "apparmorfs.h"
165 +
166 +/* struct aa_net - network confinement data
167 + * @allowed: basic network families permissions
168 + * @audit_network: which network permissions to force audit
169 + * @quiet_network: which network permissions to quiet rejects
170 + */
171 +struct aa_net {
172 +       u16 allow[AF_MAX];
173 +       u16 audit[AF_MAX];
174 +       u16 quiet[AF_MAX];
175 +};
176 +
177 +extern struct aa_fs_entry aa_fs_entry_network[];
178 +
179 +extern int aa_net_perm(int op, struct aa_profile *profile, u16 family,
180 +                      int type, int protocol, struct sock *sk);
181 +extern int aa_revalidate_sk(int op, struct sock *sk);
182 +
183 +static inline void aa_free_net_rules(struct aa_net *new)
184 +{
185 +       /* NOP */
186 +}
187 +
188 +#endif /* __AA_NET_H */
189 diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
190 index c28b0f2..b524d88 100644
191 --- a/security/apparmor/include/policy.h
192 +++ b/security/apparmor/include/policy.h
193 @@ -27,6 +27,7 @@
194  #include "capability.h"
195  #include "domain.h"
196  #include "file.h"
197 +#include "net.h"
198  #include "resource.h"
199  
200  extern const char *const aa_profile_mode_names[];
201 @@ -176,6 +177,7 @@ struct aa_replacedby {
202   * @policy: general match rules governing policy
203   * @file: The set of rules governing basic file access and domain transitions
204   * @caps: capabilities for the profile
205 + * @net: network controls for the profile
206   * @rlimits: rlimits for the profile
207   *
208   * @dents: dentries for the profiles file entries in apparmorfs
209 @@ -217,6 +219,7 @@ struct aa_profile {
210         struct aa_policydb policy;
211         struct aa_file_rules file;
212         struct aa_caps caps;
213 +       struct aa_net net;
214         struct aa_rlimit rlimits;
215  
216         unsigned char *hash;
217 diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
218 index fb99e18..de55a7f 100644
219 --- a/security/apparmor/lsm.c
220 +++ b/security/apparmor/lsm.c
221 @@ -32,6 +32,7 @@
222  #include "include/context.h"
223  #include "include/file.h"
224  #include "include/ipc.h"
225 +#include "include/net.h"
226  #include "include/path.h"
227  #include "include/policy.h"
228  #include "include/procattr.h"
229 @@ -615,6 +616,104 @@ static int apparmor_task_setrlimit(struct task_struct *task,
230         return error;
231  }
232  
233 +static int apparmor_socket_create(int family, int type, int protocol, int kern)
234 +{
235 +       struct aa_profile *profile;
236 +       int error = 0;
237 +
238 +       if (kern)
239 +               return 0;
240 +
241 +       profile = __aa_current_profile();
242 +       if (!unconfined(profile))
243 +               error = aa_net_perm(OP_CREATE, profile, family, type, protocol,
244 +                                   NULL);
245 +       return error;
246 +}
247 +
248 +static int apparmor_socket_bind(struct socket *sock,
249 +                               struct sockaddr *address, int addrlen)
250 +{
251 +       struct sock *sk = sock->sk;
252 +
253 +       return aa_revalidate_sk(OP_BIND, sk);
254 +}
255 +
256 +static int apparmor_socket_connect(struct socket *sock,
257 +                                  struct sockaddr *address, int addrlen)
258 +{
259 +       struct sock *sk = sock->sk;
260 +
261 +       return aa_revalidate_sk(OP_CONNECT, sk);
262 +}
263 +
264 +static int apparmor_socket_listen(struct socket *sock, int backlog)
265 +{
266 +       struct sock *sk = sock->sk;
267 +
268 +       return aa_revalidate_sk(OP_LISTEN, sk);
269 +}
270 +
271 +static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
272 +{
273 +       struct sock *sk = sock->sk;
274 +
275 +       return aa_revalidate_sk(OP_ACCEPT, sk);
276 +}
277 +
278 +static int apparmor_socket_sendmsg(struct socket *sock,
279 +                                  struct msghdr *msg, int size)
280 +{
281 +       struct sock *sk = sock->sk;
282 +
283 +       return aa_revalidate_sk(OP_SENDMSG, sk);
284 +}
285 +
286 +static int apparmor_socket_recvmsg(struct socket *sock,
287 +                                  struct msghdr *msg, int size, int flags)
288 +{
289 +       struct sock *sk = sock->sk;
290 +
291 +       return aa_revalidate_sk(OP_RECVMSG, sk);
292 +}
293 +
294 +static int apparmor_socket_getsockname(struct socket *sock)
295 +{
296 +       struct sock *sk = sock->sk;
297 +
298 +       return aa_revalidate_sk(OP_GETSOCKNAME, sk);
299 +}
300 +
301 +static int apparmor_socket_getpeername(struct socket *sock)
302 +{
303 +       struct sock *sk = sock->sk;
304 +
305 +       return aa_revalidate_sk(OP_GETPEERNAME, sk);
306 +}
307 +
308 +static int apparmor_socket_getsockopt(struct socket *sock, int level,
309 +                                     int optname)
310 +{
311 +       struct sock *sk = sock->sk;
312 +
313 +       return aa_revalidate_sk(OP_GETSOCKOPT, sk);
314 +}
315 +
316 +static int apparmor_socket_setsockopt(struct socket *sock, int level,
317 +                                     int optname)
318 +{
319 +       struct sock *sk = sock->sk;
320 +
321 +       return aa_revalidate_sk(OP_SETSOCKOPT, sk);
322 +}
323 +
324 +static int apparmor_socket_shutdown(struct socket *sock, int how)
325 +{
326 +       struct sock *sk = sock->sk;
327 +
328 +       return aa_revalidate_sk(OP_SOCK_SHUTDOWN, sk);
329 +}
330 +
331  static struct security_operations apparmor_ops = {
332         .name =                         "apparmor",
333  
334 @@ -647,6 +746,19 @@ static struct security_operations apparmor_ops = {
335         .getprocattr =                  apparmor_getprocattr,
336         .setprocattr =                  apparmor_setprocattr,
337  
338 +       .socket_create =                apparmor_socket_create,
339 +       .socket_bind =                  apparmor_socket_bind,
340 +       .socket_connect =               apparmor_socket_connect,
341 +       .socket_listen =                apparmor_socket_listen,
342 +       .socket_accept =                apparmor_socket_accept,
343 +       .socket_sendmsg =               apparmor_socket_sendmsg,
344 +       .socket_recvmsg =               apparmor_socket_recvmsg,
345 +       .socket_getsockname =           apparmor_socket_getsockname,
346 +       .socket_getpeername =           apparmor_socket_getpeername,
347 +       .socket_getsockopt =            apparmor_socket_getsockopt,
348 +       .socket_setsockopt =            apparmor_socket_setsockopt,
349 +       .socket_shutdown =              apparmor_socket_shutdown,
350 +
351         .cred_alloc_blank =             apparmor_cred_alloc_blank,
352         .cred_free =                    apparmor_cred_free,
353         .cred_prepare =                 apparmor_cred_prepare,
354 diff --git a/security/apparmor/net.c b/security/apparmor/net.c
355 new file mode 100644
356 index 0000000..003dd18
357 --- /dev/null
358 +++ b/security/apparmor/net.c
359 @@ -0,0 +1,162 @@
360 +/*
361 + * AppArmor security module
362 + *
363 + * This file contains AppArmor network mediation
364 + *
365 + * Copyright (C) 1998-2008 Novell/SUSE
366 + * Copyright 2009-2012 Canonical Ltd.
367 + *
368 + * This program is free software; you can redistribute it and/or
369 + * modify it under the terms of the GNU General Public License as
370 + * published by the Free Software Foundation, version 2 of the
371 + * License.
372 + */
373 +
374 +#include "include/apparmor.h"
375 +#include "include/audit.h"
376 +#include "include/context.h"
377 +#include "include/net.h"
378 +#include "include/policy.h"
379 +
380 +#include "net_names.h"
381 +
382 +struct aa_fs_entry aa_fs_entry_network[] = {
383 +       AA_FS_FILE_STRING("af_mask", AA_FS_AF_MASK),
384 +       { }
385 +};
386 +
387 +/* audit callback for net specific fields */
388 +static void audit_cb(struct audit_buffer *ab, void *va)
389 +{
390 +       struct common_audit_data *sa = va;
391 +
392 +       audit_log_format(ab, " family=");
393 +       if (address_family_names[sa->u.net->family]) {
394 +               audit_log_string(ab, address_family_names[sa->u.net->family]);
395 +       } else {
396 +               audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family);
397 +       }
398 +       audit_log_format(ab, " sock_type=");
399 +       if (sock_type_names[sa->aad->net.type]) {
400 +               audit_log_string(ab, sock_type_names[sa->aad->net.type]);
401 +       } else {
402 +               audit_log_format(ab, "\"unknown(%d)\"", sa->aad->net.type);
403 +       }
404 +       audit_log_format(ab, " protocol=%d", sa->aad->net.protocol);
405 +}
406 +
407 +/**
408 + * audit_net - audit network access
409 + * @profile: profile being enforced  (NOT NULL)
410 + * @op: operation being checked
411 + * @family: network family
412 + * @type:   network type
413 + * @protocol: network protocol
414 + * @sk: socket auditing is being applied to
415 + * @error: error code for failure else 0
416 + *
417 + * Returns: %0 or sa->error else other errorcode on failure
418 + */
419 +static int audit_net(struct aa_profile *profile, int op, u16 family, int type,
420 +                    int protocol, struct sock *sk, int error)
421 +{
422 +       int audit_type = AUDIT_APPARMOR_AUTO;
423 +       struct common_audit_data sa;
424 +       struct apparmor_audit_data aad = { };
425 +       struct lsm_network_audit net = { };
426 +       if (sk) {
427 +               sa.type = LSM_AUDIT_DATA_NET;
428 +       } else {
429 +               sa.type = LSM_AUDIT_DATA_NONE;
430 +       }
431 +       /* todo fill in socket addr info */
432 +       sa.aad = &aad;
433 +       sa.u.net = &net;
434 +       sa.aad->op = op,
435 +       sa.u.net->family = family;
436 +       sa.u.net->sk = sk;
437 +       sa.aad->net.type = type;
438 +       sa.aad->net.protocol = protocol;
439 +       sa.aad->error = error;
440 +
441 +       if (likely(!sa.aad->error)) {
442 +               u16 audit_mask = profile->net.audit[sa.u.net->family];
443 +               if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
444 +                          !(1 << sa.aad->net.type & audit_mask)))
445 +                       return 0;
446 +               audit_type = AUDIT_APPARMOR_AUDIT;
447 +       } else {
448 +               u16 quiet_mask = profile->net.quiet[sa.u.net->family];
449 +               u16 kill_mask = 0;
450 +               u16 denied = (1 << sa.aad->net.type) & ~quiet_mask;
451 +
452 +               if (denied & kill_mask)
453 +                       audit_type = AUDIT_APPARMOR_KILL;
454 +
455 +               if ((denied & quiet_mask) &&
456 +                   AUDIT_MODE(profile) != AUDIT_NOQUIET &&
457 +                   AUDIT_MODE(profile) != AUDIT_ALL)
458 +                       return COMPLAIN_MODE(profile) ? 0 : sa.aad->error;
459 +       }
460 +
461 +       return aa_audit(audit_type, profile, GFP_KERNEL, &sa, audit_cb);
462 +}
463 +
464 +/**
465 + * aa_net_perm - very course network access check
466 + * @op: operation being checked
467 + * @profile: profile being enforced  (NOT NULL)
468 + * @family: network family
469 + * @type:   network type
470 + * @protocol: network protocol
471 + *
472 + * Returns: %0 else error if permission denied
473 + */
474 +int aa_net_perm(int op, struct aa_profile *profile, u16 family, int type,
475 +               int protocol, struct sock *sk)
476 +{
477 +       u16 family_mask;
478 +       int error;
479 +
480 +       if ((family < 0) || (family >= AF_MAX))
481 +               return -EINVAL;
482 +
483 +       if ((type < 0) || (type >= SOCK_MAX))
484 +               return -EINVAL;
485 +
486 +       /* unix domain and netlink sockets are handled by ipc */
487 +       if (family == AF_UNIX || family == AF_NETLINK)
488 +               return 0;
489 +
490 +       family_mask = profile->net.allow[family];
491 +
492 +       error = (family_mask & (1 << type)) ? 0 : -EACCES;
493 +
494 +       return audit_net(profile, op, family, type, protocol, sk, error);
495 +}
496 +
497 +/**
498 + * aa_revalidate_sk - Revalidate access to a sock
499 + * @op: operation being checked
500 + * @sk: sock being revalidated  (NOT NULL)
501 + *
502 + * Returns: %0 else error if permission denied
503 + */
504 +int aa_revalidate_sk(int op, struct sock *sk)
505 +{
506 +       struct aa_profile *profile;
507 +       int error = 0;
508 +
509 +       /* aa_revalidate_sk should not be called from interrupt context
510 +        * don't mediate these calls as they are not task related
511 +        */
512 +       if (in_interrupt())
513 +               return 0;
514 +
515 +       profile = __aa_current_profile();
516 +       if (!unconfined(profile))
517 +               error = aa_net_perm(op, profile, sk->sk_family, sk->sk_type,
518 +                                   sk->sk_protocol, sk);
519 +
520 +       return error;
521 +}
522 diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
523 index 705c287..e2afe29 100644
524 --- a/security/apparmor/policy.c
525 +++ b/security/apparmor/policy.c
526 @@ -603,6 +603,7 @@ void aa_free_profile(struct aa_profile *profile)
527  
528         aa_free_file_rules(&profile->file);
529         aa_free_cap_rules(&profile->caps);
530 +       aa_free_net_rules(&profile->net);
531         aa_free_rlimit_rules(&profile->rlimits);
532  
533         kzfree(profile->dirname);
534 diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
535 index a689f10..1a35e6b 100644
536 --- a/security/apparmor/policy_unpack.c
537 +++ b/security/apparmor/policy_unpack.c
538 @@ -193,6 +193,19 @@ fail:
539         return 0;
540  }
541  
542 +static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name)
543 +{
544 +       if (unpack_nameX(e, AA_U16, name)) {
545 +               if (!inbounds(e, sizeof(u16)))
546 +                       return 0;
547 +               if (data)
548 +                       *data = le16_to_cpu(get_unaligned((u16 *) e->pos));
549 +               e->pos += sizeof(u16);
550 +               return 1;
551 +       }
552 +       return 0;
553 +}
554 +
555  static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
556  {
557         if (unpack_nameX(e, AA_U32, name)) {
558 @@ -476,6 +489,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
559  {
560         struct aa_profile *profile = NULL;
561         const char *name = NULL;
562 +       size_t size = 0;
563         int i, error = -EPROTO;
564         kernel_cap_t tmpcap;
565         u32 tmp;
566 @@ -576,6 +590,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
567         if (!unpack_rlimits(e, profile))
568                 goto fail;
569  
570 +       size = unpack_array(e, "net_allowed_af");
571 +       if (size) {
572 +
573 +               for (i = 0; i < size; i++) {
574 +                       /* discard extraneous rules that this kernel will
575 +                        * never request
576 +                        */
577 +                       if (i >= AF_MAX) {
578 +                               u16 tmp;
579 +                               if (!unpack_u16(e, &tmp, NULL) ||
580 +                                   !unpack_u16(e, &tmp, NULL) ||
581 +                                   !unpack_u16(e, &tmp, NULL))
582 +                                       goto fail;
583 +                               continue;
584 +                       }
585 +                       if (!unpack_u16(e, &profile->net.allow[i], NULL))
586 +                               goto fail;
587 +                       if (!unpack_u16(e, &profile->net.audit[i], NULL))
588 +                               goto fail;
589 +                       if (!unpack_u16(e, &profile->net.quiet[i], NULL))
590 +                               goto fail;
591 +               }
592 +               if (!unpack_nameX(e, AA_ARRAYEND, NULL))
593 +                       goto fail;
594 +       }
595 +       /*
596 +        * allow unix domain and netlink sockets they are handled
597 +        * by IPC
598 +        */
599 +       profile->net.allow[AF_UNIX] = 0xffff;
600 +       profile->net.allow[AF_NETLINK] = 0xffff;
601 +
602         if (unpack_nameX(e, AA_STRUCT, "policydb")) {
603                 /* generic policy dfa - optional and may be NULL */
604                 profile->policy.dfa = unpack_dfa(e);
605 -- 
606 1.8.3.2
607
608 From b452a37e97af826ba6c7548230e07c95bd13d9c4 Mon Sep 17 00:00:00 2001
609 From: John Johansen <john.johansen@canonical.com>
610 Date: Fri, 29 Jun 2012 17:34:00 -0700
611 Subject: [PATCH 2/3] apparmor: Fix quieting of audit messages for network
612  mediation
613
614 If a profile specified a quieting of network denials for a given rule by
615 either the quiet or deny rule qualifiers, the resultant quiet mask for
616 denied requests was applied incorrectly, resulting in two potential bugs.
617 1. The misapplied quiet mask would prevent denials from being correctly
618    tested against the kill mask/mode. Thus network access requests that
619    should have resulted in the application being killed did not.
620
621 2. The actual quieting of the denied network request was not being applied.
622    This would result in network rejections always being logged even when
623    they had been specifically marked as quieted.
624
625 Signed-off-by: John Johansen <john.johansen@canonical.com>
626 ---
627  security/apparmor/net.c | 2 +-
628  1 file changed, 1 insertion(+), 1 deletion(-)
629
630 diff --git a/security/apparmor/net.c b/security/apparmor/net.c
631 index 003dd18..6e6e5c9 100644
632 --- a/security/apparmor/net.c
633 +++ b/security/apparmor/net.c
634 @@ -88,7 +88,7 @@ static int audit_net(struct aa_profile *profile, int op, u16 family, int type,
635         } else {
636                 u16 quiet_mask = profile->net.quiet[sa.u.net->family];
637                 u16 kill_mask = 0;
638 -               u16 denied = (1 << sa.aad->net.type) & ~quiet_mask;
639 +               u16 denied = (1 << sa.aad->net.type);
640  
641                 if (denied & kill_mask)
642                         audit_type = AUDIT_APPARMOR_KILL;
643 -- 
644 1.8.3.2
645
646 From 0f113c1f052be315f5097d8b7294a620b0adda87 Mon Sep 17 00:00:00 2001
647 From: John Johansen <john.johansen@canonical.com>
648 Date: Wed, 16 May 2012 10:58:05 -0700
649 Subject: [PATCH 3/3] UBUNTU: SAUCE: apparmor: Add the ability to mediate mount
650
651 Add the ability for apparmor to do mediation of mount operations. Mount
652 rules require an updated apparmor_parser (2.8 series) for policy compilation.
653
654 The basic form of the rules are.
655
656   [audit] [deny] mount [conds]* [device] [ -> [conds] path],
657   [audit] [deny] remount [conds]* [path],
658   [audit] [deny] umount [conds]* [path],
659   [audit] [deny] pivotroot [oldroot=<value>] <path>
660
661   remount is just a short cut for mount options=remount
662
663   where [conds] can be
664     fstype=<expr>
665     options=<expr>
666
667 Example mount commands
668   mount,                # allow all mounts, but not umount or pivotroot
669
670   mount fstype=procfs,  # allow mounting procfs anywhere
671
672   mount options=(bind, ro) /foo -> /bar,  # readonly bind mount
673
674   mount /dev/sda -> /mnt,
675
676   mount /dev/sd** -> /mnt/**,
677
678   mount fstype=overlayfs options=(rw,upperdir=/tmp/upper/,lowerdir=/) -> /mnt/
679
680   umount,
681
682   umount /m*,
683
684 See the apparmor userspace for full documentation
685
686 Signed-off-by: John Johansen <john.johansen@canonical.com>
687 Acked-by: Kees Cook <kees@ubuntu.com>
688
689 Conflicts:
690         security/apparmor/Makefile
691         security/apparmor/apparmorfs.c
692 ---
693  security/apparmor/Makefile           |   2 +-
694  security/apparmor/apparmorfs.c       |  15 +-
695  security/apparmor/audit.c            |   4 +
696  security/apparmor/domain.c           |   2 +-
697  security/apparmor/include/apparmor.h |   3 +-
698  security/apparmor/include/audit.h    |  11 +
699  security/apparmor/include/domain.h   |   2 +
700  security/apparmor/include/mount.h    |  54 +++
701  security/apparmor/lsm.c              |  59 ++++
702  security/apparmor/mount.c            | 620 +++++++++++++++++++++++++++++++++++
703  10 files changed, 768 insertions(+), 4 deletions(-)
704  create mode 100644 security/apparmor/include/mount.h
705  create mode 100644 security/apparmor/mount.c
706
707 diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
708 index 5dbb72f..89b3445 100644
709 --- a/security/apparmor/Makefile
710 +++ b/security/apparmor/Makefile
711 @@ -4,7 +4,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
712  
713  apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
714                path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
715 -              resource.o sid.o file.o net.o
716 +              resource.o sid.o file.o net.o mount.o
717  apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
718  
719  clean-files := capability_names.h rlim_names.h net_names.h
720 diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
721 index 18fc02c..e709030 100644
722 --- a/security/apparmor/apparmorfs.c
723 +++ b/security/apparmor/apparmorfs.c
724 @@ -799,7 +799,18 @@ static struct aa_fs_entry aa_fs_entry_domain[] = {
725  
726  static struct aa_fs_entry aa_fs_entry_policy[] = {
727         AA_FS_FILE_BOOLEAN("set_load",          1),
728 -       {}
729 +       { }
730 +};
731 +
732 +static struct aa_fs_entry aa_fs_entry_mount[] = {
733 +       AA_FS_FILE_STRING("mask", "mount umount"),
734 +       { }
735 +};
736 +
737 +static struct aa_fs_entry aa_fs_entry_namespaces[] = {
738 +       AA_FS_FILE_BOOLEAN("profile",           1),
739 +       AA_FS_FILE_BOOLEAN("pivot_root",        1),
740 +       { }
741  };
742  
743  static struct aa_fs_entry aa_fs_entry_features[] = {
744 @@ -807,6 +818,8 @@ static struct aa_fs_entry aa_fs_entry_features[] = {
745         AA_FS_DIR("domain",                     aa_fs_entry_domain),
746         AA_FS_DIR("file",                       aa_fs_entry_file),
747         AA_FS_DIR("network",                    aa_fs_entry_network),
748 +       AA_FS_DIR("mount",                      aa_fs_entry_mount),
749 +       AA_FS_DIR("namespaces",                 aa_fs_entry_namespaces),
750         AA_FS_FILE_U64("capability",            VFS_CAP_FLAGS_MASK),
751         AA_FS_DIR("rlimit",                     aa_fs_entry_rlimit),
752         AA_FS_DIR("caps",                       aa_fs_entry_caps),
753 diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
754 index 031d2d9..02d804c 100644
755 --- a/security/apparmor/audit.c
756 +++ b/security/apparmor/audit.c
757 @@ -44,6 +44,10 @@ const char *const op_table[] = {
758         "file_mmap",
759         "file_mprotect",
760  
761 +       "pivotroot",
762 +       "mount",
763 +       "umount",
764 +
765         "create",
766         "post_create",
767         "bind",
768 diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
769 index 26c607c..23936c5 100644
770 --- a/security/apparmor/domain.c
771 +++ b/security/apparmor/domain.c
772 @@ -238,7 +238,7 @@ static const char *next_name(int xtype, const char *name)
773   *
774   * Returns: refcounted profile, or NULL on failure (MAYBE NULL)
775   */
776 -static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
777 +struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
778  {
779         struct aa_profile *new_profile = NULL;
780         struct aa_namespace *ns = profile->ns;
781 diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
782 index 8fb1488..22b172c 100644
783 --- a/security/apparmor/include/apparmor.h
784 +++ b/security/apparmor/include/apparmor.h
785 @@ -30,8 +30,9 @@
786  #define AA_CLASS_NET           4
787  #define AA_CLASS_RLIMITS       5
788  #define AA_CLASS_DOMAIN                6
789 +#define AA_CLASS_MOUNT         7
790  
791 -#define AA_CLASS_LAST          AA_CLASS_DOMAIN
792 +#define AA_CLASS_LAST          AA_CLASS_MOUNT
793  
794  /* Control parameters settable through module/boot flags */
795  extern enum audit_mode aa_g_audit;
796 diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
797 index 61abec5..a9835c3 100644
798 --- a/security/apparmor/include/audit.h
799 +++ b/security/apparmor/include/audit.h
800 @@ -72,6 +72,10 @@ enum aa_ops {
801         OP_FMMAP,
802         OP_FMPROT,
803  
804 +       OP_PIVOTROOT,
805 +       OP_MOUNT,
806 +       OP_UMOUNT,
807 +
808         OP_CREATE,
809         OP_POST_CREATE,
810         OP_BIND,
811 @@ -121,6 +125,13 @@ struct apparmor_audit_data {
812                         unsigned long max;
813                 } rlim;
814                 struct {
815 +                       const char *src_name;
816 +                       const char *type;
817 +                       const char *trans;
818 +                       const char *data;
819 +                       unsigned long flags;
820 +               } mnt;
821 +               struct {
822                         const char *target;
823                         u32 request;
824                         u32 denied;
825 diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h
826 index de04464..a3f70c5 100644
827 --- a/security/apparmor/include/domain.h
828 +++ b/security/apparmor/include/domain.h
829 @@ -23,6 +23,8 @@ struct aa_domain {
830         char **table;
831  };
832  
833 +struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex);
834 +
835  int apparmor_bprm_set_creds(struct linux_binprm *bprm);
836  int apparmor_bprm_secureexec(struct linux_binprm *bprm);
837  void apparmor_bprm_committing_creds(struct linux_binprm *bprm);
838 diff --git a/security/apparmor/include/mount.h b/security/apparmor/include/mount.h
839 new file mode 100644
840 index 0000000..bc17a53
841 --- /dev/null
842 +++ b/security/apparmor/include/mount.h
843 @@ -0,0 +1,54 @@
844 +/*
845 + * AppArmor security module
846 + *
847 + * This file contains AppArmor file mediation function definitions.
848 + *
849 + * Copyright 2012 Canonical Ltd.
850 + *
851 + * This program is free software; you can redistribute it and/or
852 + * modify it under the terms of the GNU General Public License as
853 + * published by the Free Software Foundation, version 2 of the
854 + * License.
855 + */
856 +
857 +#ifndef __AA_MOUNT_H
858 +#define __AA_MOUNT_H
859 +
860 +#include <linux/fs.h>
861 +#include <linux/path.h>
862 +
863 +#include "domain.h"
864 +#include "policy.h"
865 +
866 +/* mount perms */
867 +#define AA_MAY_PIVOTROOT       0x01
868 +#define AA_MAY_MOUNT           0x02
869 +#define AA_MAY_UMOUNT          0x04
870 +#define AA_AUDIT_DATA          0x40
871 +#define AA_CONT_MATCH          0x40
872 +
873 +#define AA_MS_IGNORE_MASK (MS_KERNMOUNT | MS_NOSEC | MS_ACTIVE | MS_BORN)
874 +
875 +int aa_remount(struct aa_profile *profile, struct path *path,
876 +              unsigned long flags, void *data);
877 +
878 +int aa_bind_mount(struct aa_profile *profile, struct path *path,
879 +                 const char *old_name, unsigned long flags);
880 +
881 +
882 +int aa_mount_change_type(struct aa_profile *profile, struct path *path,
883 +                        unsigned long flags);
884 +
885 +int aa_move_mount(struct aa_profile *profile, struct path *path,
886 +                 const char *old_name);
887 +
888 +int aa_new_mount(struct aa_profile *profile, const char *dev_name,
889 +                struct path *path, const char *type, unsigned long flags,
890 +                void *data);
891 +
892 +int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags);
893 +
894 +int aa_pivotroot(struct aa_profile *profile, struct path *old_path,
895 +                 struct path *new_path);
896 +
897 +#endif /* __AA_MOUNT_H */
898 diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
899 index de55a7f..e0dd95f 100644
900 --- a/security/apparmor/lsm.c
901 +++ b/security/apparmor/lsm.c
902 @@ -36,6 +36,7 @@
903  #include "include/path.h"
904  #include "include/policy.h"
905  #include "include/procattr.h"
906 +#include "include/mount.h"
907  
908  /* Flag indicating whether initialization completed */
909  int apparmor_initialized __initdata;
910 @@ -502,6 +503,60 @@ static int apparmor_file_mprotect(struct vm_area_struct *vma,
911                            !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
912  }
913  
914 +static int apparmor_sb_mount(char *dev_name, struct path *path, char *type,
915 +                            unsigned long flags, void *data)
916 +{
917 +       struct aa_profile *profile;
918 +       int error = 0;
919 +
920 +       /* Discard magic */
921 +       if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
922 +               flags &= ~MS_MGC_MSK;
923 +
924 +       flags &= ~AA_MS_IGNORE_MASK;
925 +
926 +       profile = __aa_current_profile();
927 +       if (!unconfined(profile)) {
928 +               if (flags & MS_REMOUNT)
929 +                       error = aa_remount(profile, path, flags, data);
930 +               else if (flags & MS_BIND)
931 +                       error = aa_bind_mount(profile, path, dev_name, flags);
932 +               else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE |
933 +                                 MS_UNBINDABLE))
934 +                       error = aa_mount_change_type(profile, path, flags);
935 +               else if (flags & MS_MOVE)
936 +                       error = aa_move_mount(profile, path, dev_name);
937 +               else
938 +                       error = aa_new_mount(profile, dev_name, path, type,
939 +                                            flags, data);
940 +       }
941 +       return error;
942 +}
943 +
944 +static int apparmor_sb_umount(struct vfsmount *mnt, int flags)
945 +{
946 +       struct aa_profile *profile;
947 +       int error = 0;
948 +
949 +       profile = __aa_current_profile();
950 +       if (!unconfined(profile))
951 +               error = aa_umount(profile, mnt, flags);
952 +
953 +       return error;
954 +}
955 +
956 +static int apparmor_sb_pivotroot(struct path *old_path, struct path *new_path)
957 +{
958 +       struct aa_profile *profile;
959 +       int error = 0;
960 +
961 +       profile = __aa_current_profile();
962 +       if (!unconfined(profile))
963 +               error = aa_pivotroot(profile, old_path, new_path);
964 +
965 +       return error;
966 +}
967 +
968  static int apparmor_getprocattr(struct task_struct *task, char *name,
969                                 char **value)
970  {
971 @@ -722,6 +777,10 @@ static struct security_operations apparmor_ops = {
972         .capget =                       apparmor_capget,
973         .capable =                      apparmor_capable,
974  
975 +       .sb_mount =                     apparmor_sb_mount,
976 +       .sb_umount =                    apparmor_sb_umount,
977 +       .sb_pivotroot =                 apparmor_sb_pivotroot,
978 +
979         .path_link =                    apparmor_path_link,
980         .path_unlink =                  apparmor_path_unlink,
981         .path_symlink =                 apparmor_path_symlink,
982 diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c
983 new file mode 100644
984 index 0000000..478aa4d
985 --- /dev/null
986 +++ b/security/apparmor/mount.c
987 @@ -0,0 +1,620 @@
988 +/*
989 + * AppArmor security module
990 + *
991 + * This file contains AppArmor mediation of files
992 + *
993 + * Copyright (C) 1998-2008 Novell/SUSE
994 + * Copyright 2009-2012 Canonical Ltd.
995 + *
996 + * This program is free software; you can redistribute it and/or
997 + * modify it under the terms of the GNU General Public License as
998 + * published by the Free Software Foundation, version 2 of the
999 + * License.
1000 + */
1001 +
1002 +#include <linux/fs.h>
1003 +#include <linux/mount.h>
1004 +#include <linux/namei.h>
1005 +
1006 +#include "include/apparmor.h"
1007 +#include "include/audit.h"
1008 +#include "include/context.h"
1009 +#include "include/domain.h"
1010 +#include "include/file.h"
1011 +#include "include/match.h"
1012 +#include "include/mount.h"
1013 +#include "include/path.h"
1014 +#include "include/policy.h"
1015 +
1016 +
1017 +static void audit_mnt_flags(struct audit_buffer *ab, unsigned long flags)
1018 +{
1019 +       if (flags & MS_RDONLY)
1020 +               audit_log_format(ab, "ro");
1021 +       else
1022 +               audit_log_format(ab, "rw");
1023 +       if (flags & MS_NOSUID)
1024 +               audit_log_format(ab, ", nosuid");
1025 +       if (flags & MS_NODEV)
1026 +               audit_log_format(ab, ", nodev");
1027 +       if (flags & MS_NOEXEC)
1028 +               audit_log_format(ab, ", noexec");
1029 +       if (flags & MS_SYNCHRONOUS)
1030 +               audit_log_format(ab, ", sync");
1031 +       if (flags & MS_REMOUNT)
1032 +               audit_log_format(ab, ", remount");
1033 +       if (flags & MS_MANDLOCK)
1034 +               audit_log_format(ab, ", mand");
1035 +       if (flags & MS_DIRSYNC)
1036 +               audit_log_format(ab, ", dirsync");
1037 +       if (flags & MS_NOATIME)
1038 +               audit_log_format(ab, ", noatime");
1039 +       if (flags & MS_NODIRATIME)
1040 +               audit_log_format(ab, ", nodiratime");
1041 +       if (flags & MS_BIND)
1042 +               audit_log_format(ab, flags & MS_REC ? ", rbind" : ", bind");
1043 +       if (flags & MS_MOVE)
1044 +               audit_log_format(ab, ", move");
1045 +       if (flags & MS_SILENT)
1046 +               audit_log_format(ab, ", silent");
1047 +       if (flags & MS_POSIXACL)
1048 +               audit_log_format(ab, ", acl");
1049 +       if (flags & MS_UNBINDABLE)
1050 +               audit_log_format(ab, flags & MS_REC ? ", runbindable" :
1051 +                                ", unbindable");
1052 +       if (flags & MS_PRIVATE)
1053 +               audit_log_format(ab, flags & MS_REC ? ", rprivate" :
1054 +                                ", private");
1055 +       if (flags & MS_SLAVE)
1056 +               audit_log_format(ab, flags & MS_REC ? ", rslave" :
1057 +                                ", slave");
1058 +       if (flags & MS_SHARED)
1059 +               audit_log_format(ab, flags & MS_REC ? ", rshared" :
1060 +                                ", shared");
1061 +       if (flags & MS_RELATIME)
1062 +               audit_log_format(ab, ", relatime");
1063 +       if (flags & MS_I_VERSION)
1064 +               audit_log_format(ab, ", iversion");
1065 +       if (flags & MS_STRICTATIME)
1066 +               audit_log_format(ab, ", strictatime");
1067 +       if (flags & MS_NOUSER)
1068 +               audit_log_format(ab, ", nouser");
1069 +}
1070 +
1071 +/**
1072 + * audit_cb - call back for mount specific audit fields
1073 + * @ab: audit_buffer  (NOT NULL)
1074 + * @va: audit struct to audit values of  (NOT NULL)
1075 + */
1076 +static void audit_cb(struct audit_buffer *ab, void *va)
1077 +{
1078 +       struct common_audit_data *sa = va;
1079 +
1080 +       if (sa->aad->mnt.type) {
1081 +               audit_log_format(ab, " fstype=");
1082 +               audit_log_untrustedstring(ab, sa->aad->mnt.type);
1083 +       }
1084 +       if (sa->aad->mnt.src_name) {
1085 +               audit_log_format(ab, " srcname=");
1086 +               audit_log_untrustedstring(ab, sa->aad->mnt.src_name);
1087 +       }
1088 +       if (sa->aad->mnt.trans) {
1089 +               audit_log_format(ab, " trans=");
1090 +               audit_log_untrustedstring(ab, sa->aad->mnt.trans);
1091 +       }
1092 +       if (sa->aad->mnt.flags || sa->aad->op == OP_MOUNT) {
1093 +               audit_log_format(ab, " flags=\"");
1094 +               audit_mnt_flags(ab, sa->aad->mnt.flags);
1095 +               audit_log_format(ab, "\"");
1096 +       }
1097 +       if (sa->aad->mnt.data) {
1098 +               audit_log_format(ab, " options=");
1099 +               audit_log_untrustedstring(ab, sa->aad->mnt.data);
1100 +       }
1101 +}
1102 +
1103 +/**
1104 + * audit_mount - handle the auditing of mount operations
1105 + * @profile: the profile being enforced  (NOT NULL)
1106 + * @gfp: allocation flags
1107 + * @op: operation being mediated (NOT NULL)
1108 + * @name: name of object being mediated (MAYBE NULL)
1109 + * @src_name: src_name of object being mediated (MAYBE_NULL)
1110 + * @type: type of filesystem (MAYBE_NULL)
1111 + * @trans: name of trans (MAYBE NULL)
1112 + * @flags: filesystem idependent mount flags
1113 + * @data: filesystem mount flags
1114 + * @request: permissions requested
1115 + * @perms: the permissions computed for the request (NOT NULL)
1116 + * @info: extra information message (MAYBE NULL)
1117 + * @error: 0 if operation allowed else failure error code
1118 + *
1119 + * Returns: %0 or error on failure
1120 + */
1121 +static int audit_mount(struct aa_profile *profile, gfp_t gfp, int op,
1122 +                      const char *name, const char *src_name,
1123 +                      const char *type, const char *trans,
1124 +                      unsigned long flags, const void *data, u32 request,
1125 +                      struct file_perms *perms, const char *info, int error)
1126 +{
1127 +       int audit_type = AUDIT_APPARMOR_AUTO;
1128 +       struct common_audit_data sa = { };
1129 +       struct apparmor_audit_data aad = { };
1130 +
1131 +       if (likely(!error)) {
1132 +               u32 mask = perms->audit;
1133 +
1134 +               if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
1135 +                       mask = 0xffff;
1136 +
1137 +               /* mask off perms that are not being force audited */
1138 +               request &= mask;
1139 +
1140 +               if (likely(!request))
1141 +                       return 0;
1142 +               audit_type = AUDIT_APPARMOR_AUDIT;
1143 +       } else {
1144 +               /* only report permissions that were denied */
1145 +               request = request & ~perms->allow;
1146 +
1147 +               if (request & perms->kill)
1148 +                       audit_type = AUDIT_APPARMOR_KILL;
1149 +
1150 +               /* quiet known rejects, assumes quiet and kill do not overlap */
1151 +               if ((request & perms->quiet) &&
1152 +                   AUDIT_MODE(profile) != AUDIT_NOQUIET &&
1153 +                   AUDIT_MODE(profile) != AUDIT_ALL)
1154 +                       request &= ~perms->quiet;
1155 +
1156 +               if (!request)
1157 +                       return COMPLAIN_MODE(profile) ?
1158 +                               complain_error(error) : error;
1159 +       }
1160 +
1161 +       sa.type = LSM_AUDIT_DATA_NONE;
1162 +       sa.aad = &aad;
1163 +       sa.aad->op = op;
1164 +       sa.aad->name = name;
1165 +       sa.aad->mnt.src_name = src_name;
1166 +       sa.aad->mnt.type = type;
1167 +       sa.aad->mnt.trans = trans;
1168 +       sa.aad->mnt.flags = flags;
1169 +       if (data && (perms->audit & AA_AUDIT_DATA))
1170 +               sa.aad->mnt.data = data;
1171 +       sa.aad->info = info;
1172 +       sa.aad->error = error;
1173 +
1174 +       return aa_audit(audit_type, profile, gfp, &sa, audit_cb);
1175 +}
1176 +
1177 +/**
1178 + * match_mnt_flags - Do an ordered match on mount flags
1179 + * @dfa: dfa to match against
1180 + * @state: state to start in
1181 + * @flags: mount flags to match against
1182 + *
1183 + * Mount flags are encoded as an ordered match. This is done instead of
1184 + * checking against a simple bitmask, to allow for logical operations
1185 + * on the flags.
1186 + *
1187 + * Returns: next state after flags match
1188 + */
1189 +static unsigned int match_mnt_flags(struct aa_dfa *dfa, unsigned int state,
1190 +                                   unsigned long flags)
1191 +{
1192 +       unsigned int i;
1193 +
1194 +       for (i = 0; i <= 31 ; ++i) {
1195 +               if ((1 << i) & flags)
1196 +                       state = aa_dfa_next(dfa, state, i + 1);
1197 +       }
1198 +
1199 +       return state;
1200 +}
1201 +
1202 +/**
1203 + * compute_mnt_perms - compute mount permission associated with @state
1204 + * @dfa: dfa to match against (NOT NULL)
1205 + * @state: state match finished in
1206 + *
1207 + * Returns: mount permissions
1208 + */
1209 +static struct file_perms compute_mnt_perms(struct aa_dfa *dfa,
1210 +                                          unsigned int state)
1211 +{
1212 +       struct file_perms perms;
1213 +
1214 +       perms.kill = 0;
1215 +       perms.allow = dfa_user_allow(dfa, state);
1216 +       perms.audit = dfa_user_audit(dfa, state);
1217 +       perms.quiet = dfa_user_quiet(dfa, state);
1218 +       perms.xindex = dfa_user_xindex(dfa, state);
1219 +
1220 +       return perms;
1221 +}
1222 +
1223 +static const char const *mnt_info_table[] = {
1224 +       "match succeeded",
1225 +       "failed mntpnt match",
1226 +       "failed srcname match",
1227 +       "failed type match",
1228 +       "failed flags match",
1229 +       "failed data match"
1230 +};
1231 +
1232 +/*
1233 + * Returns 0 on success else element that match failed in, this is the
1234 + * index into the mnt_info_table above
1235 + */
1236 +static int do_match_mnt(struct aa_dfa *dfa, unsigned int start,
1237 +                       const char *mntpnt, const char *devname,
1238 +                       const char *type, unsigned long flags,
1239 +                       void *data, bool binary, struct file_perms *perms)
1240 +{
1241 +       unsigned int state;
1242 +
1243 +       state = aa_dfa_match(dfa, start, mntpnt);
1244 +       state = aa_dfa_null_transition(dfa, state);
1245 +       if (!state)
1246 +               return 1;
1247 +
1248 +       if (devname)
1249 +               state = aa_dfa_match(dfa, state, devname);
1250 +       state = aa_dfa_null_transition(dfa, state);
1251 +       if (!state)
1252 +               return 2;
1253 +
1254 +       if (type)
1255 +               state = aa_dfa_match(dfa, state, type);
1256 +       state = aa_dfa_null_transition(dfa, state);
1257 +       if (!state)
1258 +               return 3;
1259 +
1260 +       state = match_mnt_flags(dfa, state, flags);
1261 +       if (!state)
1262 +               return 4;
1263 +       *perms = compute_mnt_perms(dfa, state);
1264 +       if (perms->allow & AA_MAY_MOUNT)
1265 +               return 0;
1266 +
1267 +       /* only match data if not binary and the DFA flags data is expected */
1268 +       if (data && !binary && (perms->allow & AA_CONT_MATCH)) {
1269 +               state = aa_dfa_null_transition(dfa, state);
1270 +               if (!state)
1271 +                       return 4;
1272 +
1273 +               state = aa_dfa_match(dfa, state, data);
1274 +               if (!state)
1275 +                       return 5;
1276 +               *perms = compute_mnt_perms(dfa, state);
1277 +               if (perms->allow & AA_MAY_MOUNT)
1278 +                       return 0;
1279 +       }
1280 +
1281 +       /* failed at end of flags match */
1282 +       return 4;
1283 +}
1284 +
1285 +/**
1286 + * match_mnt - handle path matching for mount
1287 + * @profile: the confining profile
1288 + * @mntpnt: string for the mntpnt (NOT NULL)
1289 + * @devname: string for the devname/src_name (MAYBE NULL)
1290 + * @type: string for the dev type (MAYBE NULL)
1291 + * @flags: mount flags to match
1292 + * @data: fs mount data (MAYBE NULL)
1293 + * @binary: whether @data is binary
1294 + * @perms: Returns: permission found by the match
1295 + * @info: Returns: infomation string about the match for logging
1296 + *
1297 + * Returns: 0 on success else error
1298 + */
1299 +static int match_mnt(struct aa_profile *profile, const char *mntpnt,
1300 +                    const char *devname, const char *type,
1301 +                    unsigned long flags, void *data, bool binary,
1302 +                    struct file_perms *perms, const char **info)
1303 +{
1304 +       int pos;
1305 +
1306 +       if (!profile->policy.dfa)
1307 +               return -EACCES;
1308 +
1309 +       pos = do_match_mnt(profile->policy.dfa,
1310 +                          profile->policy.start[AA_CLASS_MOUNT],
1311 +                          mntpnt, devname, type, flags, data, binary, perms);
1312 +       if (pos) {
1313 +               *info = mnt_info_table[pos];
1314 +               return -EACCES;
1315 +       }
1316 +
1317 +       return 0;
1318 +}
1319 +
1320 +static int path_flags(struct aa_profile *profile, struct path *path)
1321 +{
1322 +       return profile->path_flags |
1323 +               S_ISDIR(path->dentry->d_inode->i_mode) ? PATH_IS_DIR : 0;
1324 +}
1325 +
1326 +int aa_remount(struct aa_profile *profile, struct path *path,
1327 +              unsigned long flags, void *data)
1328 +{
1329 +       struct file_perms perms = { };
1330 +       const char *name, *info = NULL;
1331 +       char *buffer = NULL;
1332 +       int binary, error;
1333 +
1334 +       binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA;
1335 +
1336 +       error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1337 +                            &info);
1338 +       if (error)
1339 +               goto audit;
1340 +
1341 +       error = match_mnt(profile, name, NULL, NULL, flags, data, binary,
1342 +                         &perms, &info);
1343 +
1344 +audit:
1345 +       error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
1346 +                           NULL, flags, data, AA_MAY_MOUNT, &perms, info,
1347 +                           error);
1348 +       kfree(buffer);
1349 +
1350 +       return error;
1351 +}
1352 +
1353 +int aa_bind_mount(struct aa_profile *profile, struct path *path,
1354 +                 const char *dev_name, unsigned long flags)
1355 +{
1356 +       struct file_perms perms = { };
1357 +       char *buffer = NULL, *old_buffer = NULL;
1358 +       const char *name, *old_name = NULL, *info = NULL;
1359 +       struct path old_path;
1360 +       int error;
1361 +
1362 +       if (!dev_name || !*dev_name)
1363 +               return -EINVAL;
1364 +
1365 +       flags &= MS_REC | MS_BIND;
1366 +
1367 +       error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1368 +                            &info);
1369 +       if (error)
1370 +               goto audit;
1371 +
1372 +       error = kern_path(dev_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
1373 +       if (error)
1374 +               goto audit;
1375 +
1376 +       error = aa_path_name(&old_path, path_flags(profile, &old_path),
1377 +                            &old_buffer, &old_name, &info);
1378 +       path_put(&old_path);
1379 +       if (error)
1380 +               goto audit;
1381 +
1382 +       error = match_mnt(profile, name, old_name, NULL, flags, NULL, 0,
1383 +                         &perms, &info);
1384 +
1385 +audit:
1386 +       error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
1387 +                           NULL, NULL, flags, NULL, AA_MAY_MOUNT, &perms,
1388 +                           info, error);
1389 +       kfree(buffer);
1390 +       kfree(old_buffer);
1391 +
1392 +       return error;
1393 +}
1394 +
1395 +int aa_mount_change_type(struct aa_profile *profile, struct path *path,
1396 +                        unsigned long flags)
1397 +{
1398 +       struct file_perms perms = { };
1399 +       char *buffer = NULL;
1400 +       const char *name, *info = NULL;
1401 +       int error;
1402 +
1403 +       /* These are the flags allowed by do_change_type() */
1404 +       flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE |
1405 +                 MS_UNBINDABLE);
1406 +
1407 +       error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1408 +                            &info);
1409 +       if (error)
1410 +               goto audit;
1411 +
1412 +       error = match_mnt(profile, name, NULL, NULL, flags, NULL, 0, &perms,
1413 +                         &info);
1414 +
1415 +audit:
1416 +       error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
1417 +                           NULL, flags, NULL, AA_MAY_MOUNT, &perms, info,
1418 +                           error);
1419 +       kfree(buffer);
1420 +
1421 +       return error;
1422 +}
1423 +
1424 +int aa_move_mount(struct aa_profile *profile, struct path *path,
1425 +                 const char *orig_name)
1426 +{
1427 +       struct file_perms perms = { };
1428 +       char *buffer = NULL, *old_buffer = NULL;
1429 +       const char *name, *old_name = NULL, *info = NULL;
1430 +       struct path old_path;
1431 +       int error;
1432 +
1433 +       if (!orig_name || !*orig_name)
1434 +               return -EINVAL;
1435 +
1436 +       error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1437 +                            &info);
1438 +       if (error)
1439 +               goto audit;
1440 +
1441 +       error = kern_path(orig_name, LOOKUP_FOLLOW, &old_path);
1442 +       if (error)
1443 +               goto audit;
1444 +
1445 +       error = aa_path_name(&old_path, path_flags(profile, &old_path),
1446 +                            &old_buffer, &old_name, &info);
1447 +       path_put(&old_path);
1448 +       if (error)
1449 +               goto audit;
1450 +
1451 +       error = match_mnt(profile, name, old_name, NULL, MS_MOVE, NULL, 0,
1452 +                         &perms, &info);
1453 +
1454 +audit:
1455 +       error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
1456 +                           NULL, NULL, MS_MOVE, NULL, AA_MAY_MOUNT, &perms,
1457 +                           info, error);
1458 +       kfree(buffer);
1459 +       kfree(old_buffer);
1460 +
1461 +       return error;
1462 +}
1463 +
1464 +int aa_new_mount(struct aa_profile *profile, const char *orig_dev_name,
1465 +                struct path *path, const char *type, unsigned long flags,
1466 +                void *data)
1467 +{
1468 +       struct file_perms perms = { };
1469 +       char *buffer = NULL, *dev_buffer = NULL;
1470 +       const char *name = NULL, *dev_name = NULL, *info = NULL;
1471 +       int binary = 1;
1472 +       int error;
1473 +
1474 +       dev_name = orig_dev_name;
1475 +       if (type) {
1476 +               int requires_dev;
1477 +               struct file_system_type *fstype = get_fs_type(type);
1478 +               if (!fstype)
1479 +                       return -ENODEV;
1480 +
1481 +               binary = fstype->fs_flags & FS_BINARY_MOUNTDATA;
1482 +               requires_dev = fstype->fs_flags & FS_REQUIRES_DEV;
1483 +               put_filesystem(fstype);
1484 +
1485 +               if (requires_dev) {
1486 +                       struct path dev_path;
1487 +
1488 +                       if (!dev_name || !*dev_name) {
1489 +                               error = -ENOENT;
1490 +                               goto out;
1491 +                       }
1492 +
1493 +                       error = kern_path(dev_name, LOOKUP_FOLLOW, &dev_path);
1494 +                       if (error)
1495 +                               goto audit;
1496 +
1497 +                       error = aa_path_name(&dev_path,
1498 +                                            path_flags(profile, &dev_path),
1499 +                                            &dev_buffer, &dev_name, &info);
1500 +                       path_put(&dev_path);
1501 +                       if (error)
1502 +                               goto audit;
1503 +               }
1504 +       }
1505 +
1506 +       error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1507 +                            &info);
1508 +       if (error)
1509 +               goto audit;
1510 +
1511 +       error = match_mnt(profile, name, dev_name, type, flags, data, binary,
1512 +                         &perms, &info);
1513 +
1514 +audit:
1515 +       error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name,  dev_name,
1516 +                           type, NULL, flags, data, AA_MAY_MOUNT, &perms, info,
1517 +                           error);
1518 +       kfree(buffer);
1519 +       kfree(dev_buffer);
1520 +
1521 +out:
1522 +       return error;
1523 +
1524 +}
1525 +
1526 +int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags)
1527 +{
1528 +       struct file_perms perms = { };
1529 +       char *buffer = NULL;
1530 +       const char *name, *info = NULL;
1531 +       int error;
1532 +
1533 +       struct path path = { mnt, mnt->mnt_root };
1534 +       error = aa_path_name(&path, path_flags(profile, &path), &buffer, &name,
1535 +                            &info);
1536 +       if (error)
1537 +               goto audit;
1538 +
1539 +       if (!error && profile->policy.dfa) {
1540 +               unsigned int state;
1541 +               state = aa_dfa_match(profile->policy.dfa,
1542 +                                    profile->policy.start[AA_CLASS_MOUNT],
1543 +                                    name);
1544 +               perms = compute_mnt_perms(profile->policy.dfa, state);
1545 +       }
1546 +
1547 +       if (AA_MAY_UMOUNT & ~perms.allow)
1548 +               error = -EACCES;
1549 +
1550 +audit:
1551 +       error = audit_mount(profile, GFP_KERNEL, OP_UMOUNT, name, NULL, NULL,
1552 +                           NULL, 0, NULL, AA_MAY_UMOUNT, &perms, info, error);
1553 +       kfree(buffer);
1554 +
1555 +       return error;
1556 +}
1557 +
1558 +int aa_pivotroot(struct aa_profile *profile, struct path *old_path,
1559 +                 struct path *new_path)
1560 +{
1561 +       struct file_perms perms = { };
1562 +       struct aa_profile *target = NULL;
1563 +       char *old_buffer = NULL, *new_buffer = NULL;
1564 +       const char *old_name, *new_name = NULL, *info = NULL;
1565 +       int error;
1566 +
1567 +       error = aa_path_name(old_path, path_flags(profile, old_path),
1568 +                            &old_buffer, &old_name, &info);
1569 +       if (error)
1570 +               goto audit;
1571 +
1572 +       error = aa_path_name(new_path, path_flags(profile, new_path),
1573 +                            &new_buffer, &new_name, &info);
1574 +       if (error)
1575 +               goto audit;
1576 +
1577 +       if (profile->policy.dfa) {
1578 +               unsigned int state;
1579 +               state = aa_dfa_match(profile->policy.dfa,
1580 +                                    profile->policy.start[AA_CLASS_MOUNT],
1581 +                                    new_name);
1582 +               state = aa_dfa_null_transition(profile->policy.dfa, state);
1583 +               state = aa_dfa_match(profile->policy.dfa, state, old_name);
1584 +               perms = compute_mnt_perms(profile->policy.dfa, state);
1585 +       }
1586 +
1587 +       if (AA_MAY_PIVOTROOT & perms.allow) {
1588 +               if ((perms.xindex & AA_X_TYPE_MASK) == AA_X_TABLE) {
1589 +                       target = x_table_lookup(profile, perms.xindex);
1590 +                       if (!target)
1591 +                               error = -ENOENT;
1592 +                       else
1593 +                               error = aa_replace_current_profile(target);
1594 +               }
1595 +       } else
1596 +               error = -EACCES;
1597 +
1598 +audit:
1599 +       error = audit_mount(profile, GFP_KERNEL, OP_PIVOTROOT, new_name,
1600 +                           old_name, NULL, target ? target->base.name : NULL,
1601 +                           0, NULL,  AA_MAY_PIVOTROOT, &perms, info, error);
1602 +       aa_put_profile(target);
1603 +       kfree(old_buffer);
1604 +       kfree(new_buffer);
1605 +
1606 +       return error;
1607 +}
1608 -- 
1609 1.8.3.2
1610
This page took 0.465872 seconds and 3 git commands to generate.