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