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