]> git.pld-linux.org Git - packages/kernel.git/blob - kernel-apparmor.patch
- rel 0.3
[packages/kernel.git] / kernel-apparmor.patch
1 From 0ae314bc92d8b22250f04f85e4bd36ee9ed30890 Mon Sep 17 00:00:00 2001
2 From: John Johansen <john.johansen@canonical.com>
3 Date: Mon, 4 Oct 2010 15:03:36 -0700
4 Subject: [PATCH 1/3] AppArmor: compatibility patch for v5 network controll
5
6 Add compatibility for v5 network rules.
7
8 Signed-off-by: John Johansen <john.johansen@canonical.com>
9 ---
10  include/linux/lsm_audit.h          |    4 +
11  security/apparmor/Makefile         |   19 ++++-
12  security/apparmor/include/net.h    |   40 +++++++++
13  security/apparmor/include/policy.h |    3 +
14  security/apparmor/lsm.c            |  112 +++++++++++++++++++++++
15  security/apparmor/net.c            |  170 ++++++++++++++++++++++++++++++++++++
16  security/apparmor/policy.c         |    1 +
17  security/apparmor/policy_unpack.c  |   48 ++++++++++-
18  8 files changed, 394 insertions(+), 3 deletions(-)
19  create mode 100644 security/apparmor/include/net.h
20  create mode 100644 security/apparmor/net.c
21
22 diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h
23 index 112a550..d5f3dd7 100644
24 --- a/include/linux/lsm_audit.h
25 +++ b/include/linux/lsm_audit.h
26 @@ -123,6 +123,10 @@ struct common_audit_data {
27                                         u32 denied;
28                                         uid_t ouid;
29                                 } fs;
30 +                               struct {
31 +                                       int type, protocol;
32 +                                       struct sock *sk;
33 +                               } net;
34                         };
35                 } apparmor_audit_data;
36  #endif
37 diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
38 index 2dafe50..7cefef9 100644
39 --- a/security/apparmor/Makefile
40 +++ b/security/apparmor/Makefile
41 @@ -4,9 +4,9 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
42  
43  apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
44                path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
45 -              resource.o sid.o file.o
46 +              resource.o sid.o file.o net.o
47  
48 -clean-files := capability_names.h rlim_names.h
49 +clean-files := capability_names.h rlim_names.h af_names.h
50  
51  
52  # Build a lower case string table of capability names
53 @@ -44,9 +44,24 @@ cmd_make-rlim = echo "static const char *rlim_names[] = {" > $@ ;\
54         sed -r -n "s/^\# ?define[ \t]+(RLIMIT_[A-Z0-9_]+).*/\1,/p" $< >> $@ ;\
55         echo "};" >> $@
56  
57 +# Build a lower case string table of address family names.
58 +# Transform lines from
59 +# #define AF_INET              2       /* Internet IP Protocol         */
60 +# to
61 +# [2] = "inet",
62 +quiet_cmd_make-af = GEN     $@
63 +cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\
64 +       sed $< >> $@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e \
65 +         's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+).*/[\2] = "\L\1",/p';\
66 +       echo "};" >> $@
67 +
68 +
69  $(obj)/capability.o : $(obj)/capability_names.h
70  $(obj)/resource.o : $(obj)/rlim_names.h
71 +$(obj)/net.o : $(obj)/af_names.h
72  $(obj)/capability_names.h : $(srctree)/include/linux/capability.h
73         $(call cmd,make-caps)
74  $(obj)/rlim_names.h : $(srctree)/include/asm-generic/resource.h
75         $(call cmd,make-rlim)
76 +$(obj)/af_names.h : $(srctree)/include/linux/socket.h
77 +       $(call cmd,make-af)
78 \ No newline at end of file
79 diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
80 new file mode 100644
81 index 0000000..3c7d599
82 --- /dev/null
83 +++ b/security/apparmor/include/net.h
84 @@ -0,0 +1,40 @@
85 +/*
86 + * AppArmor security module
87 + *
88 + * This file contains AppArmor network mediation definitions.
89 + *
90 + * Copyright (C) 1998-2008 Novell/SUSE
91 + * Copyright 2009-2010 Canonical Ltd.
92 + *
93 + * This program is free software; you can redistribute it and/or
94 + * modify it under the terms of the GNU General Public License as
95 + * published by the Free Software Foundation, version 2 of the
96 + * License.
97 + */
98 +
99 +#ifndef __AA_NET_H
100 +#define __AA_NET_H
101 +
102 +#include <net/sock.h>
103 +
104 +/* struct aa_net - network confinement data
105 + * @allowed: basic network families permissions
106 + * @audit_network: which network permissions to force audit
107 + * @quiet_network: which network permissions to quiet rejects
108 + */
109 +struct aa_net {
110 +       u16 allow[AF_MAX];
111 +       u16 audit[AF_MAX];
112 +       u16 quiet[AF_MAX];
113 +};
114 +
115 +extern int aa_net_perm(int op, struct aa_profile *profile, u16 family,
116 +                      int type, int protocol, struct sock *sk);
117 +extern int aa_revalidate_sk(int op, struct sock *sk);
118 +
119 +static inline void aa_free_net_rules(struct aa_net *new)
120 +{
121 +       /* NOP */
122 +}
123 +
124 +#endif /* __AA_NET_H */
125 diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
126 index aeda5cf..6776929 100644
127 --- a/security/apparmor/include/policy.h
128 +++ b/security/apparmor/include/policy.h
129 @@ -27,6 +27,7 @@
130  #include "capability.h"
131  #include "domain.h"
132  #include "file.h"
133 +#include "net.h"
134  #include "resource.h"
135  
136  extern const char *profile_mode_names[];
137 @@ -145,6 +146,7 @@ struct aa_namespace {
138   * @size: the memory consumed by this profiles rules
139   * @file: The set of rules governing basic file access and domain transitions
140   * @caps: capabilities for the profile
141 + * @net: network controls for the profile
142   * @rlimits: rlimits for the profile
143   *
144   * The AppArmor profile contains the basic confinement data.  Each profile
145 @@ -181,6 +183,7 @@ struct aa_profile {
146  
147         struct aa_file_rules file;
148         struct aa_caps caps;
149 +       struct aa_net net;
150         struct aa_rlimit rlimits;
151  };
152  
153 diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
154 index ae3a698..05c018b 100644
155 --- a/security/apparmor/lsm.c
156 +++ b/security/apparmor/lsm.c
157 @@ -32,6 +32,7 @@
158  #include "include/context.h"
159  #include "include/file.h"
160  #include "include/ipc.h"
161 +#include "include/net.h"
162  #include "include/path.h"
163  #include "include/policy.h"
164  #include "include/procattr.h"
165 @@ -610,5 +611,103 @@ static int apparmor_task_setrlimit(struct task_struct *task,
166         return error;
167  }
168  
169 +static int apparmor_socket_create(int family, int type, int protocol, int kern)
170 +{
171 +       struct aa_profile *profile;
172 +       int error = 0;
173 +
174 +       if (kern)
175 +               return 0;
176 +
177 +       profile = __aa_current_profile();
178 +       if (!unconfined(profile))
179 +               error = aa_net_perm(OP_CREATE, profile, family, type, protocol,
180 +                                   NULL);
181 +       return error;
182 +}
183 +
184 +static int apparmor_socket_bind(struct socket *sock,
185 +                               struct sockaddr *address, int addrlen)
186 +{
187 +       struct sock *sk = sock->sk;
188 +
189 +       return aa_revalidate_sk(OP_BIND, sk);
190 +}
191 +
192 +static int apparmor_socket_connect(struct socket *sock,
193 +                                  struct sockaddr *address, int addrlen)
194 +{
195 +       struct sock *sk = sock->sk;
196 +
197 +       return aa_revalidate_sk(OP_CONNECT, sk);
198 +}
199 +
200 +static int apparmor_socket_listen(struct socket *sock, int backlog)
201 +{
202 +       struct sock *sk = sock->sk;
203 +
204 +       return aa_revalidate_sk(OP_LISTEN, sk);
205 +}
206 +
207 +static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
208 +{
209 +       struct sock *sk = sock->sk;
210 +
211 +       return aa_revalidate_sk(OP_ACCEPT, sk);
212 +}
213 +
214 +static int apparmor_socket_sendmsg(struct socket *sock,
215 +                                  struct msghdr *msg, int size)
216 +{
217 +       struct sock *sk = sock->sk;
218 +
219 +       return aa_revalidate_sk(OP_SENDMSG, sk);
220 +}
221 +
222 +static int apparmor_socket_recvmsg(struct socket *sock,
223 +                                  struct msghdr *msg, int size, int flags)
224 +{
225 +       struct sock *sk = sock->sk;
226 +
227 +       return aa_revalidate_sk(OP_RECVMSG, sk);
228 +}
229 +
230 +static int apparmor_socket_getsockname(struct socket *sock)
231 +{
232 +       struct sock *sk = sock->sk;
233 +
234 +       return aa_revalidate_sk(OP_GETSOCKNAME, sk);
235 +}
236 +
237 +static int apparmor_socket_getpeername(struct socket *sock)
238 +{
239 +       struct sock *sk = sock->sk;
240 +
241 +       return aa_revalidate_sk(OP_GETPEERNAME, sk);
242 +}
243 +
244 +static int apparmor_socket_getsockopt(struct socket *sock, int level,
245 +                                     int optname)
246 +{
247 +       struct sock *sk = sock->sk;
248 +
249 +       return aa_revalidate_sk(OP_GETSOCKOPT, sk);
250 +}
251 +
252 +static int apparmor_socket_setsockopt(struct socket *sock, int level,
253 +                                     int optname)
254 +{
255 +       struct sock *sk = sock->sk;
256 +
257 +       return aa_revalidate_sk(OP_SETSOCKOPT, sk);
258 +}
259 +
260 +static int apparmor_socket_shutdown(struct socket *sock, int how)
261 +{
262 +       struct sock *sk = sock->sk;
263 +
264 +       return aa_revalidate_sk(OP_SOCK_SHUTDOWN, sk);
265 +}
266 +
267  static int apparmor_task_setrlimit(struct task_struct *task,
268                 unsigned int resource, struct rlimit *new_rlim)
269 @@ -651,6 +750,19 @@ static struct security_operations apparmor_ops = {
270         .getprocattr =                  apparmor_getprocattr,
271         .setprocattr =                  apparmor_setprocattr,
272  
273 +       .socket_create =                apparmor_socket_create,
274 +       .socket_bind =                  apparmor_socket_bind,
275 +       .socket_connect =               apparmor_socket_connect,
276 +       .socket_listen =                apparmor_socket_listen,
277 +       .socket_accept =                apparmor_socket_accept,
278 +       .socket_sendmsg =               apparmor_socket_sendmsg,
279 +       .socket_recvmsg =               apparmor_socket_recvmsg,
280 +       .socket_getsockname =           apparmor_socket_getsockname,
281 +       .socket_getpeername =           apparmor_socket_getpeername,
282 +       .socket_getsockopt =            apparmor_socket_getsockopt,
283 +       .socket_setsockopt =            apparmor_socket_setsockopt,
284 +       .socket_shutdown =              apparmor_socket_shutdown,
285 +
286         .cred_alloc_blank =             apparmor_cred_alloc_blank,
287         .cred_free =                    apparmor_cred_free,
288         .cred_prepare =                 apparmor_cred_prepare,
289 diff --git a/security/apparmor/net.c b/security/apparmor/net.c
290 new file mode 100644
291 index 0000000..1765901
292 --- /dev/null
293 +++ b/security/apparmor/net.c
294 @@ -0,0 +1,170 @@
295 +/*
296 + * AppArmor security module
297 + *
298 + * This file contains AppArmor network mediation
299 + *
300 + * Copyright (C) 1998-2008 Novell/SUSE
301 + * Copyright 2009-2010 Canonical Ltd.
302 + *
303 + * This program is free software; you can redistribute it and/or
304 + * modify it under the terms of the GNU General Public License as
305 + * published by the Free Software Foundation, version 2 of the
306 + * License.
307 + */
308 +
309 +#include "include/apparmor.h"
310 +#include "include/audit.h"
311 +#include "include/context.h"
312 +#include "include/net.h"
313 +#include "include/policy.h"
314 +
315 +#include "af_names.h"
316 +
317 +static const char *sock_type_names[] = {
318 +       "unknown(0)",
319 +       "stream",
320 +       "dgram",
321 +       "raw",
322 +       "rdm",
323 +       "seqpacket",
324 +       "dccp",
325 +       "unknown(7)",
326 +       "unknown(8)",
327 +       "unknown(9)",
328 +       "packet",
329 +};
330 +
331 +/* audit callback for net specific fields */
332 +static void audit_cb(struct audit_buffer *ab, void *va)
333 +{
334 +       struct common_audit_data *sa = va;
335 +
336 +       audit_log_format(ab, " family=");
337 +       if (address_family_names[sa->u.net.family]) {
338 +               audit_log_string(ab, address_family_names[sa->u.net.family]);
339 +       } else {
340 +               audit_log_format(ab, " \"unknown(%d)\"", sa->u.net.family);
341 +       }
342 +
343 +       audit_log_format(ab, " sock_type=");
344 +       if (sock_type_names[sa->aad.net.type]) {
345 +               audit_log_string(ab, sock_type_names[sa->aad.net.type]);
346 +       } else {
347 +               audit_log_format(ab, "\"unknown(%d)\"", sa->aad.net.type);
348 +       }
349 +
350 +       audit_log_format(ab, " protocol=%d", sa->aad.net.protocol);
351 +}
352 +
353 +/**
354 + * audit_net - audit network access
355 + * @profile: profile being enforced  (NOT NULL)
356 + * @op: operation being checked
357 + * @family: network family
358 + * @type:   network type
359 + * @protocol: network protocol
360 + * @sk: socket auditing is being applied to
361 + * @error: error code for failure else 0
362 + *
363 + * Returns: %0 or sa->error else other errorcode on failure
364 + */
365 +static int audit_net(struct aa_profile *profile, int op, u16 family, int type,
366 +                    int protocol, struct sock *sk, int error)
367 +{
368 +       int audit_type = AUDIT_APPARMOR_AUTO;
369 +       struct common_audit_data sa;
370 +       if (sk) {
371 +               COMMON_AUDIT_DATA_INIT(&sa, NET);
372 +       } else {
373 +               COMMON_AUDIT_DATA_INIT(&sa, NONE);
374 +       }
375 +       /* todo fill in socket addr info */
376 +
377 +       sa.aad.op = op,
378 +       sa.u.net.family = family;
379 +       sa.u.net.sk = sk;
380 +       sa.aad.net.type = type;
381 +       sa.aad.net.protocol = protocol;
382 +       sa.aad.error = error;
383 +
384 +       if (likely(!sa.aad.error)) {
385 +               u16 audit_mask = profile->net.audit[sa.u.net.family];
386 +               if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
387 +                          !(1 << sa.aad.net.type & audit_mask)))
388 +                       return 0;
389 +               audit_type = AUDIT_APPARMOR_AUDIT;
390 +       } else {
391 +               u16 quiet_mask = profile->net.quiet[sa.u.net.family];
392 +               u16 kill_mask = 0;
393 +               u16 denied = (1 << sa.aad.net.type) & ~quiet_mask;
394 +
395 +               if (denied & kill_mask)
396 +                       audit_type = AUDIT_APPARMOR_KILL;
397 +
398 +               if ((denied & quiet_mask) &&
399 +                   AUDIT_MODE(profile) != AUDIT_NOQUIET &&
400 +                   AUDIT_MODE(profile) != AUDIT_ALL)
401 +                       return COMPLAIN_MODE(profile) ? 0 : sa.aad.error;
402 +       }
403 +
404 +       return aa_audit(audit_type, profile, GFP_KERNEL, &sa, audit_cb);
405 +}
406 +
407 +/**
408 + * aa_net_perm - very course network access check
409 + * @op: operation being checked
410 + * @profile: profile being enforced  (NOT NULL)
411 + * @family: network family
412 + * @type:   network type
413 + * @protocol: network protocol
414 + *
415 + * Returns: %0 else error if permission denied
416 + */
417 +int aa_net_perm(int op, struct aa_profile *profile, u16 family, int type,
418 +               int protocol, struct sock *sk)
419 +{
420 +       u16 family_mask;
421 +       int error;
422 +
423 +       if ((family < 0) || (family >= AF_MAX))
424 +               return -EINVAL;
425 +
426 +       if ((type < 0) || (type >= SOCK_MAX))
427 +               return -EINVAL;
428 +
429 +       /* unix domain and netlink sockets are handled by ipc */
430 +       if (family == AF_UNIX || family == AF_NETLINK)
431 +               return 0;
432 +
433 +       family_mask = profile->net.allow[family];
434 +
435 +       error = (family_mask & (1 << type)) ? 0 : -EACCES;
436 +
437 +       return audit_net(profile, op, family, type, protocol, sk, error);
438 +}
439 +
440 +/**
441 + * aa_revalidate_sk - Revalidate access to a sock
442 + * @op: operation being checked
443 + * @sk: sock being revalidated  (NOT NULL)
444 + *
445 + * Returns: %0 else error if permission denied
446 + */
447 +int aa_revalidate_sk(int op, struct sock *sk)
448 +{
449 +       struct aa_profile *profile;
450 +       int error = 0;
451 +
452 +       /* aa_revalidate_sk should not be called from interrupt context
453 +        * don't mediate these calls as they are not task related
454 +        */
455 +       if (in_interrupt())
456 +               return 0;
457 +
458 +       profile = __aa_current_profile();
459 +       if (!unconfined(profile))
460 +               error = aa_net_perm(op, profile, sk->sk_family, sk->sk_type,
461 +                                   sk->sk_protocol, sk);
462 +
463 +       return error;
464 +}
465 diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
466 index 4f0eade..4d5ce13 100644
467 --- a/security/apparmor/policy.c
468 +++ b/security/apparmor/policy.c
469 @@ -745,6 +745,7 @@ static void free_profile(struct aa_profile *profile)
470  
471         aa_free_file_rules(&profile->file);
472         aa_free_cap_rules(&profile->caps);
473 +       aa_free_net_rules(&profile->net);
474         aa_free_rlimit_rules(&profile->rlimits);
475  
476         aa_free_sid(profile->sid);
477 diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
478 index e33aaf7..fa3f1b4 100644
479 --- a/security/apparmor/policy_unpack.c
480 +++ b/security/apparmor/policy_unpack.c
481 @@ -190,6 +190,19 @@ fail:
482         return 0;
483  }
484  
485 +static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name)
486 +{
487 +       if (unpack_nameX(e, AA_U16, name)) {
488 +               if (!inbounds(e, sizeof(u16)))
489 +                       return 0;
490 +               if (data)
491 +                       *data = le16_to_cpu(get_unaligned((u16 *) e->pos));
492 +               e->pos += sizeof(u16);
493 +               return 1;
494 +       }
495 +       return 0;
496 +}
497 +
498  static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
499  {
500         if (unpack_nameX(e, AA_U32, name)) {
501 @@ -468,7 +481,8 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
502  {
503         struct aa_profile *profile = NULL;
504         const char *name = NULL;
505 -       int error = -EPROTO;
506 +       size_t size = 0;
507 +       int i, error = -EPROTO;
508         kernel_cap_t tmpcap;
509         u32 tmp;
510  
511 @@ -559,6 +573,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
512         if (!unpack_rlimits(e, profile))
513                 goto fail;
514  
515 +       size = unpack_array(e, "net_allowed_af");
516 +       if (size) {
517 +
518 +               for (i = 0; i < size; i++) {
519 +                       /* discard extraneous rules that this kernel will
520 +                        * never request
521 +                        */
522 +                       if (i > AF_MAX) {
523 +                               u16 tmp;
524 +                               if (!unpack_u16(e, &tmp, NULL) ||
525 +                                   !unpack_u16(e, &tmp, NULL) ||
526 +                                   !unpack_u16(e, &tmp, NULL))
527 +                                       goto fail;
528 +                               continue;
529 +                       }
530 +                       if (!unpack_u16(e, &profile->net.allow[i], NULL))
531 +                               goto fail;
532 +                       if (!unpack_u16(e, &profile->net.audit[i], NULL))
533 +                               goto fail;
534 +                       if (!unpack_u16(e, &profile->net.quiet[i], NULL))
535 +                               goto fail;
536 +               }
537 +               if (!unpack_nameX(e, AA_ARRAYEND, NULL))
538 +                       goto fail;
539 +               /*
540 +                * allow unix domain and netlink sockets they are handled
541 +                * by IPC
542 +                */
543 +       }
544 +       profile->net.allow[AF_UNIX] = 0xffff;
545 +       profile->net.allow[AF_NETLINK] = 0xffff;
546 +
547         /* get file rules */
548         profile->file.dfa = unpack_dfa(e);
549         if (IS_ERR(profile->file.dfa)) {
550 -- 
551 1.7.0.4
552
553 From cdc6b35345e5bcfe92bb2b52ef003f94ceedd40d Mon Sep 17 00:00:00 2001
554 From: John Johansen <john.johansen@canonical.com>
555 Date: Thu, 22 Jul 2010 02:32:02 -0700
556 Subject: [PATCH 2/3] AppArmor: compatibility patch for v5 interface
557
558 Signed-off-by: John Johansen <john.johansen@canonical.com>
559 ---
560  security/apparmor/Kconfig              |    9 +
561  security/apparmor/Makefile             |    1 +
562  security/apparmor/apparmorfs-24.c      |  287 ++++++++++++++++++++++++++++++++
563  security/apparmor/apparmorfs.c         |   18 ++-
564  security/apparmor/include/apparmorfs.h |    6 +
565  5 files changed, 319 insertions(+), 2 deletions(-)
566  create mode 100644 security/apparmor/apparmorfs-24.c
567
568 diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig
569 index 9b9013b..51ebf96 100644
570 --- a/security/apparmor/Kconfig
571 +++ b/security/apparmor/Kconfig
572 @@ -29,3 +29,12 @@ config SECURITY_APPARMOR_BOOTPARAM_VALUE
573           boot.
574  
575           If you are unsure how to answer this question, answer 1.
576 +
577 +config SECURITY_APPARMOR_COMPAT_24
578 +       bool "Enable AppArmor 2.4 compatability"
579 +       depends on SECURITY_APPARMOR
580 +       default y
581 +       help
582 +         This option enables compatability with AppArmor 2.4.  It is
583 +          recommended if compatability with older versions of AppArmor
584 +          is desired.
585 diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
586 index 7cefef9..0bb604b 100644
587 --- a/security/apparmor/Makefile
588 +++ b/security/apparmor/Makefile
589 @@ -5,6 +5,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
590  apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
591                path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
592                resource.o sid.o file.o net.o
593 +apparmor-$(CONFIG_SECURITY_APPARMOR_COMPAT_24) += apparmorfs-24.o
594  
595  clean-files := capability_names.h rlim_names.h af_names.h
596  
597 diff --git a/security/apparmor/apparmorfs-24.c b/security/apparmor/apparmorfs-24.c
598 new file mode 100644
599 index 0000000..dc8c744
600 --- /dev/null
601 +++ b/security/apparmor/apparmorfs-24.c
602 @@ -0,0 +1,287 @@
603 +/*
604 + * AppArmor security module
605 + *
606 + * This file contains AppArmor /sys/kernel/secrutiy/apparmor interface functions
607 + *
608 + * Copyright (C) 1998-2008 Novell/SUSE
609 + * Copyright 2009-2010 Canonical Ltd.
610 + *
611 + * This program is free software; you can redistribute it and/or
612 + * modify it under the terms of the GNU General Public License as
613 + * published by the Free Software Foundation, version 2 of the
614 + * License.
615 + *
616 + *
617 + * This file contain functions providing an interface for <= AppArmor 2.4
618 + * compatibility.  It is dependent on CONFIG_SECURITY_APPARMOR_COMPAT_24
619 + * being set (see Makefile).
620 + */
621 +
622 +#include <linux/security.h>
623 +#include <linux/vmalloc.h>
624 +#include <linux/module.h>
625 +#include <linux/seq_file.h>
626 +#include <linux/uaccess.h>
627 +#include <linux/namei.h>
628 +
629 +#include "include/apparmor.h"
630 +#include "include/audit.h"
631 +#include "include/context.h"
632 +#include "include/policy.h"
633 +
634 +
635 +/* apparmor/matching */
636 +static ssize_t aa_matching_read(struct file *file, char __user *buf,
637 +                               size_t size, loff_t *ppos)
638 +{
639 +       const char matching[] = "pattern=aadfa audit perms=crwxamlk/ "
640 +           "user::other";
641 +
642 +       return simple_read_from_buffer(buf, size, ppos, matching,
643 +                                      sizeof(matching) - 1);
644 +}
645 +
646 +const struct file_operations aa_fs_matching_fops = {
647 +       .read = aa_matching_read,
648 +};
649 +
650 +/* apparmor/features */
651 +static ssize_t aa_features_read(struct file *file, char __user *buf,
652 +                               size_t size, loff_t *ppos)
653 +{
654 +       const char features[] = "file=3.1 capability=2.0 network=1.0 "
655 +           "change_hat=1.5 change_profile=1.1 " "aanamespaces=1.1 rlimit=1.1";
656 +
657 +       return simple_read_from_buffer(buf, size, ppos, features,
658 +                                      sizeof(features) - 1);
659 +}
660 +
661 +const struct file_operations aa_fs_features_fops = {
662 +       .read = aa_features_read,
663 +};
664 +
665 +/**
666 + * __next_namespace - find the next namespace to list
667 + * @root: root namespace to stop search at (NOT NULL)
668 + * @ns: current ns position (NOT NULL)
669 + *
670 + * Find the next namespace from @ns under @root and handle all locking needed
671 + * while switching current namespace.
672 + *
673 + * Returns: next namespace or NULL if at last namespace under @root
674 + * NOTE: will not unlock root->lock
675 + */
676 +static struct aa_namespace *__next_namespace(struct aa_namespace *root,
677 +                                            struct aa_namespace *ns)
678 +{
679 +       struct aa_namespace *parent;
680 +
681 +       /* is next namespace a child */
682 +       if (!list_empty(&ns->sub_ns)) {
683 +               struct aa_namespace *next;
684 +               next = list_first_entry(&ns->sub_ns, typeof(*ns), base.list);
685 +               read_lock(&next->lock);
686 +               return next;
687 +       }
688 +
689 +       /* check if the next ns is a sibling, parent, gp, .. */
690 +       parent = ns->parent;
691 +       while (parent) {
692 +               read_unlock(&ns->lock);
693 +               list_for_each_entry_continue(ns, &parent->sub_ns, base.list) {
694 +                       read_lock(&ns->lock);
695 +                       return ns;
696 +               }
697 +               if (parent == root)
698 +                       return NULL;
699 +               ns = parent;
700 +               parent = parent->parent;
701 +       }
702 +
703 +       return NULL;
704 +}
705 +
706 +/**
707 + * __first_profile - find the first profile in a namespace
708 + * @root: namespace that is root of profiles being displayed (NOT NULL)
709 + * @ns: namespace to start in   (NOT NULL)
710 + *
711 + * Returns: unrefcounted profile or NULL if no profile
712 + */
713 +static struct aa_profile *__first_profile(struct aa_namespace *root,
714 +                                         struct aa_namespace *ns)
715 +{
716 +       for ( ; ns; ns = __next_namespace(root, ns)) {
717 +               if (!list_empty(&ns->base.profiles))
718 +                       return list_first_entry(&ns->base.profiles,
719 +                                               struct aa_profile, base.list);
720 +       }
721 +       return NULL;
722 +}
723 +
724 +/**
725 + * __next_profile - step to the next profile in a profile tree
726 + * @profile: current profile in tree (NOT NULL)
727 + *
728 + * Perform a depth first taversal on the profile tree in a namespace
729 + *
730 + * Returns: next profile or NULL if done
731 + * Requires: profile->ns.lock to be held
732 + */
733 +static struct aa_profile *__next_profile(struct aa_profile *p)
734 +{
735 +       struct aa_profile *parent;
736 +       struct aa_namespace *ns = p->ns;
737 +
738 +       /* is next profile a child */
739 +       if (!list_empty(&p->base.profiles))
740 +               return list_first_entry(&p->base.profiles, typeof(*p),
741 +                                       base.list);
742 +
743 +       /* is next profile a sibling, parent sibling, gp, subling, .. */
744 +       parent = p->parent;
745 +       while (parent) {
746 +               list_for_each_entry_continue(p, &parent->base.profiles,
747 +                                            base.list)
748 +                               return p;
749 +               p = parent;
750 +               parent = parent->parent;
751 +       }
752 +
753 +       /* is next another profile in the namespace */
754 +       list_for_each_entry_continue(p, &ns->base.profiles, base.list)
755 +               return p;
756 +
757 +       return NULL;
758 +}
759 +
760 +/**
761 + * next_profile - step to the next profile in where ever it may be
762 + * @root: root namespace  (NOT NULL)
763 + * @profile: current profile  (NOT NULL)
764 + *
765 + * Returns: next profile or NULL if there isn't one
766 + */
767 +static struct aa_profile *next_profile(struct aa_namespace *root,
768 +                                      struct aa_profile *profile)
769 +{
770 +       struct aa_profile *next = __next_profile(profile);
771 +       if (next)
772 +               return next;
773 +
774 +       /* finished all profiles in namespace move to next namespace */
775 +       return __first_profile(root, __next_namespace(root, profile->ns));
776 +}
777 +
778 +/**
779 + * p_start - start a depth first traversal of profile tree
780 + * @f: seq_file to fill
781 + * @pos: current position
782 + *
783 + * Returns: first profile under current namespace or NULL if none found
784 + *
785 + * acquires first ns->lock
786 + */
787 +static void *p_start(struct seq_file *f, loff_t *pos)
788 +       __acquires(root->lock)
789 +{
790 +       struct aa_profile *profile = NULL;
791 +       struct aa_namespace *root = aa_current_profile()->ns;
792 +       loff_t l = *pos;
793 +       f->private = aa_get_namespace(root);
794 +
795 +
796 +       /* find the first profile */
797 +       read_lock(&root->lock);
798 +       profile = __first_profile(root, root);
799 +
800 +       /* skip to position */
801 +       for (; profile && l > 0; l--)
802 +               profile = next_profile(root, profile);
803 +
804 +       return profile;
805 +}
806 +
807 +/**
808 + * p_next - read the next profile entry
809 + * @f: seq_file to fill
810 + * @p: profile previously returned
811 + * @pos: current position
812 + *
813 + * Returns: next profile after @p or NULL if none
814 + *
815 + * may acquire/release locks in namespace tree as necessary
816 + */
817 +static void *p_next(struct seq_file *f, void *p, loff_t *pos)
818 +{
819 +       struct aa_profile *profile = p;
820 +       struct aa_namespace *root = f->private;
821 +       (*pos)++;
822 +
823 +       return next_profile(root, profile);
824 +}
825 +
826 +/**
827 + * p_stop - stop depth first traversal
828 + * @f: seq_file we are filling
829 + * @p: the last profile writen
830 + *
831 + * Release all locking done by p_start/p_next on namespace tree
832 + */
833 +static void p_stop(struct seq_file *f, void *p)
834 +       __releases(root->lock)
835 +{
836 +       struct aa_profile *profile = p;
837 +       struct aa_namespace *root = f->private, *ns;
838 +
839 +       if (profile) {
840 +               for (ns = profile->ns; ns && ns != root; ns = ns->parent)
841 +                       read_unlock(&ns->lock);
842 +       }
843 +       read_unlock(&root->lock);
844 +       aa_put_namespace(root);
845 +}
846 +
847 +/**
848 + * seq_show_profile - show a profile entry
849 + * @f: seq_file to file
850 + * @p: current position (profile)    (NOT NULL)
851 + *
852 + * Returns: error on failure
853 + */
854 +static int seq_show_profile(struct seq_file *f, void *p)
855 +{
856 +       struct aa_profile *profile = (struct aa_profile *)p;
857 +       struct aa_namespace *root = f->private;
858 +
859 +       if (profile->ns != root)
860 +               seq_printf(f, ":%s://", aa_ns_name(root, profile->ns));
861 +       seq_printf(f, "%s (%s)\n", profile->base.hname,
862 +                  COMPLAIN_MODE(profile) ? "complain" : "enforce");
863 +
864 +       return 0;
865 +}
866 +
867 +static const struct seq_operations aa_fs_profiles_op = {
868 +       .start = p_start,
869 +       .next = p_next,
870 +       .stop = p_stop,
871 +       .show = seq_show_profile,
872 +};
873 +
874 +static int profiles_open(struct inode *inode, struct file *file)
875 +{
876 +       return seq_open(file, &aa_fs_profiles_op);
877 +}
878 +
879 +static int profiles_release(struct inode *inode, struct file *file)
880 +{
881 +       return seq_release(inode, file);
882 +}
883 +
884 +const struct file_operations aa_fs_profiles_fops = {
885 +       .open = profiles_open,
886 +       .read = seq_read,
887 +       .llseek = seq_lseek,
888 +       .release = profiles_release,
889 +};
890 diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
891 index 0848292..28c52ac 100644
892 --- a/security/apparmor/apparmorfs.c
893 +++ b/security/apparmor/apparmorfs.c
894 @@ -187,7 +187,11 @@ void __init aa_destroy_aafs(void)
895                 aafs_remove(".remove");
896                 aafs_remove(".replace");
897                 aafs_remove(".load");
898 -
899 +#ifdef CONFIG_SECURITY_APPARMOR_COMPAT_24
900 +               aafs_remove("profiles");
901 +               aafs_remove("matching");
902 +               aafs_remove("features");
903 +#endif
904                 securityfs_remove(aa_fs_dentry);
905                 aa_fs_dentry = NULL;
906         }
907 @@ -218,7 +222,17 @@ int __init aa_create_aafs(void)
908                 aa_fs_dentry = NULL;
909                 goto error;
910         }
911 -
912 +#ifdef CONFIG_SECURITY_APPARMOR_COMPAT_24
913 +       error = aafs_create("matching", 0444, &aa_fs_matching_fops);
914 +       if (error)
915 +               goto error;
916 +       error = aafs_create("features", 0444, &aa_fs_features_fops);
917 +       if (error)
918 +               goto error;
919 +#endif
920 +       error = aafs_create("profiles", 0440, &aa_fs_profiles_fops);
921 +       if (error)
922 +               goto error;
923         error = aafs_create(".load", 0640, &aa_fs_profile_load);
924         if (error)
925                 goto error;
926 diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h
927 index cb1e93a..14f955c 100644
928 --- a/security/apparmor/include/apparmorfs.h
929 +++ b/security/apparmor/include/apparmorfs.h
930 @@ -17,4 +17,10 @@
931  
932  extern void __init aa_destroy_aafs(void);
933  
934 +#ifdef CONFIG_SECURITY_APPARMOR_COMPAT_24
935 +extern const struct file_operations aa_fs_matching_fops;
936 +extern const struct file_operations aa_fs_features_fops;
937 +extern const struct file_operations aa_fs_profiles_fops;
938 +#endif
939 +
940  #endif /* __AA_APPARMORFS_H */
941 -- 
942 1.7.0.4
943
944 From f17b28f64b963c47e76737f7bb7f58ce3a7c5249 Mon Sep 17 00:00:00 2001
945 From: John Johansen <john.johansen@canonical.com>
946 Date: Tue, 20 Jul 2010 06:57:08 -0700
947 Subject: [PATCH 3/3] AppArmor: Allow dfa backward compatibility with broken userspace
948
949 The apparmor_parser when compiling policy could generate invalid dfas
950 that did not have sufficient padding to avoid invalid references, when
951 used by the kernel.  The kernels check to verify the next/check table
952 size was broken meaning invalid dfas were being created by userspace
953 and not caught.
954
955 To remain compatible with old tools that are not fixed, pad the loaded
956 dfas next/check table.  The dfa's themselves are valid except for the
957 high padding for potentially invalid transitions (high bounds error),
958 which have a maximimum is 256 entries.  So just allocate an extra null filled
959 256 entries for the next/check tables.  This will guarentee all bounds
960 are good and invalid transitions go to the null (0) state.
961
962 Signed-off-by: John Johansen <john.johansen@canonical.com>
963 ---
964  security/apparmor/match.c |   17 +++++++++++++++++
965  1 files changed, 17 insertions(+), 0 deletions(-)
966
967 diff --git a/security/apparmor/match.c b/security/apparmor/match.c
968 index 06d764c..cf92856 100644
969 --- a/security/apparmor/match.c
970 +++ b/security/apparmor/match.c
971 @@ -57,8 +57,17 @@ static struct table_header *unpack_table(char *blob, size_t bsize)
972         if (bsize < tsize)
973                 goto out;
974  
975 +       /* Pad table allocation for next/check by 256 entries to remain
976 +        * backwards compatible with old (buggy) tools and remain safe without
977 +        * run time checks
978 +        */
979 +       if (th.td_id == YYTD_ID_NXT || th.td_id == YYTD_ID_CHK)
980 +               tsize += 256 * th.td_flags;
981 +
982         table = kvmalloc(tsize);
983         if (table) {
984 +               /* ensure the pad is clear, else there will be errors */
985 +               memset(table, 0, tsize);
986                 *table = th;
987                 if (th.td_flags == YYTD_DATA8)
988                         UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
989 @@ -134,11 +143,19 @@ static int verify_dfa(struct aa_dfa *dfa, int flags)
990                 goto out;
991  
992         if (flags & DFA_FLAG_VERIFY_STATES) {
993 +               int warning = 0;
994                 for (i = 0; i < state_count; i++) {
995                         if (DEFAULT_TABLE(dfa)[i] >= state_count)
996                                 goto out;
997                         /* TODO: do check that DEF state recursion terminates */
998                         if (BASE_TABLE(dfa)[i] + 255 >= trans_count) {
999 +                               if (warning)
1000 +                                       continue;
1001 +                               printk(KERN_WARNING "AppArmor DFA next/check "
1002 +                                      "upper bounds error fixed, upgrade "
1003 +                                      "user space tools \n");
1004 +                               warning = 1;
1005 +                       } else if (BASE_TABLE(dfa)[i] >= trans_count) {
1006                                 printk(KERN_ERR "AppArmor DFA next/check upper "
1007                                        "bounds error\n");
1008                                 goto out;
1009 -- 
1010 1.7.0.4
1011
This page took 0.111528 seconds and 4 git commands to generate.