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