]> git.pld-linux.org Git - packages/kernel.git/commitdiff
- rel 2; apparmor is back (upstream merged all apparmor patches, so upcoming 4.14... auto/th/kernel-4.13.2-2 auto/th/kernel-nopae-4.13.2-2
authorArkadiusz Miśkiewicz <arekm@maven.pl>
Fri, 15 Sep 2017 07:15:06 +0000 (09:15 +0200)
committerArkadiusz Miśkiewicz <arekm@maven.pl>
Fri, 15 Sep 2017 07:15:06 +0000 (09:15 +0200)
21 files changed:
0001-Enable-SCSI_CONSTANTS-The-error-messages-regarding-y.patch [new file with mode: 0644]
0001-UBUNTU-SAUCE-efi-lockdown-MODSIGN-Fix-module-signatu.patch [new file with mode: 0644]
0002-apparmor-Fix-shadowed-local-variable-in-unpack_trans.patch [new file with mode: 0644]
0003-apparmor-Fix-logical-error-in-verify_header.patch [new file with mode: 0644]
0004-apparmor-Fix-an-error-code-in-aafs_create.patch [new file with mode: 0644]
0005-apparmor-Redundant-condition-prev_ns.-in-label.c-149.patch [new file with mode: 0644]
0006-apparmor-add-the-ability-to-mediate-signals.patch [new file with mode: 0644]
0007-apparmor-add-mount-mediation.patch [moved from kernel-apparmor-mount.patch with 50% similarity]
0008-apparmor-cleanup-conditional-check-for-label-in-labe.patch [new file with mode: 0644]
0009-apparmor-add-support-for-absolute-root-view-based-la.patch [new file with mode: 0644]
0010-apparmor-make-policy_unpack-able-to-audit-different-.patch [new file with mode: 0644]
0011-apparmor-add-more-debug-asserts-to-apparmorfs.patch [new file with mode: 0644]
0012-apparmor-add-base-infastructure-for-socket-mediation.patch [new file with mode: 0644]
0013-apparmor-move-new_null_profile-to-after-profile-look.patch [new file with mode: 0644]
0014-apparmor-fix-race-condition-in-null-profile-creation.patch [new file with mode: 0644]
0015-apparmor-ensure-unconfined-profiles-have-dfas-initia.patch [new file with mode: 0644]
0016-apparmor-fix-incorrect-type-assignment-when-freeing-.patch [new file with mode: 0644]
0017-UBUNTU-SAUCE-apparmor-af_unix-mediation.patch [new file with mode: 0644]
kernel-apparmor-net-audit.patch [deleted file]
kernel-apparmor-net.patch [deleted file]
kernel.spec

diff --git a/0001-Enable-SCSI_CONSTANTS-The-error-messages-regarding-y.patch b/0001-Enable-SCSI_CONSTANTS-The-error-messages-regarding-y.patch
new file mode 100644 (file)
index 0000000..7b35483
--- /dev/null
@@ -0,0 +1,26 @@
+From 3cf99fb519595e3934882ac9ea32409badc6b57a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Arkadiusz=20Mi=C5=9Bkiewicz?= <arekm@maven.pl>
+Date: Fri, 27 Jun 2014 13:50:25 +0200
+Subject: [PATCH] Enable SCSI_CONSTANTS; The error messages regarding your SCSI
+ hardware will be easier to understand if you say Y here.
+
+---
+ kernel-multiarch.config | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/kernel-multiarch.config b/kernel-multiarch.config
+index ea15c17..8aee3c6 100644
+--- a/kernel-multiarch.config
++++ b/kernel-multiarch.config
+@@ -4513,7 +4513,7 @@ CHR_DEV_SG all=m
+ CHR_DEV_SCH all=m
+ SCSI_ENCLOSURE all=m
+ SCSI_MULTI_LUN all=y
+-SCSI_CONSTANTS all=n
++SCSI_CONSTANTS all=y
+ SCSI_LOGGING all=y
+ SCSI_SCAN_ASYNC all=y
+ SCSI_WAIT_SCAN all=m
+-- 
+2.0.0
+
diff --git a/0001-UBUNTU-SAUCE-efi-lockdown-MODSIGN-Fix-module-signatu.patch b/0001-UBUNTU-SAUCE-efi-lockdown-MODSIGN-Fix-module-signatu.patch
new file mode 100644 (file)
index 0000000..6401a55
--- /dev/null
@@ -0,0 +1,41 @@
+From 00c72bc198aa85e5da02de2c0c4cc423c82a54f1 Mon Sep 17 00:00:00 2001
+From: Fedora Kernel Team <kernel-team@fedoraproject.org>
+Date: Thu, 3 Aug 2017 13:46:51 -0500
+Subject: [PATCH 01/17] UBUNTU: SAUCE: (efi-lockdown) MODSIGN: Fix module
+ signature verification
+
+BugLink: http://bugs.launchpad.net/bugs/1712168
+
+Currently mod_verify_sig() calls verify_pkcs_7_signature() with
+trusted_keys=NULL, which causes only the builtin keys to be used
+to verify the signature. This breaks self-signing of modules with
+a MOK, as the MOK is loaded into the secondary trusted keyring.
+Fix this by passing the spacial value trusted_keys=(void *)1UL,
+which tells verify_pkcs_7_signature() to use the secondary
+keyring instead.
+
+(cherry picked from commit cff4523d65b848f9c41c9e998a735ae2a820da2d
+ git://git.kernel.org/pub/scm/linux/kernel/git/jwboyer/fedora.git)
+[ saf: Taken from fedora commit without authorship information or much
+  of a commit message; modified so that commit will describe the
+  problem being fixed. ]
+Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
+---
+ kernel/module_signing.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/kernel/module_signing.c b/kernel/module_signing.c
+index 937c844bee4a..d3d6f95a96b4 100644
+--- a/kernel/module_signing.c
++++ b/kernel/module_signing.c
+@@ -81,6 +81,6 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen)
+       }
+       return verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len,
+-                                    NULL, VERIFYING_MODULE_SIGNATURE,
++                                    (void *)1UL, VERIFYING_MODULE_SIGNATURE,
+                                     NULL, NULL);
+ }
+-- 
+2.11.0
+
diff --git a/0002-apparmor-Fix-shadowed-local-variable-in-unpack_trans.patch b/0002-apparmor-Fix-shadowed-local-variable-in-unpack_trans.patch
new file mode 100644 (file)
index 0000000..4d9836d
--- /dev/null
@@ -0,0 +1,51 @@
+From c6cad5e65a23dcafa1821ca381901297664d9c64 Mon Sep 17 00:00:00 2001
+From: Geert Uytterhoeven <geert@linux-m68k.org>
+Date: Thu, 6 Jul 2017 10:56:21 +0200
+Subject: [PATCH 02/17] apparmor: Fix shadowed local variable in
+ unpack_trans_table()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+with W=2:
+
+    security/apparmor/policy_unpack.c: In function ‘unpack_trans_table’:
+    security/apparmor/policy_unpack.c:469: warning: declaration of ‘pos’ shadows a previous local
+    security/apparmor/policy_unpack.c:451: warning: shadowed declaration is here
+
+Rename the old "pos" to "saved_pos" to fix this.
+
+Fixes: 5379a3312024a8be ("apparmor: support v7 transition format compatible with label_parse")
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+Reviewed-by: Serge Hallyn <serge@hallyn.com>
+Signed-off-by: John Johansen <john.johansen@canonical.com>
+(cherry picked from commit 966d631935a578fadb5770f17a957ee1a969d868)
+---
+ security/apparmor/policy_unpack.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
+index c600f4dd1783..2d5a1a007b06 100644
+--- a/security/apparmor/policy_unpack.c
++++ b/security/apparmor/policy_unpack.c
+@@ -448,7 +448,7 @@ static struct aa_dfa *unpack_dfa(struct aa_ext *e)
+  */
+ static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile)
+ {
+-      void *pos = e->pos;
++      void *saved_pos = e->pos;
+       /* exec table is optional */
+       if (unpack_nameX(e, AA_STRUCT, "xtable")) {
+@@ -511,7 +511,7 @@ static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile)
+ fail:
+       aa_free_domain_entries(&profile->file.trans);
+-      e->pos = pos;
++      e->pos = saved_pos;
+       return 0;
+ }
+-- 
+2.11.0
+
diff --git a/0003-apparmor-Fix-logical-error-in-verify_header.patch b/0003-apparmor-Fix-logical-error-in-verify_header.patch
new file mode 100644 (file)
index 0000000..be4f854
--- /dev/null
@@ -0,0 +1,32 @@
+From 9934296cba701d429a0fc0cf071a40c8c3a1587e Mon Sep 17 00:00:00 2001
+From: Christos Gkekas <chris.gekas@gmail.com>
+Date: Sat, 8 Jul 2017 20:50:21 +0100
+Subject: [PATCH 03/17] apparmor: Fix logical error in verify_header()
+
+verify_header() is currently checking whether interface version is less
+than 5 *and* greater than 7, which always evaluates to false. Instead it
+should check whether it is less than 5 *or* greater than 7.
+
+Signed-off-by: Christos Gkekas <chris.gekas@gmail.com>
+Signed-off-by: John Johansen <john.johansen@canonical.com>
+(cherry picked from commit c54a2175e3a6bf6c697d249bba1aa729e06c7ba8)
+---
+ security/apparmor/policy_unpack.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
+index 2d5a1a007b06..bda0dce3b582 100644
+--- a/security/apparmor/policy_unpack.c
++++ b/security/apparmor/policy_unpack.c
+@@ -832,7 +832,7 @@ static int verify_header(struct aa_ext *e, int required, const char **ns)
+        * if not specified use previous version
+        * Mask off everything that is not kernel abi version
+        */
+-      if (VERSION_LT(e->version, v5) && VERSION_GT(e->version, v7)) {
++      if (VERSION_LT(e->version, v5) || VERSION_GT(e->version, v7)) {
+               audit_iface(NULL, NULL, NULL, "unsupported interface version",
+                           e, error);
+               return error;
+-- 
+2.11.0
+
diff --git a/0004-apparmor-Fix-an-error-code-in-aafs_create.patch b/0004-apparmor-Fix-an-error-code-in-aafs_create.patch
new file mode 100644 (file)
index 0000000..4e937e0
--- /dev/null
@@ -0,0 +1,37 @@
+From 8b3851c7b83f32f2be9d4b48371ddf033afedf62 Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Thu, 13 Jul 2017 10:39:20 +0300
+Subject: [PATCH 04/17] apparmor: Fix an error code in aafs_create()
+
+We accidentally forgot to set the error code on this path.  It means we
+return NULL instead of an error pointer.  I looked through a bunch of
+callers and I don't think it really causes a big issue, but the
+documentation says we're supposed to return error pointers here.
+
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+Acked-by: Serge Hallyn <serge@hallyn.com>
+Signed-off-by: John Johansen <john.johansen@canonical.com>
+(cherry picked from commit aee58bf341db52a3a3563c6b972bfd4fc2d41e46)
+---
+ security/apparmor/apparmorfs.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
+index 853c2ec8e0c9..2caeb748070c 100644
+--- a/security/apparmor/apparmorfs.c
++++ b/security/apparmor/apparmorfs.c
+@@ -248,8 +248,10 @@ static struct dentry *aafs_create(const char *name, umode_t mode,
+       inode_lock(dir);
+       dentry = lookup_one_len(name, parent, strlen(name));
+-      if (IS_ERR(dentry))
++      if (IS_ERR(dentry)) {
++              error = PTR_ERR(dentry);
+               goto fail_lock;
++      }
+       if (d_really_is_positive(dentry)) {
+               error = -EEXIST;
+-- 
+2.11.0
+
diff --git a/0005-apparmor-Redundant-condition-prev_ns.-in-label.c-149.patch b/0005-apparmor-Redundant-condition-prev_ns.-in-label.c-149.patch
new file mode 100644 (file)
index 0000000..beea3de
--- /dev/null
@@ -0,0 +1,29 @@
+From 4b56e146905bbad2c79ea92e3f49e210ca527572 Mon Sep 17 00:00:00 2001
+From: John Johansen <john.johansen@canonical.com>
+Date: Mon, 31 Jul 2017 23:44:37 -0700
+Subject: [PATCH 05/17] apparmor: Redundant condition: prev_ns. in
+ [label.c:1498]
+
+Reported-by: David Binderman <dcb314@hotmail.com>
+Signed-off-by: John Johansen <john.johansen@canonical.com>
+(cherry picked from commit d323d2c17cfcc54b6845bfc1d13bca5cef210fc7)
+---
+ security/apparmor/label.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/security/apparmor/label.c b/security/apparmor/label.c
+index e052eaba1cf6..e324f4df3e34 100644
+--- a/security/apparmor/label.c
++++ b/security/apparmor/label.c
+@@ -1495,7 +1495,7 @@ static int aa_profile_snxprint(char *str, size_t size, struct aa_ns *view,
+               view = profiles_ns(profile);
+       if (view != profile->ns &&
+-          (!prev_ns || (prev_ns && *prev_ns != profile->ns))) {
++          (!prev_ns || (*prev_ns != profile->ns))) {
+               if (prev_ns)
+                       *prev_ns = profile->ns;
+               ns_name = aa_ns_name(view, profile->ns,
+-- 
+2.11.0
+
diff --git a/0006-apparmor-add-the-ability-to-mediate-signals.patch b/0006-apparmor-add-the-ability-to-mediate-signals.patch
new file mode 100644 (file)
index 0000000..ee3672d
--- /dev/null
@@ -0,0 +1,397 @@
+From f9e20353a6c5726775867db81b6085e8ab425a36 Mon Sep 17 00:00:00 2001
+From: John Johansen <john.johansen@canonical.com>
+Date: Tue, 18 Jul 2017 22:56:22 -0700
+Subject: [PATCH 06/17] apparmor: add the ability to mediate signals
+
+Add signal mediation where the signal can be mediated based on the
+signal, direction, or the label or the peer/target. The signal perms
+are verified on a cross check to ensure policy consistency in the case
+of incremental policy load/replacement.
+
+The optimization of skipping the cross check when policy is guaranteed
+to be consistent (single compile unit) remains to be done.
+
+policy rules have the form of
+  SIGNAL_RULE = [ QUALIFIERS ] 'signal' [ SIGNAL ACCESS PERMISSIONS ]
+                [ SIGNAL SET ] [ SIGNAL PEER ]
+
+  SIGNAL ACCESS PERMISSIONS = SIGNAL ACCESS | SIGNAL ACCESS LIST
+
+  SIGNAL ACCESS LIST = '(' Comma or space separated list of SIGNAL
+                           ACCESS ')'
+
+  SIGNAL ACCESS = ( 'r' | 'w' | 'rw' | 'read' | 'write' | 'send' |
+                    'receive' )
+
+  SIGNAL SET = 'set' '=' '(' SIGNAL LIST ')'
+
+  SIGNAL LIST = Comma or space separated list of SIGNALS
+
+  SIGNALS = ( 'hup' | 'int' | 'quit' | 'ill' | 'trap' | 'abrt' |
+              'bus' | 'fpe' | 'kill' | 'usr1' | 'segv' | 'usr2' |
+             'pipe' | 'alrm' | 'term' | 'stkflt' | 'chld' | 'cont' |
+             'stop' | 'stp' | 'ttin' | 'ttou' | 'urg' | 'xcpu' |
+             'xfsz' | 'vtalrm' | 'prof' | 'winch' | 'io' | 'pwr' |
+             'sys' | 'emt' | 'exists' | 'rtmin+0' ... 'rtmin+32'
+            )
+
+  SIGNAL PEER = 'peer' '=' AARE
+
+eg.
+  signal,                                 # allow all signals
+  signal send set=(hup, kill) peer=foo,
+
+Signed-off-by: John Johansen <john.johansen@canonical.com>
+Acked-by: Seth Arnold <seth.arnold@canonical.com>
+(cherry picked from commit c6bf1adaecaa719d7c56338cc43b2982214f2f44)
+---
+ security/apparmor/apparmorfs.c        |  7 +++
+ security/apparmor/include/apparmor.h  |  1 +
+ security/apparmor/include/audit.h     |  2 +
+ security/apparmor/include/ipc.h       |  6 +++
+ security/apparmor/include/sig_names.h | 95 +++++++++++++++++++++++++++++++++
+ security/apparmor/ipc.c               | 99 +++++++++++++++++++++++++++++++++++
+ security/apparmor/lsm.c               | 21 ++++++++
+ 7 files changed, 231 insertions(+)
+ create mode 100644 security/apparmor/include/sig_names.h
+
+diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
+index 2caeb748070c..a5f9e1aa51f7 100644
+--- a/security/apparmor/apparmorfs.c
++++ b/security/apparmor/apparmorfs.c
+@@ -32,6 +32,7 @@
+ #include "include/audit.h"
+ #include "include/context.h"
+ #include "include/crypto.h"
++#include "include/ipc.h"
+ #include "include/policy_ns.h"
+ #include "include/label.h"
+ #include "include/policy.h"
+@@ -2129,6 +2130,11 @@ static struct aa_sfs_entry aa_sfs_entry_ptrace[] = {
+       { }
+ };
++static struct aa_sfs_entry aa_sfs_entry_signal[] = {
++      AA_SFS_FILE_STRING("mask", AA_SFS_SIG_MASK),
++      { }
++};
++
+ static struct aa_sfs_entry aa_sfs_entry_domain[] = {
+       AA_SFS_FILE_BOOLEAN("change_hat",       1),
+       AA_SFS_FILE_BOOLEAN("change_hatv",      1),
+@@ -2179,6 +2185,7 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = {
+       AA_SFS_DIR("rlimit",                    aa_sfs_entry_rlimit),
+       AA_SFS_DIR("caps",                      aa_sfs_entry_caps),
+       AA_SFS_DIR("ptrace",                    aa_sfs_entry_ptrace),
++      AA_SFS_DIR("signal",                    aa_sfs_entry_signal),
+       AA_SFS_DIR("query",                     aa_sfs_entry_query),
+       { }
+ };
+diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
+index aaf893f4e4f5..962a20a75e01 100644
+--- a/security/apparmor/include/apparmor.h
++++ b/security/apparmor/include/apparmor.h
+@@ -28,6 +28,7 @@
+ #define AA_CLASS_RLIMITS      5
+ #define AA_CLASS_DOMAIN               6
+ #define AA_CLASS_PTRACE               9
++#define AA_CLASS_SIGNAL               10
+ #define AA_CLASS_LABEL                16
+ #define AA_CLASS_LAST         AA_CLASS_LABEL
+diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
+index c68839a44351..d9a156ae11b9 100644
+--- a/security/apparmor/include/audit.h
++++ b/security/apparmor/include/audit.h
+@@ -86,6 +86,7 @@ enum audit_type {
+ #define OP_SHUTDOWN "socket_shutdown"
+ #define OP_PTRACE "ptrace"
++#define OP_SIGNAL "signal"
+ #define OP_EXEC "exec"
+@@ -126,6 +127,7 @@ struct apparmor_audit_data {
+                       long pos;
+                       const char *ns;
+               } iface;
++              int signal;
+               struct {
+                       int rlim;
+                       unsigned long max;
+diff --git a/security/apparmor/include/ipc.h b/security/apparmor/include/ipc.h
+index 656fdb81c8a0..5ffc218d1e74 100644
+--- a/security/apparmor/include/ipc.h
++++ b/security/apparmor/include/ipc.h
+@@ -27,8 +27,14 @@ struct aa_profile;
+ #define AA_PTRACE_PERM_MASK (AA_PTRACE_READ | AA_PTRACE_TRACE | \
+                            AA_MAY_BE_READ | AA_MAY_BE_TRACED)
++#define AA_SIGNAL_PERM_MASK (MAY_READ | MAY_WRITE)
++
++#define AA_SFS_SIG_MASK "hup int quit ill trap abrt bus fpe kill usr1 " \
++      "segv usr2 pipe alrm term stkflt chld cont stop stp ttin ttou urg " \
++      "xcpu xfsz vtalrm prof winch io pwr sys emt lost"
+ int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee,
+                 u32 request);
++int aa_may_signal(struct aa_label *sender, struct aa_label *target, int sig);
+ #endif /* __AA_IPC_H */
+diff --git a/security/apparmor/include/sig_names.h b/security/apparmor/include/sig_names.h
+new file mode 100644
+index 000000000000..0d4395f231ca
+--- /dev/null
++++ b/security/apparmor/include/sig_names.h
+@@ -0,0 +1,95 @@
++#include <linux/signal.h>
++
++#define SIGUNKNOWN 0
++#define MAXMAPPED_SIG 35
++/* provide a mapping of arch signal to internal signal # for mediation
++ * those that are always an alias SIGCLD for SIGCLHD and SIGPOLL for SIGIO
++ * map to the same entry those that may/or may not get a separate entry
++ */
++static const int sig_map[MAXMAPPED_SIG] = {
++      [0] = MAXMAPPED_SIG,    /* existence test */
++      [SIGHUP] = 1,
++      [SIGINT] = 2,
++      [SIGQUIT] = 3,
++      [SIGILL] = 4,
++      [SIGTRAP] = 5,          /* -, 5, - */
++      [SIGABRT] = 6,          /*  SIGIOT: -, 6, - */
++      [SIGBUS] = 7,           /* 10, 7, 10 */
++      [SIGFPE] = 8,
++      [SIGKILL] = 9,
++      [SIGUSR1] = 10,         /* 30, 10, 16 */
++      [SIGSEGV] = 11,
++      [SIGUSR2] = 12,         /* 31, 12, 17 */
++      [SIGPIPE] = 13,
++      [SIGALRM] = 14,
++      [SIGTERM] = 15,
++      [SIGSTKFLT] = 16,       /* -, 16, - */
++      [SIGCHLD] = 17,         /* 20, 17, 18.  SIGCHLD -, -, 18 */
++      [SIGCONT] = 18,         /* 19, 18, 25 */
++      [SIGSTOP] = 19,         /* 17, 19, 23 */
++      [SIGTSTP] = 20,         /* 18, 20, 24 */
++      [SIGTTIN] = 21,         /* 21, 21, 26 */
++      [SIGTTOU] = 22,         /* 22, 22, 27 */
++      [SIGURG] = 23,          /* 16, 23, 21 */
++      [SIGXCPU] = 24,         /* 24, 24, 30 */
++      [SIGXFSZ] = 25,         /* 25, 25, 31 */
++      [SIGVTALRM] = 26,       /* 26, 26, 28 */
++      [SIGPROF] = 27,         /* 27, 27, 29 */
++      [SIGWINCH] = 28,        /* 28, 28, 20 */
++      [SIGIO] = 29,           /* SIGPOLL: 23, 29, 22 */
++      [SIGPWR] = 30,          /* 29, 30, 19.  SIGINFO 29, -, - */
++#ifdef SIGSYS
++      [SIGSYS] = 31,          /* 12, 31, 12. often SIG LOST/UNUSED */
++#endif
++#ifdef SIGEMT
++      [SIGEMT] = 32,          /* 7, - , 7 */
++#endif
++#if defined(SIGLOST) && SIGPWR != SIGLOST             /* sparc */
++      [SIGLOST] = 33,         /* unused on Linux */
++#endif
++#if defined(SIGLOST) && defined(SIGSYS) && SIGLOST != SIGSYS
++      [SIGUNUSED] = 34,       /* -, 31, - */
++#endif
++};
++
++/* this table is ordered post sig_map[sig] mapping */
++static const char *const sig_names[MAXMAPPED_SIG + 1] = {
++      "unknown",
++      "hup",
++      "int",
++      "quit",
++      "ill",
++      "trap",
++      "abrt",
++      "bus",
++      "fpe",
++      "kill",
++      "usr1",
++      "segv",
++      "usr2",
++      "pipe",
++      "alrm",
++      "term",
++      "stkflt",
++      "chld",
++      "cont",
++      "stop",
++      "stp",
++      "ttin",
++      "ttou",
++      "urg",
++      "xcpu",
++      "xfsz",
++      "vtalrm",
++      "prof",
++      "winch",
++      "io",
++      "pwr",
++      "sys",
++      "emt",
++      "lost",
++      "unused",
++
++      "exists",       /* always last existence test mapped to MAXMAPPED_SIG */
++};
++
+diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c
+index 11e66b5bbc42..66fb9ede9447 100644
+--- a/security/apparmor/ipc.c
++++ b/security/apparmor/ipc.c
+@@ -20,6 +20,7 @@
+ #include "include/context.h"
+ #include "include/policy.h"
+ #include "include/ipc.h"
++#include "include/sig_names.h"
+ /**
+  * audit_ptrace_mask - convert mask to permission string
+@@ -121,3 +122,101 @@ int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee,
+ }
++static inline int map_signal_num(int sig)
++{
++      if (sig > SIGRTMAX)
++              return SIGUNKNOWN;
++      else if (sig >= SIGRTMIN)
++              return sig - SIGRTMIN + 128;    /* rt sigs mapped to 128 */
++      else if (sig <= MAXMAPPED_SIG)
++              return sig_map[sig];
++      return SIGUNKNOWN;
++}
++
++/**
++ * audit_file_mask - convert mask to permission string
++ * @buffer: buffer to write string to (NOT NULL)
++ * @mask: permission mask to convert
++ */
++static void audit_signal_mask(struct audit_buffer *ab, u32 mask)
++{
++      if (mask & MAY_READ)
++              audit_log_string(ab, "receive");
++      if (mask & MAY_WRITE)
++              audit_log_string(ab, "send");
++}
++
++/**
++ * audit_cb - call back for signal specific audit fields
++ * @ab: audit_buffer  (NOT NULL)
++ * @va: audit struct to audit values of  (NOT NULL)
++ */
++static void audit_signal_cb(struct audit_buffer *ab, void *va)
++{
++      struct common_audit_data *sa = va;
++
++      if (aad(sa)->request & AA_SIGNAL_PERM_MASK) {
++              audit_log_format(ab, " requested_mask=");
++              audit_signal_mask(ab, aad(sa)->request);
++              if (aad(sa)->denied & AA_SIGNAL_PERM_MASK) {
++                      audit_log_format(ab, " denied_mask=");
++                      audit_signal_mask(ab, aad(sa)->denied);
++              }
++      }
++      if (aad(sa)->signal <= MAXMAPPED_SIG)
++              audit_log_format(ab, " signal=%s", sig_names[aad(sa)->signal]);
++      else
++              audit_log_format(ab, " signal=rtmin+%d",
++                               aad(sa)->signal - 128);
++      audit_log_format(ab, " peer=");
++      aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
++                      FLAGS_NONE, GFP_ATOMIC);
++}
++
++/* TODO: update to handle compound name&name2, conditionals */
++static void profile_match_signal(struct aa_profile *profile, const char *label,
++                               int signal, struct aa_perms *perms)
++{
++      unsigned int state;
++
++      /* TODO: secondary cache check <profile, profile, perm> */
++      state = aa_dfa_next(profile->policy.dfa,
++                          profile->policy.start[AA_CLASS_SIGNAL],
++                          signal);
++      state = aa_dfa_match(profile->policy.dfa, state, label);
++      aa_compute_perms(profile->policy.dfa, state, perms);
++}
++
++static int profile_signal_perm(struct aa_profile *profile,
++                             struct aa_profile *peer, u32 request,
++                             struct common_audit_data *sa)
++{
++      struct aa_perms perms;
++
++      if (profile_unconfined(profile) ||
++          !PROFILE_MEDIATES(profile, AA_CLASS_SIGNAL))
++              return 0;
++
++      aad(sa)->peer = &peer->label;
++      profile_match_signal(profile, peer->base.hname, aad(sa)->signal,
++                           &perms);
++      aa_apply_modes_to_perms(profile, &perms);
++      return aa_check_perms(profile, &perms, request, sa, audit_signal_cb);
++}
++
++static int aa_signal_cross_perm(struct aa_profile *sender,
++                              struct aa_profile *target,
++                              struct common_audit_data *sa)
++{
++      return xcheck(profile_signal_perm(sender, target, MAY_WRITE, sa),
++                    profile_signal_perm(target, sender, MAY_READ, sa));
++}
++
++int aa_may_signal(struct aa_label *sender, struct aa_label *target, int sig)
++{
++      DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_SIGNAL);
++
++      aad(&sa)->signal = map_signal_num(sig);
++      return xcheck_labels_profiles(sender, target, aa_signal_cross_perm,
++                                    &sa);
++}
+diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
+index 867bcd154c7e..af22f3dfbcce 100644
+--- a/security/apparmor/lsm.c
++++ b/security/apparmor/lsm.c
+@@ -656,6 +656,26 @@ static int apparmor_task_setrlimit(struct task_struct *task,
+       return error;
+ }
++static int apparmor_task_kill(struct task_struct *target, struct siginfo *info,
++                            int sig, u32 secid)
++{
++      struct aa_label *cl, *tl;
++      int error;
++
++      if (secid)
++              /* TODO: after secid to label mapping is done.
++               *  Dealing with USB IO specific behavior
++               */
++              return 0;
++      cl = __begin_current_label_crit_section();
++      tl = aa_get_task_label(target);
++      error = aa_may_signal(cl, tl, sig);
++      aa_put_label(tl);
++      __end_current_label_crit_section(cl);
++
++      return error;
++}
++
+ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
+       LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
+       LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
+@@ -697,6 +717,7 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
+       LSM_HOOK_INIT(bprm_secureexec, apparmor_bprm_secureexec),
+       LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit),
++      LSM_HOOK_INIT(task_kill, apparmor_task_kill),
+ };
+ /*
+-- 
+2.11.0
+
similarity index 50%
rename from kernel-apparmor-mount.patch
rename to 0007-apparmor-add-mount-mediation.patch
index 3c9a09780b5a09c991448082dedec080f83dd7b9..99dac5c1790898c3da3691b5c70fd630d865b984 100644 (file)
-commit 4429c3f9522b608300cfe1ae148dc6cdadf3d76c
-Author: John Johansen <john.johansen@canonical.com>
-Date:   Wed May 16 10:58:05 2012 -0700
+From f37356d0a41499f9222f9f2b9c0147b500ae4285 Mon Sep 17 00:00:00 2001
+From: John Johansen <john.johansen@canonical.com>
+Date: Tue, 18 Jul 2017 23:04:47 -0700
+Subject: [PATCH 07/17] apparmor: add mount mediation
 
-    UBUNTU: SAUCE: apparmor: Add the ability to mediate mount
-    
-    Add the ability for apparmor to do mediation of mount operations. Mount
-    rules require an updated apparmor_parser (2.8 series) for policy compilation.
-    
-    The basic form of the rules are.
-    
-      [audit] [deny] mount [conds]* [device] [ -> [conds] path],
-      [audit] [deny] remount [conds]* [path],
-      [audit] [deny] umount [conds]* [path],
-      [audit] [deny] pivotroot [oldroot=<value>] <path>
-    
-      remount is just a short cut for mount options=remount
-    
-      where [conds] can be
-        fstype=<expr>
-        options=<expr>
-    
-    Example mount commands
-      mount,                # allow all mounts, but not umount or pivotroot
-    
-      mount fstype=procfs,  # allow mounting procfs anywhere
-    
-      mount options=(bind, ro) /foo -> /bar,  # readonly bind mount
-    
-      mount /dev/sda -> /mnt,
-    
-      mount /dev/sd** -> /mnt/**,
-    
-      mount fstype=overlayfs options=(rw,upperdir=/tmp/upper/,lowerdir=/) -> /mnt/
-    
-      umount,
-    
-      umount /m*,
-    
-    See the apparmor userspace for full documentation
-    
-    Signed-off-by: John Johansen <john.johansen@canonical.com>
-    Acked-by: Kees Cook <kees@ubuntu.com>
+Add basic mount mediation. That allows controlling based on basic
+mount parameters. It does not include special mount parameters for
+apparmor, super block labeling, or any triggers for apparmor namespace
+parameter modifications on pivot root.
+
+default userspace policy rules have the form of
+  MOUNT RULE = ( MOUNT | REMOUNT | UMOUNT )
+
+  MOUNT = [ QUALIFIERS ] 'mount' [ MOUNT CONDITIONS ] [ SOURCE FILEGLOB ]
+          [ '->' MOUNTPOINT FILEGLOB ]
+
+  REMOUNT = [ QUALIFIERS ] 'remount' [ MOUNT CONDITIONS ]
+            MOUNTPOINT FILEGLOB
+
+  UMOUNT = [ QUALIFIERS ] 'umount' [ MOUNT CONDITIONS ] MOUNTPOINT FILEGLOB
+
+  MOUNT CONDITIONS = [ ( 'fstype' | 'vfstype' ) ( '=' | 'in' )
+                       MOUNT FSTYPE EXPRESSION ]
+                      [ 'options' ( '=' | 'in' ) MOUNT FLAGS EXPRESSION ]
+
+  MOUNT FSTYPE EXPRESSION = ( MOUNT FSTYPE LIST | MOUNT EXPRESSION )
+
+  MOUNT FSTYPE LIST = Comma separated list of valid filesystem and
+                      virtual filesystem types (eg ext4, debugfs, etc)
+
+  MOUNT FLAGS EXPRESSION = ( MOUNT FLAGS LIST | MOUNT EXPRESSION )
+
+  MOUNT FLAGS LIST = Comma separated list of MOUNT FLAGS.
+
+  MOUNT FLAGS = ( 'ro' | 'rw' | 'nosuid' | 'suid' | 'nodev' | 'dev' |
+                  'noexec' | 'exec' | 'sync' | 'async' | 'remount' |
+                 'mand' | 'nomand' | 'dirsync' | 'noatime' | 'atime' |
+                 'nodiratime' | 'diratime' | 'bind' | 'rbind' | 'move' |
+                 'verbose' | 'silent' | 'loud' | 'acl' | 'noacl' |
+                 'unbindable' | 'runbindable' | 'private' | 'rprivate' |
+                 'slave' | 'rslave' | 'shared' | 'rshared' |
+                 'relatime' | 'norelatime' | 'iversion' | 'noiversion' |
+                 'strictatime' | 'nouser' | 'user' )
+
+  MOUNT EXPRESSION = ( ALPHANUMERIC | AARE ) ...
+
+  PIVOT ROOT RULE = [ QUALIFIERS ] pivot_root [ oldroot=OLD PUT FILEGLOB ]
+                    [ NEW ROOT FILEGLOB ]
+
+  SOURCE FILEGLOB = FILEGLOB
+
+  MOUNTPOINT FILEGLOB = FILEGLOB
+
+eg.
+  mount,
+  mount /dev/foo,
+  mount options=ro /dev/foo -> /mnt/,
+  mount options in (ro,atime) /dev/foo -> /mnt/,
+  mount options=ro options=atime,
+
+Signed-off-by: John Johansen <john.johansen@canonical.com>
+Acked-by: Seth Arnold <seth.arnold@canonical.com>
+(cherry picked from commit fa488437d0f95b2e5db1e624341fe0d5a233f729)
+---
+ security/apparmor/Makefile           |   2 +-
+ security/apparmor/apparmorfs.c       |   8 +-
+ security/apparmor/domain.c           |   4 +-
+ security/apparmor/include/apparmor.h |   1 +
+ security/apparmor/include/audit.h    |  11 +
+ security/apparmor/include/domain.h   |   5 +
+ security/apparmor/include/mount.h    |  54 +++
+ security/apparmor/lsm.c              |  64 ++++
+ security/apparmor/mount.c            | 696 +++++++++++++++++++++++++++++++++++
+ 9 files changed, 841 insertions(+), 4 deletions(-)
+ create mode 100644 security/apparmor/include/mount.h
+ create mode 100644 security/apparmor/mount.c
 
 diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
-index a7dc10be232d..01368441f230 100644
+index a16b195274de..81a34426d024 100644
 --- a/security/apparmor/Makefile
 +++ b/security/apparmor/Makefile
 @@ -4,7 +4,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
  
  apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
                path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
--              resource.o secid.o file.o policy_ns.o net.o
-+              resource.o secid.o file.o policy_ns.o net.o mount.o
+-              resource.o secid.o file.o policy_ns.o label.o
++              resource.o secid.o file.o policy_ns.o label.o mount.o
  apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
  
- clean-files := capability_names.h rlim_names.h net_names.h
+ clean-files := capability_names.h rlim_names.h
 diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
-index 4d236736cfb8..2e8d09e2368b 100644
+index a5f9e1aa51f7..8fa6c898c44b 100644
 --- a/security/apparmor/apparmorfs.c
 +++ b/security/apparmor/apparmorfs.c
-@@ -1205,11 +1205,24 @@ static struct aa_fs_entry aa_fs_entry_policy[] = {
+@@ -2159,9 +2159,14 @@ static struct aa_sfs_entry aa_sfs_entry_policy[] = {
        { }
  };
  
-+static struct aa_fs_entry aa_fs_entry_mount[] = {
-+      AA_FS_FILE_STRING("mask", "mount umount"),
++static struct aa_sfs_entry aa_sfs_entry_mount[] = {
++      AA_SFS_FILE_STRING("mask", "mount umount pivot_root"),
 +      { }
 +};
 +
-+static struct aa_fs_entry aa_fs_entry_namespaces[] = {
-+      AA_FS_FILE_BOOLEAN("profile",           1),
-+      AA_FS_FILE_BOOLEAN("pivot_root",        1),
-+      { }
-+};
-+
- static struct aa_fs_entry aa_fs_entry_features[] = {
-       AA_FS_DIR("policy",                     aa_fs_entry_policy),
-       AA_FS_DIR("domain",                     aa_fs_entry_domain),
-       AA_FS_DIR("file",                       aa_fs_entry_file),
-       AA_FS_DIR("network",                    aa_fs_entry_network),
-+      AA_FS_DIR("mount",                      aa_fs_entry_mount),
-+      AA_FS_DIR("namespaces",                 aa_fs_entry_namespaces),
-       AA_FS_FILE_U64("capability",            VFS_CAP_FLAGS_MASK),
-       AA_FS_DIR("rlimit",                     aa_fs_entry_rlimit),
-       AA_FS_DIR("caps",                       aa_fs_entry_caps),
+ static struct aa_sfs_entry aa_sfs_entry_ns[] = {
+       AA_SFS_FILE_BOOLEAN("profile",          1),
+-      AA_SFS_FILE_BOOLEAN("pivot_root",       1),
++      AA_SFS_FILE_BOOLEAN("pivot_root",       0),
+       { }
+ };
+@@ -2180,6 +2185,7 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = {
+       AA_SFS_DIR("policy",                    aa_sfs_entry_policy),
+       AA_SFS_DIR("domain",                    aa_sfs_entry_domain),
+       AA_SFS_DIR("file",                      aa_sfs_entry_file),
++      AA_SFS_DIR("mount",                     aa_sfs_entry_mount),
+       AA_SFS_DIR("namespaces",                aa_sfs_entry_ns),
+       AA_SFS_FILE_U64("capability",           VFS_CAP_FLAGS_MASK),
+       AA_SFS_DIR("rlimit",                    aa_sfs_entry_rlimit),
 diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
-index 001e133a3c8c..708b7e22b9b5 100644
+index d0594446ae3f..ffc8c75a6785 100644
 --- a/security/apparmor/domain.c
 +++ b/security/apparmor/domain.c
-@@ -237,7 +237,7 @@ static const char *next_name(int xtype, const char *name)
+@@ -374,8 +374,8 @@ static const char *next_name(int xtype, const char *name)
   *
-  * Returns: refcounted profile, or NULL on failure (MAYBE NULL)
+  * Returns: refcounted label, or NULL on failure (MAYBE NULL)
   */
--static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
-+struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
+-static struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex,
+-                                     const char **name)
++struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex,
++                              const char **name)
  {
-       struct aa_profile *new_profile = NULL;
-       struct aa_ns *ns = profile->ns;
+       struct aa_label *label = NULL;
+       u32 xtype = xindex & AA_X_TYPE_MASK;
 diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
-index 1750cc0721c1..3383dc66f30f 100644
+index 962a20a75e01..829082c35faa 100644
 --- a/security/apparmor/include/apparmor.h
 +++ b/security/apparmor/include/apparmor.h
-@@ -27,8 +27,9 @@
+@@ -27,6 +27,7 @@
  #define AA_CLASS_NET          4
  #define AA_CLASS_RLIMITS      5
  #define AA_CLASS_DOMAIN               6
 +#define AA_CLASS_MOUNT                7
--#define AA_CLASS_LAST         AA_CLASS_DOMAIN
-+#define AA_CLASS_LAST         AA_CLASS_MOUNT
- /* Control parameters settable through module/boot flags */
- extern enum audit_mode aa_g_audit;
+ #define AA_CLASS_PTRACE               9
+ #define AA_CLASS_SIGNAL               10
+ #define AA_CLASS_LABEL                16
 diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
-index 0df708e8748b..41374ad89547 100644
+index d9a156ae11b9..c3fe1c5ef3bc 100644
 --- a/security/apparmor/include/audit.h
 +++ b/security/apparmor/include/audit.h
-@@ -70,6 +70,10 @@ enum audit_type {
- #define OP_FMMAP "file_mmap"
+@@ -71,6 +71,10 @@ enum audit_type {
  #define OP_FMPROT "file_mprotect"
+ #define OP_INHERIT "file_inherit"
  
 +#define OP_PIVOTROOT "pivotroot"
 +#define OP_MOUNT "mount"
@@ -127,36 +158,46 @@ index 0df708e8748b..41374ad89547 100644
  #define OP_CREATE "create"
  #define OP_POST_CREATE "post_create"
  #define OP_BIND "bind"
-@@ -127,6 +131,13 @@ struct apparmor_audit_data {
+@@ -132,6 +136,13 @@ struct apparmor_audit_data {
                        int rlim;
                        unsigned long max;
                } rlim;
-+              struct {
++              struct {
 +                      const char *src_name;
 +                      const char *type;
 +                      const char *trans;
 +                      const char *data;
 +                      unsigned long flags;
 +              } mnt;
-               struct {
                      int type, protocol;
-                       struct sock *sk;
+       };
};
 diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h
-index 30544729878a..7bd21d20a2bd 100644
+index bab5810b6e9a..db27403346c5 100644
 --- a/security/apparmor/include/domain.h
 +++ b/security/apparmor/include/domain.h
-@@ -23,6 +23,8 @@ struct aa_domain {
-       char **table;
- };
+@@ -15,6 +15,8 @@
+ #include <linux/binfmts.h>
+ #include <linux/types.h>
++#include "label.h"
++
+ #ifndef __AA_DOMAIN_H
+ #define __AA_DOMAIN_H
+@@ -29,6 +31,9 @@ struct aa_domain {
+ #define AA_CHANGE_ONEXEC  4
+ #define AA_CHANGE_STACK 8
  
-+struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex);
++struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex,
++                              const char **name);
 +
  int apparmor_bprm_set_creds(struct linux_binprm *bprm);
  int apparmor_bprm_secureexec(struct linux_binprm *bprm);
- void apparmor_bprm_committing_creds(struct linux_binprm *bprm);
 diff --git a/security/apparmor/include/mount.h b/security/apparmor/include/mount.h
 new file mode 100644
-index 000000000000..a43b1d62e428
+index 000000000000..25d6067fa6ef
 --- /dev/null
 +++ b/security/apparmor/include/mount.h
 @@ -0,0 +1,54 @@
@@ -165,7 +206,7 @@ index 000000000000..a43b1d62e428
 + *
 + * This file contains AppArmor file mediation function definitions.
 + *
-+ * Copyright 2012 Canonical Ltd.
++ * Copyright 2017 Canonical Ltd.
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License as
@@ -187,35 +228,35 @@ index 000000000000..a43b1d62e428
 +#define AA_MAY_MOUNT          0x02
 +#define AA_MAY_UMOUNT         0x04
 +#define AA_AUDIT_DATA         0x40
-+#define AA_CONT_MATCH         0x40
++#define AA_MNT_CONT_MATCH     0x40
 +
 +#define AA_MS_IGNORE_MASK (MS_KERNMOUNT | MS_NOSEC | MS_ACTIVE | MS_BORN)
 +
-+int aa_remount(struct aa_profile *profile, const struct path *path,
++int aa_remount(struct aa_label *label, const struct path *path,
 +             unsigned long flags, void *data);
 +
-+int aa_bind_mount(struct aa_profile *profile, const struct path *path,
++int aa_bind_mount(struct aa_label *label, const struct path *path,
 +                const char *old_name, unsigned long flags);
 +
 +
-+int aa_mount_change_type(struct aa_profile *profile, const struct path *path,
++int aa_mount_change_type(struct aa_label *label, const struct path *path,
 +                       unsigned long flags);
 +
-+int aa_move_mount(struct aa_profile *profile, const struct path *path,
++int aa_move_mount(struct aa_label *label, const struct path *path,
 +                const char *old_name);
 +
-+int aa_new_mount(struct aa_profile *profile, const char *dev_name,
++int aa_new_mount(struct aa_label *label, const char *dev_name,
 +               const struct path *path, const char *type, unsigned long flags,
 +               void *data);
 +
-+int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags);
++int aa_umount(struct aa_label *label, struct vfsmount *mnt, int flags);
 +
-+int aa_pivotroot(struct aa_profile *profile, const struct path *old_path,
++int aa_pivotroot(struct aa_label *label, const struct path *old_path,
 +               const struct path *new_path);
 +
 +#endif /* __AA_MOUNT_H */
 diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
-index e3017129a404..ee58a2cca74f 100644
+index af22f3dfbcce..4ad0b3a45142 100644
 --- a/security/apparmor/lsm.c
 +++ b/security/apparmor/lsm.c
 @@ -38,6 +38,7 @@
@@ -225,15 +266,15 @@ index e3017129a404..ee58a2cca74f 100644
 +#include "include/mount.h"
  
  /* Flag indicating whether initialization completed */
- int apparmor_initialized __initdata;
-@@ -479,6 +480,61 @@ static int apparmor_file_mprotect(struct vm_area_struct *vma,
+ int apparmor_initialized;
+@@ -511,6 +512,65 @@ static int apparmor_file_mprotect(struct vm_area_struct *vma,
                           !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
  }
  
 +static int apparmor_sb_mount(const char *dev_name, const struct path *path,
 +                           const char *type, unsigned long flags, void *data)
 +{
-+      struct aa_profile *profile;
++      struct aa_label *label;
 +      int error = 0;
 +
 +      /* Discard magic */
@@ -242,32 +283,35 @@ index e3017129a404..ee58a2cca74f 100644
 +
 +      flags &= ~AA_MS_IGNORE_MASK;
 +
-+      profile = __aa_current_profile();
-+      if (!unconfined(profile)) {
++      label = __begin_current_label_crit_section();
++      if (!unconfined(label)) {
 +              if (flags & MS_REMOUNT)
-+                      error = aa_remount(profile, path, flags, data);
++                      error = aa_remount(label, path, flags, data);
 +              else if (flags & MS_BIND)
-+                      error = aa_bind_mount(profile, path, dev_name, flags);
++                      error = aa_bind_mount(label, path, dev_name, flags);
 +              else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE |
 +                                MS_UNBINDABLE))
-+                      error = aa_mount_change_type(profile, path, flags);
++                      error = aa_mount_change_type(label, path, flags);
 +              else if (flags & MS_MOVE)
-+                      error = aa_move_mount(profile, path, dev_name);
++                      error = aa_move_mount(label, path, dev_name);
 +              else
-+                      error = aa_new_mount(profile, dev_name, path, type,
++                      error = aa_new_mount(label, dev_name, path, type,
 +                                           flags, data);
 +      }
++      __end_current_label_crit_section(label);
++
 +      return error;
 +}
 +
 +static int apparmor_sb_umount(struct vfsmount *mnt, int flags)
 +{
-+      struct aa_profile *profile;
++      struct aa_label *label;
 +      int error = 0;
 +
-+      profile = __aa_current_profile();
-+      if (!unconfined(profile))
-+              error = aa_umount(profile, mnt, flags);
++      label = __begin_current_label_crit_section();
++      if (!unconfined(label))
++              error = aa_umount(label, mnt, flags);
++      __end_current_label_crit_section(label);
 +
 +      return error;
 +}
@@ -275,12 +319,13 @@ index e3017129a404..ee58a2cca74f 100644
 +static int apparmor_sb_pivotroot(const struct path *old_path,
 +                               const struct path *new_path)
 +{
-+      struct aa_profile *profile;
++      struct aa_label *label;
 +      int error = 0;
 +
-+      profile = __aa_current_profile();
-+      if (!unconfined(profile))
-+              error = aa_pivotroot(profile, old_path, new_path);
++      label = aa_get_current_label();
++      if (!unconfined(label))
++              error = aa_pivotroot(label, old_path, new_path);
++      aa_put_label(label);
 +
 +      return error;
 +}
@@ -288,7 +333,7 @@ index e3017129a404..ee58a2cca74f 100644
  static int apparmor_getprocattr(struct task_struct *task, char *name,
                                char **value)
  {
-@@ -692,6 +748,10 @@ static struct security_hook_list apparmor_hooks[] = {
+@@ -682,6 +742,10 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(capget, apparmor_capget),
        LSM_HOOK_INIT(capable, apparmor_capable),
  
@@ -301,17 +346,17 @@ index e3017129a404..ee58a2cca74f 100644
        LSM_HOOK_INIT(path_symlink, apparmor_path_symlink),
 diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c
 new file mode 100644
-index 000000000000..9e95a41c015c
+index 000000000000..82a64b58041d
 --- /dev/null
 +++ b/security/apparmor/mount.c
-@@ -0,0 +1,616 @@
+@@ -0,0 +1,696 @@
 +/*
 + * AppArmor security module
 + *
 + * This file contains AppArmor mediation of files
 + *
 + * Copyright (C) 1998-2008 Novell/SUSE
-+ * Copyright 2009-2012 Canonical Ltd.
++ * Copyright 2009-2017 Canonical Ltd.
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License as
@@ -423,7 +468,6 @@ index 000000000000..9e95a41c015c
 +/**
 + * audit_mount - handle the auditing of mount operations
 + * @profile: the profile being enforced  (NOT NULL)
-+ * @gfp: allocation flags
 + * @op: operation being mediated (NOT NULL)
 + * @name: name of object being mediated (MAYBE NULL)
 + * @src_name: src_name of object being mediated (MAYBE_NULL)
@@ -438,11 +482,11 @@ index 000000000000..9e95a41c015c
 + *
 + * Returns: %0 or error on failure
 + */
-+static int audit_mount(struct aa_profile *profile, gfp_t gfp, const char *op,
++static int audit_mount(struct aa_profile *profile, const char *op,
 +                     const char *name, const char *src_name,
 +                     const char *type, const char *trans,
 +                     unsigned long flags, const void *data, u32 request,
-+                     struct file_perms *perms, const char *info, int error)
++                     struct aa_perms *perms, const char *info, int error)
 +{
 +      int audit_type = AUDIT_APPARMOR_AUTO;
 +      DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, op);
@@ -473,8 +517,7 @@ index 000000000000..9e95a41c015c
 +                      request &= ~perms->quiet;
 +
 +              if (!request)
-+                      return COMPLAIN_MODE(profile) ?
-+                              complain_error(error) : error;
++                      return error;
 +      }
 +
 +      aad(&sa)->name = name;
@@ -522,10 +565,10 @@ index 000000000000..9e95a41c015c
 + *
 + * Returns: mount permissions
 + */
-+static struct file_perms compute_mnt_perms(struct aa_dfa *dfa,
++static struct aa_perms compute_mnt_perms(struct aa_dfa *dfa,
 +                                         unsigned int state)
 +{
-+      struct file_perms perms;
++      struct aa_perms perms;
 +
 +      perms.kill = 0;
 +      perms.allow = dfa_user_allow(dfa, state);
@@ -536,7 +579,7 @@ index 000000000000..9e95a41c015c
 +      return perms;
 +}
 +
-+static const char *mnt_info_table[] = {
++static const char * const mnt_info_table[] = {
 +      "match succeeded",
 +      "failed mntpnt match",
 +      "failed srcname match",
@@ -552,10 +595,13 @@ index 000000000000..9e95a41c015c
 +static int do_match_mnt(struct aa_dfa *dfa, unsigned int start,
 +                      const char *mntpnt, const char *devname,
 +                      const char *type, unsigned long flags,
-+                      void *data, bool binary, struct file_perms *perms)
++                      void *data, bool binary, struct aa_perms *perms)
 +{
 +      unsigned int state;
 +
++      AA_BUG(!dfa);
++      AA_BUG(!perms);
++
 +      state = aa_dfa_match(dfa, start, mntpnt);
 +      state = aa_dfa_null_transition(dfa, state);
 +      if (!state)
@@ -581,7 +627,7 @@ index 000000000000..9e95a41c015c
 +              return 0;
 +
 +      /* only match data if not binary and the DFA flags data is expected */
-+      if (data && !binary && (perms->allow & AA_CONT_MATCH)) {
++      if (data && !binary && (perms->allow & AA_MNT_CONT_MATCH)) {
 +              state = aa_dfa_null_transition(dfa, state);
 +              if (!state)
 +                      return 4;
@@ -598,326 +644,408 @@ index 000000000000..9e95a41c015c
 +      return 4;
 +}
 +
++
++static int path_flags(struct aa_profile *profile, const struct path *path)
++{
++      AA_BUG(!profile);
++      AA_BUG(!path);
++
++      return profile->path_flags |
++              (S_ISDIR(path->dentry->d_inode->i_mode) ? PATH_IS_DIR : 0);
++}
++
 +/**
-+ * match_mnt - handle path matching for mount
++ * match_mnt_path_str - handle path matching for mount
 + * @profile: the confining profile
-+ * @mntpnt: string for the mntpnt (NOT NULL)
-+ * @devname: string for the devname/src_name (MAYBE NULL)
++ * @mntpath: for the mntpnt (NOT NULL)
++ * @buffer: buffer to be used to lookup mntpath
++ * @devnme: string for the devname/src_name (MAY BE NULL OR ERRPTR)
 + * @type: string for the dev type (MAYBE NULL)
 + * @flags: mount flags to match
 + * @data: fs mount data (MAYBE NULL)
 + * @binary: whether @data is binary
-+ * @perms: Returns: permission found by the match
-+ * @info: Returns: infomation string about the match for logging
++ * @devinfo: error str if (IS_ERR(@devname))
 + *
 + * Returns: 0 on success else error
 + */
-+static int match_mnt(struct aa_profile *profile, const char *mntpnt,
-+                   const char *devname, const char *type,
-+                   unsigned long flags, void *data, bool binary,
-+                   struct file_perms *perms, const char **info)
++static int match_mnt_path_str(struct aa_profile *profile,
++                            const struct path *mntpath, char *buffer,
++                            const char *devname, const char *type,
++                            unsigned long flags, void *data, bool binary,
++                            const char *devinfo)
 +{
-+      int pos;
++      struct aa_perms perms = { };
++      const char *mntpnt = NULL, *info = NULL;
++      int pos, error;
 +
-+      if (!profile->policy.dfa)
-+              return -EACCES;
++      AA_BUG(!profile);
++      AA_BUG(!mntpath);
++      AA_BUG(!buffer);
++
++      error = aa_path_name(mntpath, path_flags(profile, mntpath), buffer,
++                           &mntpnt, &info, profile->disconnected);
++      if (error)
++              goto audit;
++      if (IS_ERR(devname)) {
++              error = PTR_ERR(devname);
++              devname = NULL;
++              info = devinfo;
++              goto audit;
++      }
 +
++      error = -EACCES;
 +      pos = do_match_mnt(profile->policy.dfa,
 +                         profile->policy.start[AA_CLASS_MOUNT],
-+                         mntpnt, devname, type, flags, data, binary, perms);
++                         mntpnt, devname, type, flags, data, binary, &perms);
 +      if (pos) {
-+              *info = mnt_info_table[pos];
-+              return -EACCES;
++              info = mnt_info_table[pos];
++              goto audit;
 +      }
++      error = 0;
 +
-+      return 0;
++audit:
++      return audit_mount(profile, OP_MOUNT, mntpnt, devname, type, NULL,
++                         flags, data, AA_MAY_MOUNT, &perms, info, error);
 +}
 +
-+static int path_flags(struct aa_profile *profile, const struct path *path)
++/**
++ * match_mnt - handle path matching for mount
++ * @profile: the confining profile
++ * @mntpath: for the mntpnt (NOT NULL)
++ * @buffer: buffer to be used to lookup mntpath
++ * @devpath: path devname/src_name (MAYBE NULL)
++ * @devbuffer: buffer to be used to lookup devname/src_name
++ * @type: string for the dev type (MAYBE NULL)
++ * @flags: mount flags to match
++ * @data: fs mount data (MAYBE NULL)
++ * @binary: whether @data is binary
++ *
++ * Returns: 0 on success else error
++ */
++static int match_mnt(struct aa_profile *profile, const struct path *path,
++                   char *buffer, struct path *devpath, char *devbuffer,
++                   const char *type, unsigned long flags, void *data,
++                   bool binary)
 +{
-+      return profile->path_flags |
-+              S_ISDIR(path->dentry->d_inode->i_mode) ? PATH_IS_DIR : 0;
++      const char *devname = NULL, *info = NULL;
++      int error = -EACCES;
++
++      AA_BUG(!profile);
++      AA_BUG(devpath && !devbuffer);
++
++      if (devpath) {
++              error = aa_path_name(devpath, path_flags(profile, devpath),
++                                   devbuffer, &devname, &info,
++                                   profile->disconnected);
++              if (error)
++                      devname = ERR_PTR(error);
++      }
++
++      return match_mnt_path_str(profile, path, buffer, devname, type, flags,
++                                data, binary, info);
 +}
 +
-+int aa_remount(struct aa_profile *profile, const struct path *path,
++int aa_remount(struct aa_label *label, const struct path *path,
 +             unsigned long flags, void *data)
 +{
-+      struct file_perms perms = { };
-+      const char *name, *info = NULL;
++      struct aa_profile *profile;
 +      char *buffer = NULL;
-+      int binary, error;
++      bool binary;
++      int error;
 +
-+      binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA;
++      AA_BUG(!label);
++      AA_BUG(!path);
 +
-+      error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
-+                           &info);
-+      if (error)
-+              goto audit;
++      binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA;
 +
-+      error = match_mnt(profile, name, NULL, NULL, flags, data, binary,
-+                        &perms, &info);
-+
-+audit:
-+      error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
-+                          NULL, flags, data, AA_MAY_MOUNT, &perms, info,
-+                          error);
-+      kfree(buffer);
++      get_buffers(buffer);
++      error = fn_for_each_confined(label, profile,
++                      match_mnt(profile, path, buffer, NULL, NULL, NULL,
++                                flags, data, binary));
++      put_buffers(buffer);
 +
 +      return error;
 +}
 +
-+int aa_bind_mount(struct aa_profile *profile, const struct path *path,
++int aa_bind_mount(struct aa_label *label, const struct path *path,
 +                const char *dev_name, unsigned long flags)
 +{
-+      struct file_perms perms = { };
++      struct aa_profile *profile;
 +      char *buffer = NULL, *old_buffer = NULL;
-+      const char *name, *old_name = NULL, *info = NULL;
 +      struct path old_path;
 +      int error;
 +
++      AA_BUG(!label);
++      AA_BUG(!path);
++
 +      if (!dev_name || !*dev_name)
 +              return -EINVAL;
 +
 +      flags &= MS_REC | MS_BIND;
 +
-+      error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
-+                           &info);
-+      if (error)
-+              goto audit;
-+
 +      error = kern_path(dev_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
 +      if (error)
-+              goto audit;
++              return error;
 +
-+      error = aa_path_name(&old_path, path_flags(profile, &old_path),
-+                           &old_buffer, &old_name, &info);
++      get_buffers(buffer, old_buffer);
++      error = fn_for_each_confined(label, profile,
++                      match_mnt(profile, path, buffer, &old_path, old_buffer,
++                                NULL, flags, NULL, false));
++      put_buffers(buffer, old_buffer);
 +      path_put(&old_path);
-+      if (error)
-+              goto audit;
-+
-+      error = match_mnt(profile, name, old_name, NULL, flags, NULL, 0,
-+                        &perms, &info);
-+
-+audit:
-+      error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
-+                          NULL, NULL, flags, NULL, AA_MAY_MOUNT, &perms,
-+                          info, error);
-+      kfree(buffer);
-+      kfree(old_buffer);
 +
 +      return error;
 +}
 +
-+int aa_mount_change_type(struct aa_profile *profile, const struct path *path,
++int aa_mount_change_type(struct aa_label *label, const struct path *path,
 +                       unsigned long flags)
 +{
-+      struct file_perms perms = { };
++      struct aa_profile *profile;
 +      char *buffer = NULL;
-+      const char *name, *info = NULL;
 +      int error;
 +
++      AA_BUG(!label);
++      AA_BUG(!path);
++
 +      /* These are the flags allowed by do_change_type() */
 +      flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE |
 +                MS_UNBINDABLE);
 +
-+      error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
-+                           &info);
-+      if (error)
-+              goto audit;
-+
-+      error = match_mnt(profile, name, NULL, NULL, flags, NULL, 0, &perms,
-+                        &info);
-+
-+audit:
-+      error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
-+                          NULL, flags, NULL, AA_MAY_MOUNT, &perms, info,
-+                          error);
-+      kfree(buffer);
++      get_buffers(buffer);
++      error = fn_for_each_confined(label, profile,
++                      match_mnt(profile, path, buffer, NULL, NULL, NULL,
++                                flags, NULL, false));
++      put_buffers(buffer);
 +
 +      return error;
 +}
 +
-+int aa_move_mount(struct aa_profile *profile, const struct path *path,
++int aa_move_mount(struct aa_label *label, const struct path *path,
 +                const char *orig_name)
 +{
-+      struct file_perms perms = { };
++      struct aa_profile *profile;
 +      char *buffer = NULL, *old_buffer = NULL;
-+      const char *name, *old_name = NULL, *info = NULL;
 +      struct path old_path;
 +      int error;
 +
++      AA_BUG(!label);
++      AA_BUG(!path);
++
 +      if (!orig_name || !*orig_name)
 +              return -EINVAL;
 +
-+      error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
-+                           &info);
-+      if (error)
-+              goto audit;
-+
 +      error = kern_path(orig_name, LOOKUP_FOLLOW, &old_path);
 +      if (error)
-+              goto audit;
++              return error;
 +
-+      error = aa_path_name(&old_path, path_flags(profile, &old_path),
-+                           &old_buffer, &old_name, &info);
++      get_buffers(buffer, old_buffer);
++      error = fn_for_each_confined(label, profile,
++                      match_mnt(profile, path, buffer, &old_path, old_buffer,
++                                NULL, MS_MOVE, NULL, false));
++      put_buffers(buffer, old_buffer);
 +      path_put(&old_path);
-+      if (error)
-+              goto audit;
-+
-+      error = match_mnt(profile, name, old_name, NULL, MS_MOVE, NULL, 0,
-+                        &perms, &info);
-+
-+audit:
-+      error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
-+                          NULL, NULL, MS_MOVE, NULL, AA_MAY_MOUNT, &perms,
-+                          info, error);
-+      kfree(buffer);
-+      kfree(old_buffer);
 +
 +      return error;
 +}
 +
-+int aa_new_mount(struct aa_profile *profile, const char *orig_dev_name,
++int aa_new_mount(struct aa_label *label, const char *dev_name,
 +               const struct path *path, const char *type, unsigned long flags,
 +               void *data)
 +{
-+      struct file_perms perms = { };
++      struct aa_profile *profile;
 +      char *buffer = NULL, *dev_buffer = NULL;
-+      const char *name = NULL, *dev_name = NULL, *info = NULL;
-+      int binary = 1;
++      bool binary = true;
 +      int error;
++      int requires_dev = 0;
++      struct path tmp_path, *dev_path = NULL;
++
++      AA_BUG(!label);
++      AA_BUG(!path);
 +
-+      dev_name = orig_dev_name;
 +      if (type) {
-+              int requires_dev;
-+              struct file_system_type *fstype = get_fs_type(type);
++              struct file_system_type *fstype;
++
++              fstype = get_fs_type(type);
 +              if (!fstype)
 +                      return -ENODEV;
-+
 +              binary = fstype->fs_flags & FS_BINARY_MOUNTDATA;
 +              requires_dev = fstype->fs_flags & FS_REQUIRES_DEV;
 +              put_filesystem(fstype);
 +
 +              if (requires_dev) {
-+                      struct path dev_path;
++                      if (!dev_name || !*dev_name)
++                              return -ENOENT;
 +
-+                      if (!dev_name || !*dev_name) {
-+                              error = -ENOENT;
-+                              goto out;
-+                      }
-+
-+                      error = kern_path(dev_name, LOOKUP_FOLLOW, &dev_path);
++                      error = kern_path(dev_name, LOOKUP_FOLLOW, &tmp_path);
 +                      if (error)
-+                              goto audit;
-+
-+                      error = aa_path_name(&dev_path,
-+                                           path_flags(profile, &dev_path),
-+                                           &dev_buffer, &dev_name, &info);
-+                      path_put(&dev_path);
-+                      if (error)
-+                              goto audit;
++                              return error;
++                      dev_path = &tmp_path;
 +              }
 +      }
 +
-+      error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
-+                           &info);
-+      if (error)
-+              goto audit;
-+
-+      error = match_mnt(profile, name, dev_name, type, flags, data, binary,
-+                        &perms, &info);
-+
-+audit:
-+      error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name,  dev_name,
-+                          type, NULL, flags, data, AA_MAY_MOUNT, &perms, info,
-+                          error);
-+      kfree(buffer);
-+      kfree(dev_buffer);
++      get_buffers(buffer, dev_buffer);
++      if (dev_path) {
++              error = fn_for_each_confined(label, profile,
++                      match_mnt(profile, path, buffer, dev_path, dev_buffer,
++                                type, flags, data, binary));
++      } else {
++              error = fn_for_each_confined(label, profile,
++                      match_mnt_path_str(profile, path, buffer, dev_name,
++                                         type, flags, data, binary, NULL));
++      }
++      put_buffers(buffer, dev_buffer);
++      if (dev_path)
++              path_put(dev_path);
 +
-+out:
 +      return error;
-+
 +}
 +
-+int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags)
++static int profile_umount(struct aa_profile *profile, struct path *path,
++                        char *buffer)
 +{
-+      struct file_perms perms = { };
-+      char *buffer = NULL;
-+      const char *name, *info = NULL;
++      struct aa_perms perms = { };
++      const char *name = NULL, *info = NULL;
++      unsigned int state;
 +      int error;
 +
-+      struct path path = { mnt, mnt->mnt_root };
-+      error = aa_path_name(&path, path_flags(profile, &path), &buffer, &name,
-+                           &info);
++      AA_BUG(!profile);
++      AA_BUG(!path);
++
++      error = aa_path_name(path, path_flags(profile, path), buffer, &name,
++                           &info, profile->disconnected);
 +      if (error)
 +              goto audit;
 +
-+      if (!error && profile->policy.dfa) {
-+              unsigned int state;
-+              state = aa_dfa_match(profile->policy.dfa,
-+                                   profile->policy.start[AA_CLASS_MOUNT],
-+                                   name);
-+              perms = compute_mnt_perms(profile->policy.dfa, state);
-+      }
-+
++      state = aa_dfa_match(profile->policy.dfa,
++                           profile->policy.start[AA_CLASS_MOUNT],
++                           name);
++      perms = compute_mnt_perms(profile->policy.dfa, state);
 +      if (AA_MAY_UMOUNT & ~perms.allow)
 +              error = -EACCES;
 +
 +audit:
-+      error = audit_mount(profile, GFP_KERNEL, OP_UMOUNT, name, NULL, NULL,
-+                          NULL, 0, NULL, AA_MAY_UMOUNT, &perms, info, error);
-+      kfree(buffer);
++      return audit_mount(profile, OP_UMOUNT, name, NULL, NULL, NULL, 0, NULL,
++                         AA_MAY_UMOUNT, &perms, info, error);
++}
++
++int aa_umount(struct aa_label *label, struct vfsmount *mnt, int flags)
++{
++      struct aa_profile *profile;
++      char *buffer = NULL;
++      int error;
++      struct path path = { .mnt = mnt, .dentry = mnt->mnt_root };
++
++      AA_BUG(!label);
++      AA_BUG(!mnt);
++
++      get_buffers(buffer);
++      error = fn_for_each_confined(label, profile,
++                      profile_umount(profile, &path, buffer));
++      put_buffers(buffer);
 +
 +      return error;
 +}
 +
-+int aa_pivotroot(struct aa_profile *profile, const struct path *old_path,
-+               const struct path *new_path)
++/* helper fn for transition on pivotroot
++ *
++ * Returns: label for transition or ERR_PTR. Does not return NULL
++ */
++static struct aa_label *build_pivotroot(struct aa_profile *profile,
++                                      const struct path *new_path,
++                                      char *new_buffer,
++                                      const struct path *old_path,
++                                      char *old_buffer)
 +{
-+      struct file_perms perms = { };
-+      struct aa_profile *target = NULL;
-+      char *old_buffer = NULL, *new_buffer = NULL;
 +      const char *old_name, *new_name = NULL, *info = NULL;
++      const char *trans_name = NULL;
++      struct aa_perms perms = { };
++      unsigned int state;
 +      int error;
 +
++      AA_BUG(!profile);
++      AA_BUG(!new_path);
++      AA_BUG(!old_path);
++
++      if (profile_unconfined(profile))
++              return aa_get_newest_label(&profile->label);
++
 +      error = aa_path_name(old_path, path_flags(profile, old_path),
-+                           &old_buffer, &old_name, &info);
++                           old_buffer, &old_name, &info,
++                           profile->disconnected);
 +      if (error)
 +              goto audit;
-+
 +      error = aa_path_name(new_path, path_flags(profile, new_path),
-+                           &new_buffer, &new_name, &info);
++                           new_buffer, &new_name, &info,
++                           profile->disconnected);
 +      if (error)
 +              goto audit;
 +
-+      if (profile->policy.dfa) {
-+              unsigned int state;
-+              state = aa_dfa_match(profile->policy.dfa,
-+                                   profile->policy.start[AA_CLASS_MOUNT],
-+                                   new_name);
-+              state = aa_dfa_null_transition(profile->policy.dfa, state);
-+              state = aa_dfa_match(profile->policy.dfa, state, old_name);
-+              perms = compute_mnt_perms(profile->policy.dfa, state);
-+      }
++      error = -EACCES;
++      state = aa_dfa_match(profile->policy.dfa,
++                           profile->policy.start[AA_CLASS_MOUNT],
++                           new_name);
++      state = aa_dfa_null_transition(profile->policy.dfa, state);
++      state = aa_dfa_match(profile->policy.dfa, state, old_name);
++      perms = compute_mnt_perms(profile->policy.dfa, state);
 +
-+      if (AA_MAY_PIVOTROOT & perms.allow) {
-+              if ((perms.xindex & AA_X_TYPE_MASK) == AA_X_TABLE) {
-+                      target = x_table_lookup(profile, perms.xindex);
-+                      if (!target)
-+                              error = -ENOENT;
-+                      else
-+                              error = aa_replace_current_profile(target);
-+              }
-+      } else
-+              error = -EACCES;
++      if (AA_MAY_PIVOTROOT & perms.allow)
++              error = 0;
 +
 +audit:
-+      error = audit_mount(profile, GFP_KERNEL, OP_PIVOTROOT, new_name,
-+                          old_name, NULL, target ? target->base.name : NULL,
-+                          0, NULL,  AA_MAY_PIVOTROOT, &perms, info, error);
-+      aa_put_profile(target);
-+      kfree(old_buffer);
-+      kfree(new_buffer);
++      error = audit_mount(profile, OP_PIVOTROOT, new_name, old_name,
++                          NULL, trans_name, 0, NULL, AA_MAY_PIVOTROOT,
++                          &perms, info, error);
++      if (error)
++              return ERR_PTR(error);
++
++      return aa_get_newest_label(&profile->label);
++}
++
++int aa_pivotroot(struct aa_label *label, const struct path *old_path,
++               const struct path *new_path)
++{
++      struct aa_profile *profile;
++      struct aa_label *target = NULL;
++      char *old_buffer = NULL, *new_buffer = NULL, *info = NULL;
++      int error;
++
++      AA_BUG(!label);
++      AA_BUG(!old_path);
++      AA_BUG(!new_path);
++
++      get_buffers(old_buffer, new_buffer);
++      target = fn_label_build(label, profile, GFP_ATOMIC,
++                      build_pivotroot(profile, new_path, new_buffer,
++                                      old_path, old_buffer));
++      if (!target) {
++              info = "label build failed";
++              error = -ENOMEM;
++              goto fail;
++      } else if (!IS_ERR(target)) {
++              error = aa_replace_current_label(target);
++              if (error) {
++                      /* TODO: audit target */
++                      aa_put_label(target);
++                      goto out;
++              }
++      } else
++              /* already audited error */
++              error = PTR_ERR(target);
++out:
++      put_buffers(old_buffer, new_buffer);
 +
 +      return error;
++
++fail:
++      /* TODO: add back in auditing of new_name and old_name */
++      error = fn_for_each(label, profile,
++                      audit_mount(profile, OP_PIVOTROOT, NULL /*new_name */,
++                                  NULL /* old_name */,
++                                  NULL, NULL,
++                                  0, NULL, AA_MAY_PIVOTROOT, &nullperms, info,
++                                  error));
++      goto out;
 +}
+-- 
+2.11.0
+
diff --git a/0008-apparmor-cleanup-conditional-check-for-label-in-labe.patch b/0008-apparmor-cleanup-conditional-check-for-label-in-labe.patch
new file mode 100644 (file)
index 0000000..20892df
--- /dev/null
@@ -0,0 +1,71 @@
+From 763d17c9a18b0df7dbec2740f10dc40d378e3cc1 Mon Sep 17 00:00:00 2001
+From: John Johansen <john.johansen@canonical.com>
+Date: Sun, 6 Aug 2017 05:36:40 -0700
+Subject: [PATCH 08/17] apparmor: cleanup conditional check for label in
+ label_print
+
+Signed-off-by: John Johansen <john.johansen@canonical.com>
+Acked-by: Seth Arnold <seth.arnold@canonical.com>
+(cherry picked from commit 7e57939b9d67dcfc2c8348fd0e2c76a2f0349c75)
+---
+ security/apparmor/label.c | 22 ++++++++--------------
+ 1 file changed, 8 insertions(+), 14 deletions(-)
+
+diff --git a/security/apparmor/label.c b/security/apparmor/label.c
+index e324f4df3e34..38be7a89cc31 100644
+--- a/security/apparmor/label.c
++++ b/security/apparmor/label.c
+@@ -1450,9 +1450,11 @@ bool aa_update_label_name(struct aa_ns *ns, struct aa_label *label, gfp_t gfp)
+  * cached label name is present and visible
+  * @label->hname only exists if label is namespace hierachical
+  */
+-static inline bool use_label_hname(struct aa_ns *ns, struct aa_label *label)
++static inline bool use_label_hname(struct aa_ns *ns, struct aa_label *label,
++                                 int flags)
+ {
+-      if (label->hname && labels_ns(label) == ns)
++      if (label->hname && (!ns || labels_ns(label) == ns) &&
++          !(flags & ~FLAG_SHOW_MODE))
+               return true;
+       return false;
+@@ -1710,10 +1712,8 @@ void aa_label_xaudit(struct audit_buffer *ab, struct aa_ns *ns,
+       AA_BUG(!ab);
+       AA_BUG(!label);
+-      if (!ns)
+-              ns = labels_ns(label);
+-
+-      if (!use_label_hname(ns, label) || display_mode(ns, label, flags)) {
++      if (!use_label_hname(ns, label, flags) ||
++          display_mode(ns, label, flags)) {
+               len  = aa_label_asxprint(&name, ns, label, flags, gfp);
+               if (len == -1) {
+                       AA_DEBUG("label print error");
+@@ -1738,10 +1738,7 @@ void aa_label_seq_xprint(struct seq_file *f, struct aa_ns *ns,
+       AA_BUG(!f);
+       AA_BUG(!label);
+-      if (!ns)
+-              ns = labels_ns(label);
+-
+-      if (!use_label_hname(ns, label)) {
++      if (!use_label_hname(ns, label, flags)) {
+               char *str;
+               int len;
+@@ -1764,10 +1761,7 @@ void aa_label_xprintk(struct aa_ns *ns, struct aa_label *label, int flags,
+ {
+       AA_BUG(!label);
+-      if (!ns)
+-              ns = labels_ns(label);
+-
+-      if (!use_label_hname(ns, label)) {
++      if (!use_label_hname(ns, label, flags)) {
+               char *str;
+               int len;
+-- 
+2.11.0
+
diff --git a/0009-apparmor-add-support-for-absolute-root-view-based-la.patch b/0009-apparmor-add-support-for-absolute-root-view-based-la.patch
new file mode 100644 (file)
index 0000000..84ee7a1
--- /dev/null
@@ -0,0 +1,63 @@
+From 6b092bbbf9e17b10f709d11b3bc2d7e493617934 Mon Sep 17 00:00:00 2001
+From: John Johansen <john.johansen@canonical.com>
+Date: Sun, 6 Aug 2017 05:39:08 -0700
+Subject: [PATCH 09/17] apparmor: add support for absolute root view based
+ labels
+
+With apparmor policy virtualization based on policy namespace View's
+we don't generally want/need absolute root based views, however there
+are cases like debugging and some secid based conversions where
+using a root based view is important.
+
+Signed-off-by: John Johansen <john.johansen@canonical.com>
+Acked-by: Seth Arnold <seth.arnold@canonical.com>
+(cherry picked from commit eadfbf0898eda94cee0d982626aa24a3146db48b)
+---
+ security/apparmor/include/label.h |  1 +
+ security/apparmor/label.c         | 10 +++++++++-
+ 2 files changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/security/apparmor/include/label.h b/security/apparmor/include/label.h
+index 9a283b722755..af22dcbbcb8a 100644
+--- a/security/apparmor/include/label.h
++++ b/security/apparmor/include/label.h
+@@ -310,6 +310,7 @@ bool aa_update_label_name(struct aa_ns *ns, struct aa_label *label, gfp_t gfp);
+ #define FLAG_SHOW_MODE 1
+ #define FLAG_VIEW_SUBNS 2
+ #define FLAG_HIDDEN_UNCONFINED 4
++#define FLAG_ABS_ROOT 8
+ int aa_label_snxprint(char *str, size_t size, struct aa_ns *view,
+                     struct aa_label *label, int flags);
+ int aa_label_asxprint(char **strp, struct aa_ns *ns, struct aa_label *label,
+diff --git a/security/apparmor/label.c b/security/apparmor/label.c
+index 38be7a89cc31..52b4ef14840d 100644
+--- a/security/apparmor/label.c
++++ b/security/apparmor/label.c
+@@ -1607,8 +1607,13 @@ int aa_label_snxprint(char *str, size_t size, struct aa_ns *ns,
+       AA_BUG(!str && size != 0);
+       AA_BUG(!label);
+-      if (!ns)
++      if (flags & FLAG_ABS_ROOT) {
++              ns = root_ns;
++              len = snprintf(str, size, "=");
++              update_for_len(total, len, size, str);
++      } else if (!ns) {
+               ns = labels_ns(label);
++      }
+       label_for_each(i, label, profile) {
+               if (aa_ns_visible(ns, profile->ns, flags & FLAG_VIEW_SUBNS)) {
+@@ -1868,6 +1873,9 @@ struct aa_label *aa_label_parse(struct aa_label *base, const char *str,
+               if (*str == '&')
+                       str++;
+       }
++      if (*str == '=')
++              base = &root_ns->unconfined->label;
++
+       error = vec_setup(profile, vec, len, gfp);
+       if (error)
+               return ERR_PTR(error);
+-- 
+2.11.0
+
diff --git a/0010-apparmor-make-policy_unpack-able-to-audit-different-.patch b/0010-apparmor-make-policy_unpack-able-to-audit-different-.patch
new file mode 100644 (file)
index 0000000..7e481b2
--- /dev/null
@@ -0,0 +1,219 @@
+From aa4b6bded85552bc5f9f22d2e18ce86c5c17947c Mon Sep 17 00:00:00 2001
+From: John Johansen <john.johansen@canonical.com>
+Date: Tue, 18 Jul 2017 23:37:18 -0700
+Subject: [PATCH 10/17] apparmor: make policy_unpack able to audit different
+ info messages
+
+Switch unpack auditing to using the generic name field in the audit
+struct and make it so we can start adding new info messages about
+why an unpack failed.
+
+Signed-off-by: John Johansen <john.johansen@canonical.com>
+Acked-by: Seth Arnold <seth.arnold@canonical.com>
+(cherry picked from commit 1489d896c5649e9ce1b6000b4857f8baa7a6ab63)
+---
+ security/apparmor/include/audit.h |  4 +--
+ security/apparmor/policy_unpack.c | 52 ++++++++++++++++++++++++++++-----------
+ 2 files changed, 40 insertions(+), 16 deletions(-)
+
+diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
+index c3fe1c5ef3bc..620e81169659 100644
+--- a/security/apparmor/include/audit.h
++++ b/security/apparmor/include/audit.h
+@@ -127,9 +127,9 @@ struct apparmor_audit_data {
+                       } fs;
+               };
+               struct {
+-                      const char *name;
+-                      long pos;
++                      struct aa_profile *profile;
+                       const char *ns;
++                      long pos;
+               } iface;
+               int signal;
+               struct {
+diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
+index bda0dce3b582..4ede87c30f8b 100644
+--- a/security/apparmor/policy_unpack.c
++++ b/security/apparmor/policy_unpack.c
+@@ -85,9 +85,9 @@ static void audit_cb(struct audit_buffer *ab, void *va)
+               audit_log_format(ab, " ns=");
+               audit_log_untrustedstring(ab, aad(sa)->iface.ns);
+       }
+-      if (aad(sa)->iface.name) {
++      if (aad(sa)->name) {
+               audit_log_format(ab, " name=");
+-              audit_log_untrustedstring(ab, aad(sa)->iface.name);
++              audit_log_untrustedstring(ab, aad(sa)->name);
+       }
+       if (aad(sa)->iface.pos)
+               audit_log_format(ab, " offset=%ld", aad(sa)->iface.pos);
+@@ -114,9 +114,9 @@ static int audit_iface(struct aa_profile *new, const char *ns_name,
+               aad(&sa)->iface.pos = e->pos - e->start;
+       aad(&sa)->iface.ns = ns_name;
+       if (new)
+-              aad(&sa)->iface.name = new->base.hname;
++              aad(&sa)->name = new->base.hname;
+       else
+-              aad(&sa)->iface.name = name;
++              aad(&sa)->name = name;
+       aad(&sa)->info = info;
+       aad(&sa)->error = error;
+@@ -583,6 +583,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
+ {
+       struct aa_profile *profile = NULL;
+       const char *tmpname, *tmpns = NULL, *name = NULL;
++      const char *info = "failed to unpack profile";
+       size_t ns_len;
+       struct rhashtable_params params = { 0 };
+       char *key = NULL;
+@@ -604,8 +605,10 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
+       tmpname = aa_splitn_fqname(name, strlen(name), &tmpns, &ns_len);
+       if (tmpns) {
+               *ns_name = kstrndup(tmpns, ns_len, GFP_KERNEL);
+-              if (!*ns_name)
++              if (!*ns_name) {
++                      info = "out of memory";
+                       goto fail;
++              }
+               name = tmpname;
+       }
+@@ -624,12 +627,15 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
+       if (IS_ERR(profile->xmatch)) {
+               error = PTR_ERR(profile->xmatch);
+               profile->xmatch = NULL;
++              info = "bad xmatch";
+               goto fail;
+       }
+       /* xmatch_len is not optional if xmatch is set */
+       if (profile->xmatch) {
+-              if (!unpack_u32(e, &tmp, NULL))
++              if (!unpack_u32(e, &tmp, NULL)) {
++                      info = "missing xmatch len";
+                       goto fail;
++              }
+               profile->xmatch_len = tmp;
+       }
+@@ -637,8 +643,11 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
+       (void) unpack_str(e, &profile->disconnected, "disconnected");
+       /* per profile debug flags (complain, audit) */
+-      if (!unpack_nameX(e, AA_STRUCT, "flags"))
++      if (!unpack_nameX(e, AA_STRUCT, "flags")) {
++              info = "profile missing flags";
+               goto fail;
++      }
++      info = "failed to unpack profile flags";
+       if (!unpack_u32(e, &tmp, NULL))
+               goto fail;
+       if (tmp & PACKED_FLAG_HAT)
+@@ -667,6 +676,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
+               /* set a default value if path_flags field is not present */
+               profile->path_flags = PATH_MEDIATE_DELETED;
++      info = "failed to unpack profile capabilities";
+       if (!unpack_u32(e, &(profile->caps.allow.cap[0]), NULL))
+               goto fail;
+       if (!unpack_u32(e, &(profile->caps.audit.cap[0]), NULL))
+@@ -676,6 +686,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
+       if (!unpack_u32(e, &tmpcap.cap[0], NULL))
+               goto fail;
++      info = "failed to unpack upper profile capabilities";
+       if (unpack_nameX(e, AA_STRUCT, "caps64")) {
+               /* optional upper half of 64 bit caps */
+               if (!unpack_u32(e, &(profile->caps.allow.cap[1]), NULL))
+@@ -690,6 +701,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
+                       goto fail;
+       }
++      info = "failed to unpack extended profile capabilities";
+       if (unpack_nameX(e, AA_STRUCT, "capsx")) {
+               /* optional extended caps mediation mask */
+               if (!unpack_u32(e, &(profile->caps.extended.cap[0]), NULL))
+@@ -700,11 +712,14 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
+                       goto fail;
+       }
+-      if (!unpack_rlimits(e, profile))
++      if (!unpack_rlimits(e, profile)) {
++              info = "failed to unpack profile rlimits";
+               goto fail;
++      }
+       if (unpack_nameX(e, AA_STRUCT, "policydb")) {
+               /* generic policy dfa - optional and may be NULL */
++              info = "failed to unpack policydb";
+               profile->policy.dfa = unpack_dfa(e);
+               if (IS_ERR(profile->policy.dfa)) {
+                       error = PTR_ERR(profile->policy.dfa);
+@@ -734,6 +749,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
+       if (IS_ERR(profile->file.dfa)) {
+               error = PTR_ERR(profile->file.dfa);
+               profile->file.dfa = NULL;
++              info = "failed to unpack profile file rules";
+               goto fail;
+       } else if (profile->file.dfa) {
+               if (!unpack_u32(e, &profile->file.start, "dfa_start"))
+@@ -746,10 +762,13 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
+       } else
+               profile->file.dfa = aa_get_dfa(nulldfa);
+-      if (!unpack_trans_table(e, profile))
++      if (!unpack_trans_table(e, profile)) {
++              info = "failed to unpack profile transition table";
+               goto fail;
++      }
+       if (unpack_nameX(e, AA_STRUCT, "data")) {
++              info = "out of memory";
+               profile->data = kzalloc(sizeof(*profile->data), GFP_KERNEL);
+               if (!profile->data)
+                       goto fail;
+@@ -761,8 +780,10 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
+               params.hashfn = strhash;
+               params.obj_cmpfn = datacmp;
+-              if (rhashtable_init(profile->data, &params))
++              if (rhashtable_init(profile->data, &params)) {
++                      info = "failed to init key, value hash table";
+                       goto fail;
++              }
+               while (unpack_strdup(e, &key, NULL)) {
+                       data = kzalloc(sizeof(*data), GFP_KERNEL);
+@@ -784,12 +805,16 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
+                                              profile->data->p);
+               }
+-              if (!unpack_nameX(e, AA_STRUCTEND, NULL))
++              if (!unpack_nameX(e, AA_STRUCTEND, NULL)) {
++                      info = "failed to unpack end of key, value data table";
+                       goto fail;
++              }
+       }
+-      if (!unpack_nameX(e, AA_STRUCTEND, NULL))
++      if (!unpack_nameX(e, AA_STRUCTEND, NULL)) {
++              info = "failed to unpack end of profile";
+               goto fail;
++      }
+       return profile;
+@@ -798,8 +823,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
+               name = NULL;
+       else if (!name)
+               name = "unknown";
+-      audit_iface(profile, NULL, name, "failed to unpack profile", e,
+-                  error);
++      audit_iface(profile, NULL, name, info, e, error);
+       aa_free_profile(profile);
+       return ERR_PTR(error);
+-- 
+2.11.0
+
diff --git a/0011-apparmor-add-more-debug-asserts-to-apparmorfs.patch b/0011-apparmor-add-more-debug-asserts-to-apparmorfs.patch
new file mode 100644 (file)
index 0000000..85eafc8
--- /dev/null
@@ -0,0 +1,78 @@
+From ba3f778a2ef31454032c2ca9c99d9212feb4dcf1 Mon Sep 17 00:00:00 2001
+From: John Johansen <john.johansen@canonical.com>
+Date: Tue, 18 Jul 2017 23:41:13 -0700
+Subject: [PATCH 11/17] apparmor: add more debug asserts to apparmorfs
+
+Signed-off-by: John Johansen <john.johansen@canonical.com>
+Acked-by: Seth Arnold <seth.arnold@canonical.com>
+(cherry picked from commit 52c9542126fb04df1f12c605b6c22719c9096794)
+---
+ security/apparmor/apparmorfs.c | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
+index 8fa6c898c44b..7acea14c850b 100644
+--- a/security/apparmor/apparmorfs.c
++++ b/security/apparmor/apparmorfs.c
+@@ -1446,6 +1446,10 @@ void __aafs_profile_migrate_dents(struct aa_profile *old,
+ {
+       int i;
++      AA_BUG(!old);
++      AA_BUG(!new);
++      AA_BUG(!mutex_is_locked(&profiles_ns(old)->lock));
++
+       for (i = 0; i < AAFS_PROF_SIZEOF; i++) {
+               new->dents[i] = old->dents[i];
+               if (new->dents[i])
+@@ -1509,6 +1513,9 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent)
+       struct dentry *dent = NULL, *dir;
+       int error;
++      AA_BUG(!profile);
++      AA_BUG(!mutex_is_locked(&profiles_ns(profile)->lock));
++
+       if (!parent) {
+               struct aa_profile *p;
+               p = aa_deref_parent(profile);
+@@ -1734,6 +1741,7 @@ void __aafs_ns_rmdir(struct aa_ns *ns)
+       if (!ns)
+               return;
++      AA_BUG(!mutex_is_locked(&ns->lock));
+       list_for_each_entry(child, &ns->base.profiles, base.list)
+               __aafs_profile_rmdir(child);
+@@ -1906,6 +1914,10 @@ static struct aa_ns *__next_ns(struct aa_ns *root, struct aa_ns *ns)
+ {
+       struct aa_ns *parent, *next;
++      AA_BUG(!root);
++      AA_BUG(!ns);
++      AA_BUG(ns != root && !mutex_is_locked(&ns->parent->lock));
++
+       /* is next namespace a child */
+       if (!list_empty(&ns->sub_ns)) {
+               next = list_first_entry(&ns->sub_ns, typeof(*ns), base.list);
+@@ -1940,6 +1952,9 @@ static struct aa_ns *__next_ns(struct aa_ns *root, struct aa_ns *ns)
+ static struct aa_profile *__first_profile(struct aa_ns *root,
+                                         struct aa_ns *ns)
+ {
++      AA_BUG(!root);
++      AA_BUG(ns && !mutex_is_locked(&ns->lock));
++
+       for (; ns; ns = __next_ns(root, ns)) {
+               if (!list_empty(&ns->base.profiles))
+                       return list_first_entry(&ns->base.profiles,
+@@ -1962,6 +1977,8 @@ static struct aa_profile *__next_profile(struct aa_profile *p)
+       struct aa_profile *parent;
+       struct aa_ns *ns = p->ns;
++      AA_BUG(!mutex_is_locked(&profiles_ns(p)->lock));
++
+       /* is next profile a child */
+       if (!list_empty(&p->base.profiles))
+               return list_first_entry(&p->base.profiles, typeof(*p),
+-- 
+2.11.0
+
diff --git a/0012-apparmor-add-base-infastructure-for-socket-mediation.patch b/0012-apparmor-add-base-infastructure-for-socket-mediation.patch
new file mode 100644 (file)
index 0000000..2a29c96
--- /dev/null
@@ -0,0 +1,1123 @@
+From 853cbdfb6924857a2ee2a1cd5b9fa494f8e7efa2 Mon Sep 17 00:00:00 2001
+From: John Johansen <john.johansen@canonical.com>
+Date: Tue, 18 Jul 2017 23:18:33 -0700
+Subject: [PATCH 12/17] apparmor: add base infastructure for socket mediation
+
+Provide a basic mediation of sockets. This is not a full net mediation
+but just whether a spcific family of socket can be used by an
+application, along with setting up some basic infrastructure for
+network mediation to follow.
+
+the user space rule hav the basic form of
+  NETWORK RULE = [ QUALIFIERS ] 'network' [ DOMAIN ]
+                 [ TYPE | PROTOCOL ]
+
+  DOMAIN = ( 'inet' | 'ax25' | 'ipx' | 'appletalk' | 'netrom' |
+             'bridge' | 'atmpvc' | 'x25' | 'inet6' | 'rose' |
+            'netbeui' | 'security' | 'key' | 'packet' | 'ash' |
+            'econet' | 'atmsvc' | 'sna' | 'irda' | 'pppox' |
+            'wanpipe' | 'bluetooth' | 'netlink' | 'unix' | 'rds' |
+            'llc' | 'can' | 'tipc' | 'iucv' | 'rxrpc' | 'isdn' |
+            'phonet' | 'ieee802154' | 'caif' | 'alg' | 'nfc' |
+            'vsock' | 'mpls' | 'ib' | 'kcm' ) ','
+
+  TYPE = ( 'stream' | 'dgram' | 'seqpacket' |  'rdm' | 'raw' |
+           'packet' )
+
+  PROTOCOL = ( 'tcp' | 'udp' | 'icmp' )
+
+eg.
+  network,
+  network inet,
+
+Signed-off-by: John Johansen <john.johansen@canonical.com>
+Acked-by: Seth Arnold <seth.arnold@canonical.com>
+(cherry picked from commit 56387cbe3f287034ee6959cb9e8f419889e38bd9)
+---
+ security/apparmor/.gitignore       |   1 +
+ security/apparmor/Makefile         |  43 ++++-
+ security/apparmor/apparmorfs.c     |   1 +
+ security/apparmor/file.c           |  30 +++
+ security/apparmor/include/audit.h  |  26 ++-
+ security/apparmor/include/net.h    | 114 +++++++++++
+ security/apparmor/include/perms.h  |   5 +-
+ security/apparmor/include/policy.h |  13 ++
+ security/apparmor/lib.c            |   5 +-
+ security/apparmor/lsm.c            | 387 +++++++++++++++++++++++++++++++++++++
+ security/apparmor/net.c            | 184 ++++++++++++++++++
+ security/apparmor/policy_unpack.c  |  47 ++++-
+ 12 files changed, 840 insertions(+), 16 deletions(-)
+ create mode 100644 security/apparmor/include/net.h
+ create mode 100644 security/apparmor/net.c
+
+diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore
+index 9cdec70d72b8..d5b291e94264 100644
+--- a/security/apparmor/.gitignore
++++ b/security/apparmor/.gitignore
+@@ -1,5 +1,6 @@
+ #
+ # Generated include files
+ #
++net_names.h
+ capability_names.h
+ rlim_names.h
+diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
+index 81a34426d024..dafdd387d42b 100644
+--- a/security/apparmor/Makefile
++++ b/security/apparmor/Makefile
+@@ -4,11 +4,44 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
+ apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
+               path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
+-              resource.o secid.o file.o policy_ns.o label.o mount.o
++              resource.o secid.o file.o policy_ns.o label.o mount.o net.o
+ apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
+-clean-files := capability_names.h rlim_names.h
++clean-files := capability_names.h rlim_names.h net_names.h
++# Build a lower case string table of address family names
++# Transform lines from
++#    #define AF_LOCAL         1       /* POSIX name for AF_UNIX       */
++#    #define AF_INET          2       /* Internet IP Protocol         */
++# to
++#    [1] = "local",
++#    [2] = "inet",
++#
++# and build the securityfs entries for the mapping.
++# Transforms lines from
++#    #define AF_INET          2       /* Internet IP Protocol         */
++# to
++#    #define AA_SFS_AF_MASK "local inet"
++quiet_cmd_make-af = GEN     $@
++cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\
++      sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e "/AF_ROUTE/d" -e \
++       's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
++      echo "};" >> $@ ;\
++      printf '%s' '\#define AA_SFS_AF_MASK "' >> $@ ;\
++      sed -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e "/AF_ROUTE/d" -e \
++       's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\
++       $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
++
++# Build a lower case string table of sock type names
++# Transform lines from
++#    SOCK_STREAM      = 1,
++# to
++#    [1] = "stream",
++quiet_cmd_make-sock = GEN     $@
++cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\
++      sed $^ >>$@ -r -n \
++      -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
++      echo "};" >> $@
+ # Build a lower case string table of capability names
+ # Transforms lines from
+@@ -61,6 +94,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \
+           tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
+ $(obj)/capability.o : $(obj)/capability_names.h
++$(obj)/net.o : $(obj)/net_names.h
+ $(obj)/resource.o : $(obj)/rlim_names.h
+ $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
+                           $(src)/Makefile
+@@ -68,3 +102,8 @@ $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
+ $(obj)/rlim_names.h : $(srctree)/include/uapi/asm-generic/resource.h \
+                     $(src)/Makefile
+       $(call cmd,make-rlim)
++$(obj)/net_names.h : $(srctree)/include/linux/socket.h \
++                   $(srctree)/include/linux/net.h \
++                   $(src)/Makefile
++      $(call cmd,make-af)
++      $(call cmd,make-sock)
+diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
+index 7acea14c850b..125dad5c3fde 100644
+--- a/security/apparmor/apparmorfs.c
++++ b/security/apparmor/apparmorfs.c
+@@ -2202,6 +2202,7 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = {
+       AA_SFS_DIR("policy",                    aa_sfs_entry_policy),
+       AA_SFS_DIR("domain",                    aa_sfs_entry_domain),
+       AA_SFS_DIR("file",                      aa_sfs_entry_file),
++      AA_SFS_DIR("network",                   aa_sfs_entry_network),
+       AA_SFS_DIR("mount",                     aa_sfs_entry_mount),
+       AA_SFS_DIR("namespaces",                aa_sfs_entry_ns),
+       AA_SFS_FILE_U64("capability",           VFS_CAP_FLAGS_MASK),
+diff --git a/security/apparmor/file.c b/security/apparmor/file.c
+index 3382518b87fa..db80221891c6 100644
+--- a/security/apparmor/file.c
++++ b/security/apparmor/file.c
+@@ -21,6 +21,7 @@
+ #include "include/context.h"
+ #include "include/file.h"
+ #include "include/match.h"
++#include "include/net.h"
+ #include "include/path.h"
+ #include "include/policy.h"
+ #include "include/label.h"
+@@ -566,6 +567,32 @@ static int __file_path_perm(const char *op, struct aa_label *label,
+       return error;
+ }
++static int __file_sock_perm(const char *op, struct aa_label *label,
++                          struct aa_label *flabel, struct file *file,
++                          u32 request, u32 denied)
++{
++      struct socket *sock = (struct socket *) file->private_data;
++      int error;
++
++      AA_BUG(!sock);
++
++      /* revalidation due to label out of date. No revocation at this time */
++      if (!denied && aa_label_is_subset(flabel, label))
++              return 0;
++
++      /* TODO: improve to skip profiles cached in flabel */
++      error = aa_sock_file_perm(label, op, request, sock);
++      if (denied) {
++              /* TODO: improve to skip profiles checked above */
++              /* check every profile in file label to is cached */
++              last_error(error, aa_sock_file_perm(flabel, op, request, sock));
++      }
++      if (!error)
++              update_file_ctx(file_ctx(file), label, request);
++
++      return error;
++}
++
+ /**
+  * aa_file_perm - do permission revalidation check & audit for @file
+  * @op: operation being checked
+@@ -610,6 +637,9 @@ int aa_file_perm(const char *op, struct aa_label *label, struct file *file,
+               error = __file_path_perm(op, label, flabel, file, request,
+                                        denied);
++      else if (S_ISSOCK(file_inode(file)->i_mode))
++              error = __file_sock_perm(op, label, flabel, file, request,
++                                       denied);
+ done:
+       rcu_read_unlock();
+diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
+index 620e81169659..ff4316e1068d 100644
+--- a/security/apparmor/include/audit.h
++++ b/security/apparmor/include/audit.h
+@@ -121,21 +121,29 @@ struct apparmor_audit_data {
+               /* these entries require a custom callback fn */
+               struct {
+                       struct aa_label *peer;
+-                      struct {
+-                              const char *target;
+-                              kuid_t ouid;
+-                      } fs;
++                      union {
++                              struct {
++                                      kuid_t ouid;
++                                      const char *target;
++                              } fs;
++                              struct {
++                                      int type, protocol;
++                                      struct sock *peer_sk;
++                                      void *addr;
++                                      int addrlen;
++                              } net;
++                              int signal;
++                              struct {
++                                      int rlim;
++                                      unsigned long max;
++                              } rlim;
++                      };
+               };
+               struct {
+                       struct aa_profile *profile;
+                       const char *ns;
+                       long pos;
+               } iface;
+-              int signal;
+-              struct {
+-                      int rlim;
+-                      unsigned long max;
+-              } rlim;
+               struct {
+                       const char *src_name;
+                       const char *type;
+diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
+new file mode 100644
+index 000000000000..140c8efcf364
+--- /dev/null
++++ b/security/apparmor/include/net.h
+@@ -0,0 +1,114 @@
++/*
++ * AppArmor security module
++ *
++ * This file contains AppArmor network mediation definitions.
++ *
++ * Copyright (C) 1998-2008 Novell/SUSE
++ * Copyright 2009-2017 Canonical Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation, version 2 of the
++ * License.
++ */
++
++#ifndef __AA_NET_H
++#define __AA_NET_H
++
++#include <net/sock.h>
++#include <linux/path.h>
++
++#include "apparmorfs.h"
++#include "label.h"
++#include "perms.h"
++#include "policy.h"
++
++#define AA_MAY_SEND           AA_MAY_WRITE
++#define AA_MAY_RECEIVE                AA_MAY_READ
++
++#define AA_MAY_SHUTDOWN               AA_MAY_DELETE
++
++#define AA_MAY_CONNECT                AA_MAY_OPEN
++#define AA_MAY_ACCEPT         0x00100000
++
++#define AA_MAY_BIND           0x00200000
++#define AA_MAY_LISTEN         0x00400000
++
++#define AA_MAY_SETOPT         0x01000000
++#define AA_MAY_GETOPT         0x02000000
++
++#define NET_PERMS_MASK (AA_MAY_SEND | AA_MAY_RECEIVE | AA_MAY_CREATE |    \
++                      AA_MAY_SHUTDOWN | AA_MAY_BIND | AA_MAY_LISTEN |   \
++                      AA_MAY_CONNECT | AA_MAY_ACCEPT | AA_MAY_SETATTR | \
++                      AA_MAY_GETATTR | AA_MAY_SETOPT | AA_MAY_GETOPT)
++
++#define NET_FS_PERMS (AA_MAY_SEND | AA_MAY_RECEIVE | AA_MAY_CREATE |  \
++                    AA_MAY_SHUTDOWN | AA_MAY_CONNECT | AA_MAY_RENAME |\
++                    AA_MAY_SETATTR | AA_MAY_GETATTR | AA_MAY_CHMOD |  \
++                    AA_MAY_CHOWN | AA_MAY_CHGRP | AA_MAY_LOCK |       \
++                    AA_MAY_MPROT)
++
++#define NET_PEER_MASK (AA_MAY_SEND | AA_MAY_RECEIVE | AA_MAY_CONNECT |        \
++                     AA_MAY_ACCEPT)
++struct aa_sk_ctx {
++      struct aa_label *label;
++      struct aa_label *peer;
++      struct path path;
++};
++
++#define SK_CTX(X) ((X)->sk_security)
++#define SOCK_ctx(X) SOCK_INODE(X)->i_security
++#define DEFINE_AUDIT_NET(NAME, OP, SK, F, T, P)                                 \
++      struct lsm_network_audit NAME ## _net = { .sk = (SK),             \
++                                                .family = (F)};         \
++      DEFINE_AUDIT_DATA(NAME,                                           \
++                        ((SK) && (F) != AF_UNIX) ? LSM_AUDIT_DATA_NET : \
++                                                   LSM_AUDIT_DATA_NONE, \
++                        OP);                                            \
++      NAME.u.net = &(NAME ## _net);                                     \
++      aad(&NAME)->net.type = (T);                                       \
++      aad(&NAME)->net.protocol = (P)
++
++#define DEFINE_AUDIT_SK(NAME, OP, SK)                                 \
++      DEFINE_AUDIT_NET(NAME, OP, SK, (SK)->sk_family, (SK)->sk_type,  \
++                       (SK)->sk_protocol)
++
++/* struct aa_net - network confinement data
++ * @allow: basic network families permissions
++ * @audit: which network permissions to force audit
++ * @quiet: which network permissions to quiet rejects
++ */
++struct aa_net {
++      u16 allow[AF_MAX];
++      u16 audit[AF_MAX];
++      u16 quiet[AF_MAX];
++};
++
++
++extern struct aa_sfs_entry aa_sfs_entry_network[];
++
++void audit_net_cb(struct audit_buffer *ab, void *va);
++int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa,
++                     u32 request, u16 family, int type);
++int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family,
++             int type, int protocol);
++static inline int aa_profile_af_sk_perm(struct aa_profile *profile,
++                                      struct common_audit_data *sa,
++                                      u32 request,
++                                      struct sock *sk)
++{
++      return aa_profile_af_perm(profile, sa, request, sk->sk_family,
++                                sk->sk_type);
++}
++int aa_sk_perm(const char *op, u32 request, struct sock *sk);
++
++int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request,
++                    struct socket *sock);
++
++
++static inline void aa_free_net_rules(struct aa_net *new)
++{
++      /* NOP */
++}
++
++#endif /* __AA_NET_H */
+diff --git a/security/apparmor/include/perms.h b/security/apparmor/include/perms.h
+index 2b27bb79aec4..af04d5a7d73d 100644
+--- a/security/apparmor/include/perms.h
++++ b/security/apparmor/include/perms.h
+@@ -135,9 +135,10 @@ extern struct aa_perms allperms;
+ void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask);
+-void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask);
++void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names,
++                       u32 mask);
+ void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
+-                      u32 chrsmask, const char **names, u32 namesmask);
++                      u32 chrsmask, const char * const *names, u32 namesmask);
+ void aa_apply_modes_to_perms(struct aa_profile *profile,
+                            struct aa_perms *perms);
+ void aa_compute_perms(struct aa_dfa *dfa, unsigned int state,
+diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
+index 17fe41a9cac3..4364088a0b9e 100644
+--- a/security/apparmor/include/policy.h
++++ b/security/apparmor/include/policy.h
+@@ -30,6 +30,7 @@
+ #include "file.h"
+ #include "lib.h"
+ #include "label.h"
++#include "net.h"
+ #include "perms.h"
+ #include "resource.h"
+@@ -111,6 +112,7 @@ struct aa_data {
+  * @policy: general match rules governing policy
+  * @file: The set of rules governing basic file access and domain transitions
+  * @caps: capabilities for the profile
++ * @net: network controls for the profile
+  * @rlimits: rlimits for the profile
+  *
+  * @dents: dentries for the profiles file entries in apparmorfs
+@@ -148,6 +150,7 @@ struct aa_profile {
+       struct aa_policydb policy;
+       struct aa_file_rules file;
+       struct aa_caps caps;
++      struct aa_net net;
+       struct aa_rlimit rlimits;
+       struct aa_loaddata *rawdata;
+@@ -220,6 +223,16 @@ static inline unsigned int PROFILE_MEDIATES_SAFE(struct aa_profile *profile,
+       return 0;
+ }
++static inline unsigned int PROFILE_MEDIATES_AF(struct aa_profile *profile,
++                                             u16 AF) {
++      unsigned int state = PROFILE_MEDIATES(profile, AA_CLASS_NET);
++      u16 be_af = cpu_to_be16(AF);
++
++      if (!state)
++              return 0;
++      return aa_dfa_match_len(profile->policy.dfa, state, (char *) &be_af, 2);
++}
++
+ /**
+  * aa_get_profile - increment refcount on profile @p
+  * @p: profile  (MAYBE NULL)
+diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c
+index 08ca26bcca77..8818621b5d95 100644
+--- a/security/apparmor/lib.c
++++ b/security/apparmor/lib.c
+@@ -211,7 +211,8 @@ void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask)
+       *str = '\0';
+ }
+-void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask)
++void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names,
++                       u32 mask)
+ {
+       const char *fmt = "%s";
+       unsigned int i, perm = 1;
+@@ -229,7 +230,7 @@ void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask)
+ }
+ void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
+-                      u32 chrsmask, const char **names, u32 namesmask)
++                      u32 chrsmask, const char * const *names, u32 namesmask)
+ {
+       char str[33];
+diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
+index 4ad0b3a45142..cc5ab23a2d84 100644
+--- a/security/apparmor/lsm.c
++++ b/security/apparmor/lsm.c
+@@ -33,6 +33,7 @@
+ #include "include/context.h"
+ #include "include/file.h"
+ #include "include/ipc.h"
++#include "include/net.h"
+ #include "include/path.h"
+ #include "include/label.h"
+ #include "include/policy.h"
+@@ -736,6 +737,368 @@ static int apparmor_task_kill(struct task_struct *target, struct siginfo *info,
+       return error;
+ }
++/**
++ * apparmor_sk_alloc_security - allocate and attach the sk_security field
++ */
++static int apparmor_sk_alloc_security(struct sock *sk, int family, gfp_t flags)
++{
++      struct aa_sk_ctx *ctx;
++
++      ctx = kzalloc(sizeof(*ctx), flags);
++      if (!ctx)
++              return -ENOMEM;
++
++      SK_CTX(sk) = ctx;
++
++      return 0;
++}
++
++/**
++ * apparmor_sk_free_security - free the sk_security field
++ */
++static void apparmor_sk_free_security(struct sock *sk)
++{
++      struct aa_sk_ctx *ctx = SK_CTX(sk);
++
++      SK_CTX(sk) = NULL;
++      aa_put_label(ctx->label);
++      aa_put_label(ctx->peer);
++      path_put(&ctx->path);
++      kfree(ctx);
++}
++
++/**
++ * apparmor_clone_security - clone the sk_security field
++ */
++static void apparmor_sk_clone_security(const struct sock *sk,
++                                     struct sock *newsk)
++{
++      struct aa_sk_ctx *ctx = SK_CTX(sk);
++      struct aa_sk_ctx *new = SK_CTX(newsk);
++
++      new->label = aa_get_label(ctx->label);
++      new->peer = aa_get_label(ctx->peer);
++      new->path = ctx->path;
++      path_get(&new->path);
++}
++
++static int aa_sock_create_perm(struct aa_label *label, int family, int type,
++                             int protocol)
++{
++      AA_BUG(!label);
++      AA_BUG(in_interrupt());
++
++      return aa_af_perm(label, OP_CREATE, AA_MAY_CREATE, family, type,
++                        protocol);
++}
++
++
++/**
++ * apparmor_socket_create - check perms before creating a new socket
++ */
++static int apparmor_socket_create(int family, int type, int protocol, int kern)
++{
++      struct aa_label *label;
++      int error = 0;
++
++      label = begin_current_label_crit_section();
++      if (!(kern || unconfined(label)))
++              error = aa_sock_create_perm(label, family, type, protocol);
++      end_current_label_crit_section(label);
++
++      return error;
++}
++
++/**
++ * apparmor_socket_post_create - setup the per-socket security struct
++ *
++ * Note:
++ * -   kernel sockets currently labeled unconfined but we may want to
++ *     move to a special kernel label
++ * -   socket may not have sk here if created with sock_create_lite or
++ *     sock_alloc. These should be accept cases which will be handled in
++ *     sock_graft.
++ */
++static int apparmor_socket_post_create(struct socket *sock, int family,
++                                     int type, int protocol, int kern)
++{
++      struct aa_label *label;
++
++      if (kern) {
++              struct aa_ns *ns = aa_get_current_ns();
++
++              label = aa_get_label(ns_unconfined(ns));
++              aa_put_ns(ns);
++      } else
++              label = aa_get_current_label();
++
++      if (sock->sk) {
++              struct aa_sk_ctx *ctx = SK_CTX(sock->sk);
++
++              aa_put_label(ctx->label);
++              ctx->label = aa_get_label(label);
++      }
++      aa_put_label(label);
++
++      return 0;
++}
++
++/**
++ * apparmor_socket_bind - check perms before bind addr to socket
++ */
++static int apparmor_socket_bind(struct socket *sock,
++                              struct sockaddr *address, int addrlen)
++{
++      AA_BUG(!sock);
++      AA_BUG(!sock->sk);
++      AA_BUG(!address);
++      AA_BUG(in_interrupt());
++
++      return aa_sk_perm(OP_BIND, AA_MAY_BIND, sock->sk);
++}
++
++/**
++ * apparmor_socket_connect - check perms before connecting @sock to @address
++ */
++static int apparmor_socket_connect(struct socket *sock,
++                                 struct sockaddr *address, int addrlen)
++{
++      AA_BUG(!sock);
++      AA_BUG(!sock->sk);
++      AA_BUG(!address);
++      AA_BUG(in_interrupt());
++
++      return aa_sk_perm(OP_CONNECT, AA_MAY_CONNECT, sock->sk);
++}
++
++/**
++ * apparmor_socket_list - check perms before allowing listen
++ */
++static int apparmor_socket_listen(struct socket *sock, int backlog)
++{
++      AA_BUG(!sock);
++      AA_BUG(!sock->sk);
++      AA_BUG(in_interrupt());
++
++      return aa_sk_perm(OP_LISTEN, AA_MAY_LISTEN, sock->sk);
++}
++
++/**
++ * apparmor_socket_accept - check perms before accepting a new connection.
++ *
++ * Note: while @newsock is created and has some information, the accept
++ *       has not been done.
++ */
++static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
++{
++      AA_BUG(!sock);
++      AA_BUG(!sock->sk);
++      AA_BUG(!newsock);
++      AA_BUG(in_interrupt());
++
++      return aa_sk_perm(OP_ACCEPT, AA_MAY_ACCEPT, sock->sk);
++}
++
++static int aa_sock_msg_perm(const char *op, u32 request, struct socket *sock,
++                          struct msghdr *msg, int size)
++{
++      AA_BUG(!sock);
++      AA_BUG(!sock->sk);
++      AA_BUG(!msg);
++      AA_BUG(in_interrupt());
++
++      return aa_sk_perm(op, request, sock->sk);
++}
++
++/**
++ * apparmor_socket_sendmsg - check perms before sending msg to another socket
++ */
++static int apparmor_socket_sendmsg(struct socket *sock,
++                                 struct msghdr *msg, int size)
++{
++      return aa_sock_msg_perm(OP_SENDMSG, AA_MAY_SEND, sock, msg, size);
++}
++
++/**
++ * apparmor_socket_recvmsg - check perms before receiving a message
++ */
++static int apparmor_socket_recvmsg(struct socket *sock,
++                                 struct msghdr *msg, int size, int flags)
++{
++      return aa_sock_msg_perm(OP_RECVMSG, AA_MAY_RECEIVE, sock, msg, size);
++}
++
++/* revaliation, get/set attr, shutdown */
++static int aa_sock_perm(const char *op, u32 request, struct socket *sock)
++{
++      AA_BUG(!sock);
++      AA_BUG(!sock->sk);
++      AA_BUG(in_interrupt());
++
++      return aa_sk_perm(op, request, sock->sk);
++}
++
++/**
++ * apparmor_socket_getsockname - check perms before getting the local address
++ */
++static int apparmor_socket_getsockname(struct socket *sock)
++{
++      return aa_sock_perm(OP_GETSOCKNAME, AA_MAY_GETATTR, sock);
++}
++
++/**
++ * apparmor_socket_getpeername - check perms before getting remote address
++ */
++static int apparmor_socket_getpeername(struct socket *sock)
++{
++      return aa_sock_perm(OP_GETPEERNAME, AA_MAY_GETATTR, sock);
++}
++
++/* revaliation, get/set attr, opt */
++static int aa_sock_opt_perm(const char *op, u32 request, struct socket *sock,
++                          int level, int optname)
++{
++      AA_BUG(!sock);
++      AA_BUG(!sock->sk);
++      AA_BUG(in_interrupt());
++
++      return aa_sk_perm(op, request, sock->sk);
++}
++
++/**
++ * apparmor_getsockopt - check perms before getting socket options
++ */
++static int apparmor_socket_getsockopt(struct socket *sock, int level,
++                                    int optname)
++{
++      return aa_sock_opt_perm(OP_GETSOCKOPT, AA_MAY_GETOPT, sock,
++                              level, optname);
++}
++
++/**
++ * apparmor_setsockopt - check perms before setting socket options
++ */
++static int apparmor_socket_setsockopt(struct socket *sock, int level,
++                                    int optname)
++{
++      return aa_sock_opt_perm(OP_SETSOCKOPT, AA_MAY_SETOPT, sock,
++                              level, optname);
++}
++
++/**
++ * apparmor_socket_shutdown - check perms before shutting down @sock conn
++ */
++static int apparmor_socket_shutdown(struct socket *sock, int how)
++{
++      return aa_sock_perm(OP_SHUTDOWN, AA_MAY_SHUTDOWN, sock);
++}
++
++/**
++ * apparmor_socket_sock_recv_skb - check perms before associating skb to sk
++ *
++ * Note: can not sleep may be called with locks held
++ *
++ * dont want protocol specific in __skb_recv_datagram()
++ * to deny an incoming connection  socket_sock_rcv_skb()
++ */
++static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
++{
++      return 0;
++}
++
++
++static struct aa_label *sk_peer_label(struct sock *sk)
++{
++      struct aa_sk_ctx *ctx = SK_CTX(sk);
++
++      if (ctx->peer)
++              return ctx->peer;
++
++      return ERR_PTR(-ENOPROTOOPT);
++}
++
++/**
++ * apparmor_socket_getpeersec_stream - get security context of peer
++ *
++ * Note: for tcp only valid if using ipsec or cipso on lan
++ */
++static int apparmor_socket_getpeersec_stream(struct socket *sock,
++                                           char __user *optval,
++                                           int __user *optlen,
++                                           unsigned int len)
++{
++      char *name;
++      int slen, error = 0;
++      struct aa_label *label;
++      struct aa_label *peer;
++
++      label = begin_current_label_crit_section();
++      peer = sk_peer_label(sock->sk);
++      if (IS_ERR(peer)) {
++              error = PTR_ERR(peer);
++              goto done;
++      }
++      slen = aa_label_asxprint(&name, labels_ns(label), peer,
++                               FLAG_SHOW_MODE | FLAG_VIEW_SUBNS |
++                               FLAG_HIDDEN_UNCONFINED, GFP_KERNEL);
++      /* don't include terminating \0 in slen, it breaks some apps */
++      if (slen < 0) {
++              error = -ENOMEM;
++      } else {
++              if (slen > len) {
++                      error = -ERANGE;
++              } else if (copy_to_user(optval, name, slen)) {
++                      error = -EFAULT;
++                      goto out;
++              }
++              if (put_user(slen, optlen))
++                      error = -EFAULT;
++out:
++              kfree(name);
++
++      }
++
++done:
++      end_current_label_crit_section(label);
++
++      return error;
++}
++
++/**
++ * apparmor_socket_getpeersec_dgram - get security label of packet
++ * @sock: the peer socket
++ * @skb: packet data
++ * @secid: pointer to where to put the secid of the packet
++ *
++ * Sets the netlabel socket state on sk from parent
++ */
++static int apparmor_socket_getpeersec_dgram(struct socket *sock,
++                                          struct sk_buff *skb, u32 *secid)
++
++{
++      /* TODO: requires secid support */
++      return -ENOPROTOOPT;
++}
++
++/**
++ * apparmor_sock_graft - Initialize newly created socket
++ * @sk: child sock
++ * @parent: parent socket
++ *
++ * Note: could set off of SOCK_CTX(parent) but need to track inode and we can
++ *       just set sk security information off of current creating process label
++ *       Labeling of sk for accept case - probably should be sock based
++ *       instead of task, because of the case where an implicitly labeled
++ *       socket is shared by different tasks.
++ */
++static void apparmor_sock_graft(struct sock *sk, struct socket *parent)
++{
++      struct aa_sk_ctx *ctx = SK_CTX(sk);
++
++      if (!ctx->label)
++              ctx->label = aa_get_current_label();
++}
++
+ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
+       LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
+       LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
+@@ -770,6 +1133,30 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
+       LSM_HOOK_INIT(getprocattr, apparmor_getprocattr),
+       LSM_HOOK_INIT(setprocattr, apparmor_setprocattr),
++      LSM_HOOK_INIT(sk_alloc_security, apparmor_sk_alloc_security),
++      LSM_HOOK_INIT(sk_free_security, apparmor_sk_free_security),
++      LSM_HOOK_INIT(sk_clone_security, apparmor_sk_clone_security),
++
++      LSM_HOOK_INIT(socket_create, apparmor_socket_create),
++      LSM_HOOK_INIT(socket_post_create, apparmor_socket_post_create),
++      LSM_HOOK_INIT(socket_bind, apparmor_socket_bind),
++      LSM_HOOK_INIT(socket_connect, apparmor_socket_connect),
++      LSM_HOOK_INIT(socket_listen, apparmor_socket_listen),
++      LSM_HOOK_INIT(socket_accept, apparmor_socket_accept),
++      LSM_HOOK_INIT(socket_sendmsg, apparmor_socket_sendmsg),
++      LSM_HOOK_INIT(socket_recvmsg, apparmor_socket_recvmsg),
++      LSM_HOOK_INIT(socket_getsockname, apparmor_socket_getsockname),
++      LSM_HOOK_INIT(socket_getpeername, apparmor_socket_getpeername),
++      LSM_HOOK_INIT(socket_getsockopt, apparmor_socket_getsockopt),
++      LSM_HOOK_INIT(socket_setsockopt, apparmor_socket_setsockopt),
++      LSM_HOOK_INIT(socket_shutdown, apparmor_socket_shutdown),
++      LSM_HOOK_INIT(socket_sock_rcv_skb, apparmor_socket_sock_rcv_skb),
++      LSM_HOOK_INIT(socket_getpeersec_stream,
++                    apparmor_socket_getpeersec_stream),
++      LSM_HOOK_INIT(socket_getpeersec_dgram,
++                    apparmor_socket_getpeersec_dgram),
++      LSM_HOOK_INIT(sock_graft, apparmor_sock_graft),
++
+       LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank),
+       LSM_HOOK_INIT(cred_free, apparmor_cred_free),
+       LSM_HOOK_INIT(cred_prepare, apparmor_cred_prepare),
+diff --git a/security/apparmor/net.c b/security/apparmor/net.c
+new file mode 100644
+index 000000000000..33d54435f8d6
+--- /dev/null
++++ b/security/apparmor/net.c
+@@ -0,0 +1,184 @@
++/*
++ * AppArmor security module
++ *
++ * This file contains AppArmor network mediation
++ *
++ * Copyright (C) 1998-2008 Novell/SUSE
++ * Copyright 2009-2017 Canonical Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation, version 2 of the
++ * License.
++ */
++
++#include "include/apparmor.h"
++#include "include/audit.h"
++#include "include/context.h"
++#include "include/label.h"
++#include "include/net.h"
++#include "include/policy.h"
++
++#include "net_names.h"
++
++
++struct aa_sfs_entry aa_sfs_entry_network[] = {
++      AA_SFS_FILE_STRING("af_mask",   AA_SFS_AF_MASK),
++      { }
++};
++
++static const char * const net_mask_names[] = {
++      "unknown",
++      "send",
++      "receive",
++      "unknown",
++
++      "create",
++      "shutdown",
++      "connect",
++      "unknown",
++
++      "setattr",
++      "getattr",
++      "setcred",
++      "getcred",
++
++      "chmod",
++      "chown",
++      "chgrp",
++      "lock",
++
++      "mmap",
++      "mprot",
++      "unknown",
++      "unknown",
++
++      "accept",
++      "bind",
++      "listen",
++      "unknown",
++
++      "setopt",
++      "getopt",
++      "unknown",
++      "unknown",
++
++      "unknown",
++      "unknown",
++      "unknown",
++      "unknown",
++};
++
++
++/* audit callback for net specific fields */
++void audit_net_cb(struct audit_buffer *ab, void *va)
++{
++      struct common_audit_data *sa = va;
++
++      audit_log_format(ab, " family=");
++      if (address_family_names[sa->u.net->family])
++              audit_log_string(ab, address_family_names[sa->u.net->family]);
++      else
++              audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family);
++      audit_log_format(ab, " sock_type=");
++      if (sock_type_names[aad(sa)->net.type])
++              audit_log_string(ab, sock_type_names[aad(sa)->net.type]);
++      else
++              audit_log_format(ab, "\"unknown(%d)\"", aad(sa)->net.type);
++      audit_log_format(ab, " protocol=%d", aad(sa)->net.protocol);
++
++      if (aad(sa)->request & NET_PERMS_MASK) {
++              audit_log_format(ab, " requested_mask=");
++              aa_audit_perm_mask(ab, aad(sa)->request, NULL, 0,
++                                 net_mask_names, NET_PERMS_MASK);
++
++              if (aad(sa)->denied & NET_PERMS_MASK) {
++                      audit_log_format(ab, " denied_mask=");
++                      aa_audit_perm_mask(ab, aad(sa)->denied, NULL, 0,
++                                         net_mask_names, NET_PERMS_MASK);
++              }
++      }
++      if (aad(sa)->peer) {
++              audit_log_format(ab, " peer=");
++              aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
++                              FLAGS_NONE, GFP_ATOMIC);
++      }
++}
++
++
++/* Generic af perm */
++int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa,
++                     u32 request, u16 family, int type)
++{
++      struct aa_perms perms = { };
++
++      AA_BUG(family >= AF_MAX);
++      AA_BUG(type < 0 || type >= SOCK_MAX);
++
++      if (profile_unconfined(profile))
++              return 0;
++
++      perms.allow = (profile->net.allow[family] & (1 << type)) ?
++              ALL_PERMS_MASK : 0;
++      perms.audit = (profile->net.audit[family] & (1 << type)) ?
++              ALL_PERMS_MASK : 0;
++      perms.quiet = (profile->net.quiet[family] & (1 << type)) ?
++              ALL_PERMS_MASK : 0;
++      aa_apply_modes_to_perms(profile, &perms);
++
++      return aa_check_perms(profile, &perms, request, sa, audit_net_cb);
++}
++
++int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family,
++             int type, int protocol)
++{
++      struct aa_profile *profile;
++      DEFINE_AUDIT_NET(sa, op, NULL, family, type, protocol);
++
++      return fn_for_each_confined(label, profile,
++                      aa_profile_af_perm(profile, &sa, request, family,
++                                         type));
++}
++
++static int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request,
++                          struct sock *sk)
++{
++      struct aa_profile *profile;
++      DEFINE_AUDIT_SK(sa, op, sk);
++
++      AA_BUG(!label);
++      AA_BUG(!sk);
++
++      if (unconfined(label))
++              return 0;
++
++      return fn_for_each_confined(label, profile,
++                      aa_profile_af_sk_perm(profile, &sa, request, sk));
++}
++
++int aa_sk_perm(const char *op, u32 request, struct sock *sk)
++{
++      struct aa_label *label;
++      int error;
++
++      AA_BUG(!sk);
++      AA_BUG(in_interrupt());
++
++      /* TODO: switch to begin_current_label ???? */
++      label = begin_current_label_crit_section();
++      error = aa_label_sk_perm(label, op, request, sk);
++      end_current_label_crit_section(label);
++
++      return error;
++}
++
++
++int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request,
++                    struct socket *sock)
++{
++      AA_BUG(!label);
++      AA_BUG(!sock);
++      AA_BUG(!sock->sk);
++
++      return aa_label_sk_perm(label, op, request, sock->sk);
++}
+diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
+index 4ede87c30f8b..5a2aec358322 100644
+--- a/security/apparmor/policy_unpack.c
++++ b/security/apparmor/policy_unpack.c
+@@ -275,6 +275,19 @@ static bool unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name)
+       return 0;
+ }
++static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name)
++{
++      if (unpack_nameX(e, AA_U16, name)) {
++              if (!inbounds(e, sizeof(u16)))
++                      return 0;
++              if (data)
++                      *data = le16_to_cpu(get_unaligned((__le16 *) e->pos));
++              e->pos += sizeof(u16);
++              return 1;
++      }
++      return 0;
++}
++
+ static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
+ {
+       if (unpack_nameX(e, AA_U32, name)) {
+@@ -584,7 +597,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
+       struct aa_profile *profile = NULL;
+       const char *tmpname, *tmpns = NULL, *name = NULL;
+       const char *info = "failed to unpack profile";
+-      size_t ns_len;
++      size_t size = 0, ns_len;
+       struct rhashtable_params params = { 0 };
+       char *key = NULL;
+       struct aa_data *data;
+@@ -717,6 +730,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
+               goto fail;
+       }
++      size = unpack_array(e, "net_allowed_af");
++      if (size) {
++
++              for (i = 0; i < size; i++) {
++                      /* discard extraneous rules that this kernel will
++                       * never request
++                       */
++                      if (i >= AF_MAX) {
++                              u16 tmp;
++
++                              if (!unpack_u16(e, &tmp, NULL) ||
++                                  !unpack_u16(e, &tmp, NULL) ||
++                                  !unpack_u16(e, &tmp, NULL))
++                                      goto fail;
++                              continue;
++                      }
++                      if (!unpack_u16(e, &profile->net.allow[i], NULL))
++                              goto fail;
++                      if (!unpack_u16(e, &profile->net.audit[i], NULL))
++                              goto fail;
++                      if (!unpack_u16(e, &profile->net.quiet[i], NULL))
++                              goto fail;
++              }
++              if (!unpack_nameX(e, AA_ARRAYEND, NULL))
++                      goto fail;
++      }
++      if (VERSION_LT(e->version, v7)) {
++              /* pre v7 policy always allowed these */
++              profile->net.allow[AF_UNIX] = 0xffff;
++              profile->net.allow[AF_NETLINK] = 0xffff;
++      }
++
+       if (unpack_nameX(e, AA_STRUCT, "policydb")) {
+               /* generic policy dfa - optional and may be NULL */
+               info = "failed to unpack policydb";
+-- 
+2.11.0
+
diff --git a/0013-apparmor-move-new_null_profile-to-after-profile-look.patch b/0013-apparmor-move-new_null_profile-to-after-profile-look.patch
new file mode 100644 (file)
index 0000000..f1337f3
--- /dev/null
@@ -0,0 +1,194 @@
+From 50d30adbef98a0b6cc531a9413d05f564eb633ee Mon Sep 17 00:00:00 2001
+From: John Johansen <john.johansen@canonical.com>
+Date: Wed, 16 Aug 2017 08:59:57 -0700
+Subject: [PATCH 13/17] apparmor: move new_null_profile to after profile lookup
+ fns()
+
+new_null_profile will need to use some of the profile lookup fns()
+so move instead of doing forward fn declarations.
+
+Signed-off-by: John Johansen <john.johansen@canonical.com>
+(cherry picked from commit cf1e50dfc6f627bc2989b57076b129c330fb3f0a)
+---
+ security/apparmor/policy.c | 158 ++++++++++++++++++++++-----------------------
+ 1 file changed, 79 insertions(+), 79 deletions(-)
+
+diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
+index 244ea4a4a8f0..a81a384a63b1 100644
+--- a/security/apparmor/policy.c
++++ b/security/apparmor/policy.c
+@@ -289,85 +289,6 @@ struct aa_profile *aa_alloc_profile(const char *hname, struct aa_proxy *proxy,
+       return NULL;
+ }
+-/**
+- * aa_new_null_profile - create or find a null-X learning profile
+- * @parent: profile that caused this profile to be created (NOT NULL)
+- * @hat: true if the null- learning profile is a hat
+- * @base: name to base the null profile off of
+- * @gfp: type of allocation
+- *
+- * Find/Create a null- complain mode profile used in learning mode.  The
+- * name of the profile is unique and follows the format of parent//null-XXX.
+- * where XXX is based on the @name or if that fails or is not supplied
+- * a unique number
+- *
+- * null profiles are added to the profile list but the list does not
+- * hold a count on them so that they are automatically released when
+- * not in use.
+- *
+- * Returns: new refcounted profile else NULL on failure
+- */
+-struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat,
+-                                     const char *base, gfp_t gfp)
+-{
+-      struct aa_profile *profile;
+-      char *name;
+-
+-      AA_BUG(!parent);
+-
+-      if (base) {
+-              name = kmalloc(strlen(parent->base.hname) + 8 + strlen(base),
+-                             gfp);
+-              if (name) {
+-                      sprintf(name, "%s//null-%s", parent->base.hname, base);
+-                      goto name;
+-              }
+-              /* fall through to try shorter uniq */
+-      }
+-
+-      name = kmalloc(strlen(parent->base.hname) + 2 + 7 + 8, gfp);
+-      if (!name)
+-              return NULL;
+-      sprintf(name, "%s//null-%x", parent->base.hname,
+-              atomic_inc_return(&parent->ns->uniq_null));
+-
+-name:
+-      /* lookup to see if this is a dup creation */
+-      profile = aa_find_child(parent, basename(name));
+-      if (profile)
+-              goto out;
+-
+-      profile = aa_alloc_profile(name, NULL, gfp);
+-      if (!profile)
+-              goto fail;
+-
+-      profile->mode = APPARMOR_COMPLAIN;
+-      profile->label.flags |= FLAG_NULL;
+-      if (hat)
+-              profile->label.flags |= FLAG_HAT;
+-      profile->path_flags = parent->path_flags;
+-
+-      /* released on free_profile */
+-      rcu_assign_pointer(profile->parent, aa_get_profile(parent));
+-      profile->ns = aa_get_ns(parent->ns);
+-      profile->file.dfa = aa_get_dfa(nulldfa);
+-      profile->policy.dfa = aa_get_dfa(nulldfa);
+-
+-      mutex_lock(&profile->ns->lock);
+-      __add_profile(&parent->base.profiles, profile);
+-      mutex_unlock(&profile->ns->lock);
+-
+-      /* refcount released by caller */
+-out:
+-      kfree(name);
+-
+-      return profile;
+-
+-fail:
+-      aa_free_profile(profile);
+-      return NULL;
+-}
+-
+ /* TODO: profile accounting - setup in remove */
+ /**
+@@ -559,6 +480,85 @@ struct aa_profile *aa_fqlookupn_profile(struct aa_label *base,
+ }
+ /**
++ * aa_new_null_profile - create or find a null-X learning profile
++ * @parent: profile that caused this profile to be created (NOT NULL)
++ * @hat: true if the null- learning profile is a hat
++ * @base: name to base the null profile off of
++ * @gfp: type of allocation
++ *
++ * Find/Create a null- complain mode profile used in learning mode.  The
++ * name of the profile is unique and follows the format of parent//null-XXX.
++ * where XXX is based on the @name or if that fails or is not supplied
++ * a unique number
++ *
++ * null profiles are added to the profile list but the list does not
++ * hold a count on them so that they are automatically released when
++ * not in use.
++ *
++ * Returns: new refcounted profile else NULL on failure
++ */
++struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat,
++                                     const char *base, gfp_t gfp)
++{
++      struct aa_profile *profile;
++      char *name;
++
++      AA_BUG(!parent);
++
++      if (base) {
++              name = kmalloc(strlen(parent->base.hname) + 8 + strlen(base),
++                             gfp);
++              if (name) {
++                      sprintf(name, "%s//null-%s", parent->base.hname, base);
++                      goto name;
++              }
++              /* fall through to try shorter uniq */
++      }
++
++      name = kmalloc(strlen(parent->base.hname) + 2 + 7 + 8, gfp);
++      if (!name)
++              return NULL;
++      sprintf(name, "%s//null-%x", parent->base.hname,
++              atomic_inc_return(&parent->ns->uniq_null));
++
++name:
++      /* lookup to see if this is a dup creation */
++      profile = aa_find_child(parent, basename(name));
++      if (profile)
++              goto out;
++
++      profile = aa_alloc_profile(name, NULL, gfp);
++      if (!profile)
++              goto fail;
++
++      profile->mode = APPARMOR_COMPLAIN;
++      profile->label.flags |= FLAG_NULL;
++      if (hat)
++              profile->label.flags |= FLAG_HAT;
++      profile->path_flags = parent->path_flags;
++
++      /* released on free_profile */
++      rcu_assign_pointer(profile->parent, aa_get_profile(parent));
++      profile->ns = aa_get_ns(parent->ns);
++      profile->file.dfa = aa_get_dfa(nulldfa);
++      profile->policy.dfa = aa_get_dfa(nulldfa);
++
++      mutex_lock(&profile->ns->lock);
++      __add_profile(&parent->base.profiles, profile);
++      mutex_unlock(&profile->ns->lock);
++
++      /* refcount released by caller */
++out:
++      kfree(name);
++
++      return profile;
++
++fail:
++      aa_free_profile(profile);
++      return NULL;
++}
++
++/**
+  * replacement_allowed - test to see if replacement is allowed
+  * @profile: profile to test if it can be replaced  (MAYBE NULL)
+  * @noreplace: true if replacement shouldn't be allowed but addition is okay
+-- 
+2.11.0
+
diff --git a/0014-apparmor-fix-race-condition-in-null-profile-creation.patch b/0014-apparmor-fix-race-condition-in-null-profile-creation.patch
new file mode 100644 (file)
index 0000000..ae57b4b
--- /dev/null
@@ -0,0 +1,60 @@
+From ab3b869791b6122c7be7e68ca4c08e2c2e8815ac Mon Sep 17 00:00:00 2001
+From: John Johansen <john.johansen@canonical.com>
+Date: Wed, 16 Aug 2017 05:40:49 -0700
+Subject: [PATCH 14/17] apparmor: fix race condition in null profile creation
+
+There is a race when null- profile is being created between the
+initial lookup/creation of the profile and lock/addition of the
+profile. This could result in multiple version of a profile being
+added to the list which need to be removed/replaced.
+
+Since these are learning profile their is no affect on mediation.
+
+Signed-off-by: John Johansen <john.johansen@canonical.com>
+(cherry picked from commit 3aa3de2a4fb8f33ec62b00998bc6b6c6850d41b1)
+---
+ security/apparmor/policy.c | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
+index a81a384a63b1..4243b0c3f0e4 100644
+--- a/security/apparmor/policy.c
++++ b/security/apparmor/policy.c
+@@ -500,7 +500,8 @@ struct aa_profile *aa_fqlookupn_profile(struct aa_label *base,
+ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat,
+                                      const char *base, gfp_t gfp)
+ {
+-      struct aa_profile *profile;
++      struct aa_profile *p, *profile;
++      const char *bname;
+       char *name;
+       AA_BUG(!parent);
+@@ -523,7 +524,8 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat,
+ name:
+       /* lookup to see if this is a dup creation */
+-      profile = aa_find_child(parent, basename(name));
++      bname = basename(name);
++      profile = aa_find_child(parent, bname);
+       if (profile)
+               goto out;
+@@ -544,7 +546,13 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat,
+       profile->policy.dfa = aa_get_dfa(nulldfa);
+       mutex_lock(&profile->ns->lock);
+-      __add_profile(&parent->base.profiles, profile);
++      p = __find_child(&parent->base.profiles, bname);
++      if (p) {
++              aa_free_profile(profile);
++              profile = aa_get_profile(p);
++      } else {
++              __add_profile(&parent->base.profiles, profile);
++      }
+       mutex_unlock(&profile->ns->lock);
+       /* refcount released by caller */
+-- 
+2.11.0
+
diff --git a/0015-apparmor-ensure-unconfined-profiles-have-dfas-initia.patch b/0015-apparmor-ensure-unconfined-profiles-have-dfas-initia.patch
new file mode 100644 (file)
index 0000000..1ceb990
--- /dev/null
@@ -0,0 +1,36 @@
+From 7f2cdd6453518ff76c3855255c91306a2b928c9a Mon Sep 17 00:00:00 2001
+From: John Johansen <john.johansen@canonical.com>
+Date: Wed, 16 Aug 2017 05:48:06 -0700
+Subject: [PATCH 15/17] apparmor: ensure unconfined profiles have dfas
+ initialized
+
+Generally unconfined has early bailout tests and does not need the
+dfas initialized, however if an early bailout test is ever missed
+it will result in an oops.
+
+Be defensive and initialize the unconfined profile to have null dfas
+(no permission) so if an early bailout test is missed we fail
+closed (no perms granted) instead of oopsing.
+
+Signed-off-by: John Johansen <john.johansen@canonical.com>
+(cherry picked from commit 034ad2d248927722bdcd1aedb62634cdc2049113)
+---
+ security/apparmor/policy_ns.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c
+index 351d3bab3a3d..62a3589c62ab 100644
+--- a/security/apparmor/policy_ns.c
++++ b/security/apparmor/policy_ns.c
+@@ -112,6 +112,8 @@ static struct aa_ns *alloc_ns(const char *prefix, const char *name)
+       ns->unconfined->label.flags |= FLAG_IX_ON_NAME_ERROR |
+               FLAG_IMMUTIBLE | FLAG_NS_COUNT | FLAG_UNCONFINED;
+       ns->unconfined->mode = APPARMOR_UNCONFINED;
++      ns->unconfined->file.dfa = aa_get_dfa(nulldfa);
++      ns->unconfined->policy.dfa = aa_get_dfa(nulldfa);
+       /* ns and ns->unconfined share ns->unconfined refcount */
+       ns->unconfined->ns = ns;
+-- 
+2.11.0
+
diff --git a/0016-apparmor-fix-incorrect-type-assignment-when-freeing-.patch b/0016-apparmor-fix-incorrect-type-assignment-when-freeing-.patch
new file mode 100644 (file)
index 0000000..9ff09f8
--- /dev/null
@@ -0,0 +1,39 @@
+From 8daf877473653c06a28c86bf72d63ce7e5c1d542 Mon Sep 17 00:00:00 2001
+From: John Johansen <john.johansen@canonical.com>
+Date: Wed, 16 Aug 2017 09:33:48 -0700
+Subject: [PATCH 16/17] apparmor: fix incorrect type assignment when freeing
+ proxies
+
+sparse reports
+
+poisoning the proxy->label before freeing the struct is resulting in
+a sparse build warning.
+../security/apparmor/label.c:52:30: warning: incorrect type in assignment (different address spaces)
+../security/apparmor/label.c:52:30:    expected struct aa_label [noderef] <asn:4>*label
+../security/apparmor/label.c:52:30:    got struct aa_label *<noident>
+
+fix with RCU_INIT_POINTER as this is one of those cases where
+rcu_assign_pointer() is not needed.
+
+Signed-off-by: John Johansen <john.johansen@canonical.com>
+(cherry picked from commit 76e22e212a850bbd16cf49f9c586d4635507e0b5)
+---
+ security/apparmor/label.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/security/apparmor/label.c b/security/apparmor/label.c
+index 52b4ef14840d..c5b99b954580 100644
+--- a/security/apparmor/label.c
++++ b/security/apparmor/label.c
+@@ -49,7 +49,7 @@ static void free_proxy(struct aa_proxy *proxy)
+               /* p->label will not updated any more as p is dead */
+               aa_put_label(rcu_dereference_protected(proxy->label, true));
+               memset(proxy, 0, sizeof(*proxy));
+-              proxy->label = (struct aa_label *) PROXY_POISON;
++              RCU_INIT_POINTER(proxy->label, (struct aa_label *)PROXY_POISON);
+               kfree(proxy);
+       }
+ }
+-- 
+2.11.0
+
diff --git a/0017-UBUNTU-SAUCE-apparmor-af_unix-mediation.patch b/0017-UBUNTU-SAUCE-apparmor-af_unix-mediation.patch
new file mode 100644 (file)
index 0000000..5a1b220
--- /dev/null
@@ -0,0 +1,1394 @@
+From a3b0cb6676a04cdad5cc357bc422d0398083b435 Mon Sep 17 00:00:00 2001
+From: John Johansen <john.johansen@canonical.com>
+Date: Tue, 18 Jul 2017 23:27:23 -0700
+Subject: [PATCH 17/17] UBUNTU: SAUCE: apparmor: af_unix mediation
+
+af_socket mediation did not make it into 4.14 so add remaining out
+of tree patch
+
+Signed-off-by: John Johansen <john.johansen@canonical.com>
+---
+ security/apparmor/Makefile          |   3 +-
+ security/apparmor/af_unix.c         | 651 ++++++++++++++++++++++++++++++++++++
+ security/apparmor/apparmorfs.c      |   6 +
+ security/apparmor/file.c            |   4 +-
+ security/apparmor/include/af_unix.h | 114 +++++++
+ security/apparmor/include/net.h     |  16 +-
+ security/apparmor/include/path.h    |   1 +
+ security/apparmor/include/policy.h  |   2 +-
+ security/apparmor/lsm.c             | 169 ++++++----
+ security/apparmor/net.c             | 174 +++++++++-
+ 10 files changed, 1072 insertions(+), 68 deletions(-)
+ create mode 100644 security/apparmor/af_unix.c
+ create mode 100644 security/apparmor/include/af_unix.h
+
+diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
+index dafdd387d42b..ef39226ff4aa 100644
+--- a/security/apparmor/Makefile
++++ b/security/apparmor/Makefile
+@@ -4,7 +4,8 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
+ apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
+               path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
+-              resource.o secid.o file.o policy_ns.o label.o mount.o net.o
++              resource.o secid.o file.o policy_ns.o label.o mount.o net.o \
++              af_unix.o
+ apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
+ clean-files := capability_names.h rlim_names.h net_names.h
+diff --git a/security/apparmor/af_unix.c b/security/apparmor/af_unix.c
+new file mode 100644
+index 000000000000..c6876db2dbde
+--- /dev/null
++++ b/security/apparmor/af_unix.c
+@@ -0,0 +1,651 @@
++/*
++ * AppArmor security module
++ *
++ * This file contains AppArmor af_unix fine grained mediation
++ *
++ * Copyright 2014 Canonical Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation, version 2 of the
++ * License.
++ */
++
++#include <net/tcp_states.h>
++
++#include "include/af_unix.h"
++#include "include/apparmor.h"
++#include "include/context.h"
++#include "include/file.h"
++#include "include/label.h"
++#include "include/path.h"
++#include "include/policy.h"
++
++static inline struct sock *aa_sock(struct unix_sock *u)
++{
++      return &u->sk;
++}
++
++static inline int unix_fs_perm(const char *op, u32 mask, struct aa_label *label,
++                             struct unix_sock *u, int flags)
++{
++      AA_BUG(!label);
++      AA_BUG(!u);
++      AA_BUG(!UNIX_FS(aa_sock(u)));
++
++      if (unconfined(label) || !LABEL_MEDIATES(label, AA_CLASS_FILE))
++              return 0;
++
++      mask &= NET_FS_PERMS;
++      if (!u->path.dentry) {
++              struct path_cond cond = { };
++              struct aa_perms perms = { };
++              struct aa_profile *profile;
++
++              /* socket path has been cleared because it is being shutdown
++               * can only fall back to original sun_path request
++               */
++              struct aa_sk_ctx *ctx = SK_CTX(&u->sk);
++              if (ctx->path.dentry)
++                      return aa_path_perm(op, label, &ctx->path, flags, mask,
++                                          &cond);
++              return fn_for_each_confined(label, profile,
++                      ((flags | profile->path_flags) & PATH_MEDIATE_DELETED) ?
++                              __aa_path_perm(op, profile,
++                                             u->addr->name->sun_path, mask,
++                                             &cond, flags, &perms) :
++                              aa_audit_file(profile, &nullperms, op, mask,
++                                            u->addr->name->sun_path, NULL,
++                                            NULL, cond.uid,
++                                            "Failed name lookup - "
++                                            "deleted entry", -EACCES));
++      } else {
++              /* the sunpath may not be valid for this ns so use the path */
++              struct path_cond cond = { u->path.dentry->d_inode->i_uid,
++                                        u->path.dentry->d_inode->i_mode
++              };
++
++              return aa_path_perm(op, label, &u->path, flags, mask, &cond);
++      }
++
++      return 0;
++}
++
++/* passing in state returned by PROFILE_MEDIATES_AF */
++static unsigned int match_to_prot(struct aa_profile *profile,
++                                unsigned int state, int type, int protocol,
++                                const char **info)
++{
++      __be16 buffer[2];
++      buffer[0] = cpu_to_be16(type);
++      buffer[1] = cpu_to_be16(protocol);
++      state = aa_dfa_match_len(profile->policy.dfa, state, (char *) &buffer,
++                               4);
++      if (!state)
++              *info = "failed type and protocol match";
++      return state;
++}
++
++static unsigned int match_addr(struct aa_profile *profile, unsigned int state,
++                             struct sockaddr_un *addr, int addrlen)
++{
++      if (addr)
++              /* include leading \0 */
++              state = aa_dfa_match_len(profile->policy.dfa, state,
++                                       addr->sun_path,
++                                       unix_addr_len(addrlen));
++      else
++              /* anonymous end point */
++              state = aa_dfa_match_len(profile->policy.dfa, state, "\x01",
++                                       1);
++      /* todo change to out of band */
++      state = aa_dfa_null_transition(profile->policy.dfa, state);
++      return state;
++}
++
++static unsigned int match_to_local(struct aa_profile *profile,
++                                 unsigned int state, int type, int protocol,
++                                 struct sockaddr_un *addr, int addrlen,
++                                 const char **info)
++{
++      state = match_to_prot(profile, state, type, protocol, info);
++      if (state) {
++              state = match_addr(profile, state, addr, addrlen);
++              if (state) {
++                      /* todo: local label matching */
++                      state = aa_dfa_null_transition(profile->policy.dfa,
++                                                     state);
++                      if (!state)
++                              *info = "failed local label match";
++              } else
++                      *info = "failed local address match";
++      }
++
++      return state;
++}
++
++static unsigned int match_to_sk(struct aa_profile *profile,
++                              unsigned int state, struct unix_sock *u,
++                              const char **info)
++{
++      struct sockaddr_un *addr = NULL;
++      int addrlen = 0;
++
++      if (u->addr) {
++              addr = u->addr->name;
++              addrlen = u->addr->len;
++      }
++
++      return match_to_local(profile, state, u->sk.sk_type, u->sk.sk_protocol,
++                            addr, addrlen, info);
++}
++
++#define CMD_ADDR      1
++#define CMD_LISTEN    2
++#define CMD_OPT               4
++
++static inline unsigned int match_to_cmd(struct aa_profile *profile,
++                                      unsigned int state, struct unix_sock *u,
++                                      char cmd, const char **info)
++{
++      state = match_to_sk(profile, state, u, info);
++      if (state) {
++              state = aa_dfa_match_len(profile->policy.dfa, state, &cmd, 1);
++              if (!state)
++                      *info = "failed cmd selection match";
++      }
++
++      return state;
++}
++
++static inline unsigned int match_to_peer(struct aa_profile *profile,
++                                       unsigned int state,
++                                       struct unix_sock *u,
++                                       struct sockaddr_un *peer_addr,
++                                       int peer_addrlen,
++                                       const char **info)
++{
++      state = match_to_cmd(profile, state, u, CMD_ADDR, info);
++      if (state) {
++              state = match_addr(profile, state, peer_addr, peer_addrlen);
++              if (!state)
++                      *info = "failed peer address match";
++      }
++      return state;
++}
++
++static int do_perms(struct aa_profile *profile, unsigned int state, u32 request,
++                  struct common_audit_data *sa)
++{
++      struct aa_perms perms;
++
++      AA_BUG(!profile);
++
++      aa_compute_perms(profile->policy.dfa, state, &perms);
++      aa_apply_modes_to_perms(profile, &perms);
++      return aa_check_perms(profile, &perms, request, sa,
++                            audit_net_cb);
++}
++
++static int match_label(struct aa_profile *profile, struct aa_profile *peer,
++                            unsigned int state, u32 request,
++                            struct common_audit_data *sa)
++{
++      AA_BUG(!profile);
++      AA_BUG(!peer);
++
++      aad(sa)->peer = &peer->label;
++
++      if (state) {
++              state = aa_dfa_match(profile->policy.dfa, state,
++                                   peer->base.hname);
++              if (!state)
++                      aad(sa)->info = "failed peer label match";
++      }
++      return do_perms(profile, state, request, sa);
++}
++
++
++/* unix sock creation comes before we know if the socket will be an fs
++ * socket
++ * v6 - semantics are handled by mapping in profile load
++ * v7 - semantics require sock create for tasks creating an fs socket.
++ */
++static int profile_create_perm(struct aa_profile *profile, int family,
++                             int type, int protocol)
++{
++      unsigned int state;
++      DEFINE_AUDIT_NET(sa, OP_CREATE, NULL, family, type, protocol);
++
++      AA_BUG(!profile);
++      AA_BUG(profile_unconfined(profile));
++
++      if ((state = PROFILE_MEDIATES_AF(profile, AF_UNIX))) {
++              state = match_to_prot(profile, state, type, protocol,
++                                    &aad(&sa)->info);
++              return do_perms(profile, state, AA_MAY_CREATE, &sa);
++      }
++
++      return aa_profile_af_perm(profile, &sa, AA_MAY_CREATE, family, type);
++}
++
++int aa_unix_create_perm(struct aa_label *label, int family, int type,
++                      int protocol)
++{
++      struct aa_profile *profile;
++
++      if (unconfined(label))
++              return 0;
++
++      return fn_for_each_confined(label, profile,
++                      profile_create_perm(profile, family, type, protocol));
++}
++
++
++static inline int profile_sk_perm(struct aa_profile *profile, const char *op,
++                                u32 request, struct sock *sk)
++{
++      unsigned int state;
++      DEFINE_AUDIT_SK(sa, op, sk);
++
++      AA_BUG(!profile);
++      AA_BUG(!sk);
++      AA_BUG(UNIX_FS(sk));
++      AA_BUG(profile_unconfined(profile));
++
++      state = PROFILE_MEDIATES_AF(profile, AF_UNIX);
++      if (state) {
++              state = match_to_sk(profile, state, unix_sk(sk),
++                                  &aad(&sa)->info);
++              return do_perms(profile, state, request, &sa);
++      }
++
++      return aa_profile_af_sk_perm(profile, &sa, request, sk);
++}
++
++int aa_unix_label_sk_perm(struct aa_label *label, const char *op, u32 request,
++                        struct sock *sk)
++{
++      struct aa_profile *profile;
++
++      return fn_for_each_confined(label, profile,
++                      profile_sk_perm(profile, op, request, sk));
++}
++
++static int unix_label_sock_perm(struct aa_label *label, const char *op, u32 request,
++                              struct socket *sock)
++{
++      if (unconfined(label))
++              return 0;
++      if (UNIX_FS(sock->sk))
++              return unix_fs_perm(op, request, label, unix_sk(sock->sk), 0);
++
++      return aa_unix_label_sk_perm(label, op, request, sock->sk);
++}
++
++/* revaliation, get/set attr */
++int aa_unix_sock_perm(const char *op, u32 request, struct socket *sock)
++{
++      struct aa_label *label;
++      int error;
++
++      label = begin_current_label_crit_section();
++      error = unix_label_sock_perm(label, op, request, sock);
++      end_current_label_crit_section(label);
++
++      return error;
++}
++
++static int profile_bind_perm(struct aa_profile *profile, struct sock *sk,
++                           struct sockaddr *addr, int addrlen)
++{
++      unsigned int state;
++      DEFINE_AUDIT_SK(sa, OP_BIND, sk);
++
++      AA_BUG(!profile);
++      AA_BUG(!sk);
++      AA_BUG(addr->sa_family != AF_UNIX);
++      AA_BUG(profile_unconfined(profile));
++      AA_BUG(unix_addr_fs(addr, addrlen));
++
++      state = PROFILE_MEDIATES_AF(profile, AF_UNIX);
++      if (state) {
++              /* bind for abstract socket */
++              aad(&sa)->net.addr = unix_addr(addr);
++              aad(&sa)->net.addrlen = addrlen;
++
++              state = match_to_local(profile, state,
++                                     sk->sk_type, sk->sk_protocol,
++                                     unix_addr(addr), addrlen,
++                                     &aad(&sa)->info);
++              return do_perms(profile, state, AA_MAY_BIND, &sa);
++      }
++
++      return aa_profile_af_sk_perm(profile, &sa, AA_MAY_BIND, sk);
++}
++
++int aa_unix_bind_perm(struct socket *sock, struct sockaddr *address,
++                    int addrlen)
++{
++      struct aa_profile *profile;
++      struct aa_label *label;
++      int error = 0;
++
++       label = begin_current_label_crit_section();
++       /* fs bind is handled by mknod */
++      if (!(unconfined(label) || unix_addr_fs(address, addrlen)))
++              error = fn_for_each_confined(label, profile,
++                              profile_bind_perm(profile, sock->sk, address,
++                                                addrlen));
++      end_current_label_crit_section(label);
++
++      return error;
++}
++
++int aa_unix_connect_perm(struct socket *sock, struct sockaddr *address,
++                       int addrlen)
++{
++      /* unix connections are covered by the
++       * - unix_stream_connect (stream) and unix_may_send hooks (dgram)
++       * - fs connect is handled by open
++       */
++      return 0;
++}
++
++static int profile_listen_perm(struct aa_profile *profile, struct sock *sk,
++                             int backlog)
++{
++      unsigned int state;
++      DEFINE_AUDIT_SK(sa, OP_LISTEN, sk);
++
++      AA_BUG(!profile);
++      AA_BUG(!sk);
++      AA_BUG(UNIX_FS(sk));
++      AA_BUG(profile_unconfined(profile));
++
++      state = PROFILE_MEDIATES_AF(profile, AF_UNIX);
++      if (state) {
++              __be16 b = cpu_to_be16(backlog);
++
++              state = match_to_cmd(profile, state, unix_sk(sk), CMD_LISTEN,
++                                   &aad(&sa)->info);
++              if (state) {
++                      state = aa_dfa_match_len(profile->policy.dfa, state,
++                                               (char *) &b, 2);
++                      if (!state)
++                              aad(&sa)->info = "failed listen backlog match";
++              }
++              return do_perms(profile, state, AA_MAY_LISTEN, &sa);
++      }
++
++      return aa_profile_af_sk_perm(profile, &sa, AA_MAY_LISTEN, sk);
++}
++
++int aa_unix_listen_perm(struct socket *sock, int backlog)
++{
++      struct aa_profile *profile;
++      struct aa_label *label;
++      int error = 0;
++
++      label = begin_current_label_crit_section();
++      if (!(unconfined(label) || UNIX_FS(sock->sk)))
++              error = fn_for_each_confined(label, profile,
++                              profile_listen_perm(profile, sock->sk,
++                                                  backlog));
++      end_current_label_crit_section(label);
++
++      return error;
++}
++
++
++static inline int profile_accept_perm(struct aa_profile *profile,
++                                    struct sock *sk,
++                                    struct sock *newsk)
++{
++      unsigned int state;
++      DEFINE_AUDIT_SK(sa, OP_ACCEPT, sk);
++
++      AA_BUG(!profile);
++      AA_BUG(!sk);
++      AA_BUG(UNIX_FS(sk));
++      AA_BUG(profile_unconfined(profile));
++
++      state = PROFILE_MEDIATES_AF(profile, AF_UNIX);
++      if (state) {
++              state = match_to_sk(profile, state, unix_sk(sk),
++                                  &aad(&sa)->info);
++              return do_perms(profile, state, AA_MAY_ACCEPT, &sa);
++      }
++
++      return aa_profile_af_sk_perm(profile, &sa, AA_MAY_ACCEPT, sk);
++}
++
++/* ability of sock to connect, not peer address binding */
++int aa_unix_accept_perm(struct socket *sock, struct socket *newsock)
++{
++      struct aa_profile *profile;
++      struct aa_label *label;
++      int error = 0;
++
++      label = begin_current_label_crit_section();
++      if (!(unconfined(label) || UNIX_FS(sock->sk)))
++              error = fn_for_each_confined(label, profile,
++                              profile_accept_perm(profile, sock->sk,
++                                                  newsock->sk));
++      end_current_label_crit_section(label);
++
++      return error;
++}
++
++
++/* dgram handled by unix_may_sendmsg, right to send on stream done at connect
++ * could do per msg unix_stream here
++ */
++/* sendmsg, recvmsg */
++int aa_unix_msg_perm(const char *op, u32 request, struct socket *sock,
++                   struct msghdr *msg, int size)
++{
++      return 0;
++}
++
++
++static int profile_opt_perm(struct aa_profile *profile, const char *op, u32 request,
++                          struct sock *sk, int level, int optname)
++{
++      unsigned int state;
++      DEFINE_AUDIT_SK(sa, op, sk);
++
++      AA_BUG(!profile);
++      AA_BUG(!sk);
++      AA_BUG(UNIX_FS(sk));
++      AA_BUG(profile_unconfined(profile));
++
++      state = PROFILE_MEDIATES_AF(profile, AF_UNIX);
++      if (state) {
++              __be16 b = cpu_to_be16(optname);
++
++              state = match_to_cmd(profile, state, unix_sk(sk), CMD_OPT,
++                                   &aad(&sa)->info);
++              if (state) {
++                      state = aa_dfa_match_len(profile->policy.dfa, state,
++                                               (char *) &b, 2);
++                      if (!state)
++                              aad(&sa)->info = "failed sockopt match";
++              }
++              return do_perms(profile, state, request, &sa);
++      }
++
++      return aa_profile_af_sk_perm(profile, &sa, request, sk);
++}
++
++int aa_unix_opt_perm(const char *op, u32 request, struct socket *sock, int level,
++                   int optname)
++{
++      struct aa_profile *profile;
++      struct aa_label *label;
++      int error = 0;
++
++      label = begin_current_label_crit_section();
++      if (!(unconfined(label) || UNIX_FS(sock->sk)))
++              error = fn_for_each_confined(label, profile,
++                              profile_opt_perm(profile, op, request,
++                                               sock->sk, level, optname));
++      end_current_label_crit_section(label);
++
++      return error;
++}
++
++/* null peer_label is allowed, in which case the peer_sk label is used */
++static int profile_peer_perm(struct aa_profile *profile, const char *op, u32 request,
++                           struct sock *sk, struct sock *peer_sk,
++                           struct aa_label *peer_label,
++                           struct common_audit_data *sa)
++{
++      unsigned int state;
++
++      AA_BUG(!profile);
++      AA_BUG(profile_unconfined(profile));
++      AA_BUG(!sk);
++      AA_BUG(!peer_sk);
++      AA_BUG(UNIX_FS(peer_sk));
++
++      state = PROFILE_MEDIATES_AF(profile, AF_UNIX);
++      if (state) {
++              struct aa_sk_ctx *peer_ctx = SK_CTX(peer_sk);
++              struct aa_profile *peerp;
++              struct sockaddr_un *addr = NULL;
++              int len = 0;
++              if (unix_sk(peer_sk)->addr) {
++                      addr = unix_sk(peer_sk)->addr->name;
++                      len = unix_sk(peer_sk)->addr->len;
++              }
++              state = match_to_peer(profile, state, unix_sk(sk),
++                                    addr, len, &aad(sa)->info);
++              if (!peer_label)
++                      peer_label = peer_ctx->label;
++              return fn_for_each_in_ns(peer_label, peerp,
++                                 match_label(profile, peerp, state, request,
++                                             sa));
++      }
++
++      return aa_profile_af_sk_perm(profile, sa, request, sk);
++}
++
++/**
++ *
++ * Requires: lock held on both @sk and @peer_sk
++ */
++int aa_unix_peer_perm(struct aa_label *label, const char *op, u32 request,
++                    struct sock *sk, struct sock *peer_sk,
++                    struct aa_label *peer_label)
++{
++      struct unix_sock *peeru = unix_sk(peer_sk);
++      struct unix_sock *u = unix_sk(sk);
++
++      AA_BUG(!label);
++      AA_BUG(!sk);
++      AA_BUG(!peer_sk);
++
++      if (UNIX_FS(aa_sock(peeru)))
++              return unix_fs_perm(op, request, label, peeru, 0);
++      else if (UNIX_FS(aa_sock(u)))
++              return unix_fs_perm(op, request, label, u, 0);
++      else {
++              struct aa_profile *profile;
++              DEFINE_AUDIT_SK(sa, op, sk);
++              aad(&sa)->net.peer_sk = peer_sk;
++
++              /* TODO: ns!!! */
++              if (!net_eq(sock_net(sk), sock_net(peer_sk))) {
++                      ;
++              }
++
++              if (unconfined(label))
++                      return 0;
++
++              return fn_for_each_confined(label, profile,
++                              profile_peer_perm(profile, op, request, sk,
++                                                peer_sk, peer_label, &sa));
++      }
++}
++
++
++/* from net/unix/af_unix.c */
++static void unix_state_double_lock(struct sock *sk1, struct sock *sk2)
++{
++      if (unlikely(sk1 == sk2) || !sk2) {
++              unix_state_lock(sk1);
++              return;
++      }
++      if (sk1 < sk2) {
++              unix_state_lock(sk1);
++              unix_state_lock_nested(sk2);
++      } else {
++              unix_state_lock(sk2);
++              unix_state_lock_nested(sk1);
++      }
++}
++
++static void unix_state_double_unlock(struct sock *sk1, struct sock *sk2)
++{
++      if (unlikely(sk1 == sk2) || !sk2) {
++              unix_state_unlock(sk1);
++              return;
++      }
++      unix_state_unlock(sk1);
++      unix_state_unlock(sk2);
++}
++
++int aa_unix_file_perm(struct aa_label *label, const char *op, u32 request,
++                    struct socket *sock)
++{
++      struct sock *peer_sk = NULL;
++      u32 sk_req = request & ~NET_PEER_MASK;
++      int error = 0;
++
++      AA_BUG(!label);
++      AA_BUG(!sock);
++      AA_BUG(!sock->sk);
++      AA_BUG(sock->sk->sk_family != AF_UNIX);
++
++      /* TODO: update sock label with new task label */
++      unix_state_lock(sock->sk);
++      peer_sk = unix_peer(sock->sk);
++      if (peer_sk)
++              sock_hold(peer_sk);
++      if (!unix_connected(sock) && sk_req) {
++              error = unix_label_sock_perm(label, op, sk_req, sock);
++              if (!error) {
++                      // update label
++              }
++      }
++      unix_state_unlock(sock->sk);
++      if (!peer_sk)
++              return error;
++
++      unix_state_double_lock(sock->sk, peer_sk);
++      if (UNIX_FS(sock->sk)) {
++              error = unix_fs_perm(op, request, label, unix_sk(sock->sk),
++                                   PATH_SOCK_COND);
++      } else if (UNIX_FS(peer_sk)) {
++              error = unix_fs_perm(op, request, label, unix_sk(peer_sk),
++                                   PATH_SOCK_COND);
++      } else {
++              struct aa_sk_ctx *pctx = SK_CTX(peer_sk);
++              if (sk_req)
++                      error = aa_unix_label_sk_perm(label, op, sk_req,
++                                                    sock->sk);
++              last_error(error,
++                      xcheck(aa_unix_peer_perm(label, op,
++                                               MAY_READ | MAY_WRITE,
++                                               sock->sk, peer_sk, NULL),
++                             aa_unix_peer_perm(pctx->label, op,
++                                               MAY_READ | MAY_WRITE,
++                                               peer_sk, sock->sk, label)));
++      }
++
++      unix_state_double_unlock(sock->sk, peer_sk);
++      sock_put(peer_sk);
++
++      return error;
++}
+diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
+index 125dad5c3fde..20cdb1c4b266 100644
+--- a/security/apparmor/apparmorfs.c
++++ b/security/apparmor/apparmorfs.c
+@@ -2187,6 +2187,11 @@ static struct aa_sfs_entry aa_sfs_entry_ns[] = {
+       { }
+ };
++static struct aa_sfs_entry aa_sfs_entry_dbus[] = {
++      AA_SFS_FILE_STRING("mask", "acquire send receive"),
++      { }
++};
++
+ static struct aa_sfs_entry aa_sfs_entry_query_label[] = {
+       AA_SFS_FILE_STRING("perms", "allow deny audit quiet"),
+       AA_SFS_FILE_BOOLEAN("data",             1),
+@@ -2210,6 +2215,7 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = {
+       AA_SFS_DIR("caps",                      aa_sfs_entry_caps),
+       AA_SFS_DIR("ptrace",                    aa_sfs_entry_ptrace),
+       AA_SFS_DIR("signal",                    aa_sfs_entry_signal),
++      AA_SFS_DIR("dbus",                      aa_sfs_entry_dbus),
+       AA_SFS_DIR("query",                     aa_sfs_entry_query),
+       { }
+ };
+diff --git a/security/apparmor/file.c b/security/apparmor/file.c
+index db80221891c6..e62791106900 100644
+--- a/security/apparmor/file.c
++++ b/security/apparmor/file.c
+@@ -16,6 +16,7 @@
+ #include <linux/fdtable.h>
+ #include <linux/file.h>
++#include "include/af_unix.h"
+ #include "include/apparmor.h"
+ #include "include/audit.h"
+ #include "include/context.h"
+@@ -289,7 +290,8 @@ int __aa_path_perm(const char *op, struct aa_profile *profile, const char *name,
+ {
+       int e = 0;
+-      if (profile_unconfined(profile))
++      if (profile_unconfined(profile) ||
++          ((flags & PATH_SOCK_COND) && !PROFILE_MEDIATES_AF(profile, AF_UNIX)))
+               return 0;
+       aa_str_perms(profile->file.dfa, profile->file.start, name, cond, perms);
+       if (request & ~perms->allow)
+diff --git a/security/apparmor/include/af_unix.h b/security/apparmor/include/af_unix.h
+new file mode 100644
+index 000000000000..d1b7f2316be4
+--- /dev/null
++++ b/security/apparmor/include/af_unix.h
+@@ -0,0 +1,114 @@
++/*
++ * AppArmor security module
++ *
++ * This file contains AppArmor af_unix fine grained mediation
++ *
++ * Copyright 2014 Canonical Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation, version 2 of the
++ * License.
++ */
++#ifndef __AA_AF_UNIX_H
++
++#include <net/af_unix.h>
++
++#include "label.h"
++//#include "include/net.h"
++
++#define unix_addr_len(L) ((L) - sizeof(sa_family_t))
++#define unix_abstract_name_len(L) (unix_addr_len(L) - 1)
++#define unix_abstract_len(U) (unix_abstract_name_len((U)->addr->len))
++#define addr_unix_abstract_name(B) ((B)[0] == 0)
++#define addr_unix_anonymous(U) (addr_unix_len(U) <= 0)
++#define addr_unix_abstract(U) (!addr_unix_anonymous(U) && addr_unix_abstract_name((U)->addr))
++//#define unix_addr_fs(U) (!unix_addr_anonymous(U) && !unix_addr_abstract_name((U)->addr))
++
++#define unix_addr(A) ((struct sockaddr_un *)(A))
++#define unix_addr_anon(A, L) ((A) && unix_addr_len(L) <= 0)
++#define unix_addr_fs(A, L) (!unix_addr_anon(A, L) && !addr_unix_abstract_name(unix_addr(A)->sun_path))
++
++#define UNIX_ANONYMOUS(U) (!unix_sk(U)->addr)
++/* from net/unix/af_unix.c */
++#define UNIX_ABSTRACT(U) (!UNIX_ANONYMOUS(U) &&                               \
++                        unix_sk(U)->addr->hash < UNIX_HASH_SIZE)
++#define UNIX_FS(U) (!UNIX_ANONYMOUS(U) && unix_sk(U)->addr->name->sun_path[0])
++#define unix_peer(sk) (unix_sk(sk)->peer)
++#define unix_connected(S) ((S)->state == SS_CONNECTED)
++
++static inline void print_unix_addr(struct sockaddr_un *A, int L)
++{
++      char *buf = (A) ? (char *) &(A)->sun_path : NULL;
++      int len = unix_addr_len(L);
++      if (!buf || len <= 0)
++              printk(" <anonymous>");
++      else if (buf[0])
++              printk(" %s", buf);
++      else
++              /* abstract name len includes leading \0 */
++              printk(" %d @%.*s", len - 1, len - 1, buf+1);
++};
++
++/*
++      printk("%s: %s: f %d, t %d, p %d", __FUNCTION__,                \
++             #SK ,                                                    \
++*/
++#define print_unix_sk(SK)                                             \
++do {                                                                  \
++      struct unix_sock *u = unix_sk(SK);                              \
++      printk("%s: f %d, t %d, p %d",  #SK ,                           \
++             (SK)->sk_family, (SK)->sk_type, (SK)->sk_protocol);      \
++      if (u->addr)                                                    \
++              print_unix_addr(u->addr->name, u->addr->len);           \
++      else                                                            \
++              print_unix_addr(NULL, sizeof(sa_family_t));             \
++      /* printk("\n");*/                                              \
++} while (0)
++
++#define print_sk(SK)                                                  \
++do {                                                                  \
++      if (!(SK)) {                                                    \
++              printk("%s: %s is null\n", __FUNCTION__, #SK);          \
++      } else if ((SK)->sk_family == PF_UNIX) {                        \
++              print_unix_sk(SK);                                      \
++              printk("\n");                                           \
++      } else {                                                        \
++              printk("%s: %s: family %d\n", __FUNCTION__, #SK ,       \
++                     (SK)->sk_family);                                \
++      }                                                               \
++} while (0)
++
++#define print_sock_addr(U) \
++do {                         \
++      printk("%s:\n", __FUNCTION__);                                  \
++      printk("    sock %s:", sock_ctx && sock_ctx->label ? aa_label_printk(sock_ctx->label, GFP_ATOMIC); : "<null>"); print_sk(sock); \
++      printk("    other %s:", other_ctx && other_ctx->label ? aa_label_printk(other_ctx->label, GFP_ATOMIC); : "<null>"); print_sk(other); \
++      printk("    new %s", new_ctx && new_ctx->label ? aa_label_printk(new_ctx->label, GFP_ATOMIC); : "<null>"); print_sk(newsk); \
++} while (0)
++
++
++
++
++int aa_unix_peer_perm(struct aa_label *label, const char *op, u32 request,
++                    struct sock *sk, struct sock *peer_sk,
++                    struct aa_label *peer_label);
++int aa_unix_label_sk_perm(struct aa_label *label, const char *op, u32 request,
++                        struct sock *sk);
++int aa_unix_sock_perm(const char *op, u32 request, struct socket *sock);
++int aa_unix_create_perm(struct aa_label *label, int family, int type,
++                      int protocol);
++int aa_unix_bind_perm(struct socket *sock, struct sockaddr *address,
++                    int addrlen);
++int aa_unix_connect_perm(struct socket *sock, struct sockaddr *address,
++                       int addrlen);
++int aa_unix_listen_perm(struct socket *sock, int backlog);
++int aa_unix_accept_perm(struct socket *sock, struct socket *newsock);
++int aa_unix_msg_perm(const char *op, u32 request, struct socket *sock,
++                   struct msghdr *msg, int size);
++int aa_unix_opt_perm(const char *op, u32 request, struct socket *sock, int level,
++                   int optname);
++int aa_unix_file_perm(struct aa_label *label, const char *op, u32 request,
++                    struct socket *sock);
++
++#endif /* __AA_AF_UNIX_H */
+diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
+index 140c8efcf364..0ae45240c352 100644
+--- a/security/apparmor/include/net.h
++++ b/security/apparmor/include/net.h
+@@ -90,8 +90,6 @@ extern struct aa_sfs_entry aa_sfs_entry_network[];
+ void audit_net_cb(struct audit_buffer *ab, void *va);
+ int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa,
+                      u32 request, u16 family, int type);
+-int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family,
+-             int type, int protocol);
+ static inline int aa_profile_af_sk_perm(struct aa_profile *profile,
+                                       struct common_audit_data *sa,
+                                       u32 request,
+@@ -100,8 +98,20 @@ static inline int aa_profile_af_sk_perm(struct aa_profile *profile,
+       return aa_profile_af_perm(profile, sa, request, sk->sk_family,
+                                 sk->sk_type);
+ }
+-int aa_sk_perm(const char *op, u32 request, struct sock *sk);
++int aa_sock_perm(const char *op, u32 request, struct socket *sock);
++int aa_sock_create_perm(struct aa_label *label, int family, int type,
++                      int protocol);
++int aa_sock_bind_perm(struct socket *sock, struct sockaddr *address,
++                    int addrlen);
++int aa_sock_connect_perm(struct socket *sock, struct sockaddr *address,
++                       int addrlen);
++int aa_sock_listen_perm(struct socket *sock, int backlog);
++int aa_sock_accept_perm(struct socket *sock, struct socket *newsock);
++int aa_sock_msg_perm(const char *op, u32 request, struct socket *sock,
++                   struct msghdr *msg, int size);
++int aa_sock_opt_perm(const char *op, u32 request, struct socket *sock, int level,
++                   int optname);
+ int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request,
+                     struct socket *sock);
+diff --git a/security/apparmor/include/path.h b/security/apparmor/include/path.h
+index 05fb3305671e..26762db2207d 100644
+--- a/security/apparmor/include/path.h
++++ b/security/apparmor/include/path.h
+@@ -18,6 +18,7 @@
+ enum path_flags {
+       PATH_IS_DIR = 0x1,              /* path is a directory */
++      PATH_SOCK_COND = 0x2,
+       PATH_CONNECT_PATH = 0x4,        /* connect disconnected paths to / */
+       PATH_CHROOT_REL = 0x8,          /* do path lookup relative to chroot */
+       PATH_CHROOT_NSCONNECT = 0x10,   /* connect paths that are at ns root */
+diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
+index 4364088a0b9e..26660a1a50b0 100644
+--- a/security/apparmor/include/policy.h
++++ b/security/apparmor/include/policy.h
+@@ -226,7 +226,7 @@ static inline unsigned int PROFILE_MEDIATES_SAFE(struct aa_profile *profile,
+ static inline unsigned int PROFILE_MEDIATES_AF(struct aa_profile *profile,
+                                              u16 AF) {
+       unsigned int state = PROFILE_MEDIATES(profile, AA_CLASS_NET);
+-      u16 be_af = cpu_to_be16(AF);
++      __be16 be_af = cpu_to_be16(AF);
+       if (!state)
+               return 0;
+diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
+index cc5ab23a2d84..0ede66d80a53 100644
+--- a/security/apparmor/lsm.c
++++ b/security/apparmor/lsm.c
+@@ -26,6 +26,7 @@
+ #include <linux/kmemleak.h>
+ #include <net/sock.h>
++#include "include/af_unix.h"
+ #include "include/apparmor.h"
+ #include "include/apparmorfs.h"
+ #include "include/audit.h"
+@@ -782,16 +783,96 @@ static void apparmor_sk_clone_security(const struct sock *sk,
+       path_get(&new->path);
+ }
+-static int aa_sock_create_perm(struct aa_label *label, int family, int type,
+-                             int protocol)
++static struct path *UNIX_FS_CONN_PATH(struct sock *sk, struct sock *newsk)
+ {
+-      AA_BUG(!label);
+-      AA_BUG(in_interrupt());
++      if (sk->sk_family == PF_UNIX && UNIX_FS(sk))
++              return &unix_sk(sk)->path;
++      else if (newsk->sk_family == PF_UNIX && UNIX_FS(newsk))
++              return &unix_sk(newsk)->path;
++      return NULL;
++}
++
++/**
++ * apparmor_unix_stream_connect - check perms before making unix domain conn
++ *
++ * peer is locked when this hook is called
++ */
++static int apparmor_unix_stream_connect(struct sock *sk, struct sock *peer_sk,
++                                      struct sock *newsk)
++{
++      struct aa_sk_ctx *sk_ctx = SK_CTX(sk);
++      struct aa_sk_ctx *peer_ctx = SK_CTX(peer_sk);
++      struct aa_sk_ctx *new_ctx = SK_CTX(newsk);
++      struct aa_label *label;
++      struct path *path;
++      int error;
+-      return aa_af_perm(label, OP_CREATE, AA_MAY_CREATE, family, type,
+-                        protocol);
++      label = __begin_current_label_crit_section();
++      error = aa_unix_peer_perm(label, OP_CONNECT,
++                              (AA_MAY_CONNECT | AA_MAY_SEND | AA_MAY_RECEIVE),
++                                sk, peer_sk, NULL);
++      if (!UNIX_FS(peer_sk)) {
++              last_error(error,
++                      aa_unix_peer_perm(peer_ctx->label, OP_CONNECT,
++                              (AA_MAY_ACCEPT | AA_MAY_SEND | AA_MAY_RECEIVE),
++                              peer_sk, sk, label));
++      }
++      __end_current_label_crit_section(label);
++
++      if (error)
++              return error;
++
++      /* label newsk if it wasn't labeled in post_create. Normally this
++       * would be done in sock_graft, but because we are directly looking
++       * at the peer_sk to obtain peer_labeling for unix socks this
++       * does not work
++       */
++      if (!new_ctx->label)
++              new_ctx->label = aa_get_label(peer_ctx->label);
++
++      /* Cross reference the peer labels for SO_PEERSEC */
++      if (new_ctx->peer)
++              aa_put_label(new_ctx->peer);
++
++      if (sk_ctx->peer)
++              aa_put_label(sk_ctx->peer);
++
++      new_ctx->peer = aa_get_label(sk_ctx->label);
++      sk_ctx->peer = aa_get_label(peer_ctx->label);
++
++      path = UNIX_FS_CONN_PATH(sk, peer_sk);
++      if (path) {
++              new_ctx->path = *path;
++              sk_ctx->path = *path;
++              path_get(path);
++              path_get(path);
++      }
++      return 0;
+ }
++/**
++ * apparmor_unix_may_send - check perms before conn or sending unix dgrams
++ *
++ * other is locked when this hook is called
++ *
++ * dgram connect calls may_send, peer setup but path not copied?????
++ */
++static int apparmor_unix_may_send(struct socket *sock, struct socket *peer)
++{
++      struct aa_sk_ctx *peer_ctx = SK_CTX(peer->sk);
++      struct aa_label *label;
++      int error;
++
++      label = __begin_current_label_crit_section();
++      error = xcheck(aa_unix_peer_perm(label, OP_SENDMSG, AA_MAY_SEND,
++                                       sock->sk, peer->sk, NULL),
++                     aa_unix_peer_perm(peer_ctx->label, OP_SENDMSG,
++                                       AA_MAY_RECEIVE,
++                                       peer->sk, sock->sk, label));
++      __end_current_label_crit_section(label);
++
++      return error;
++}
+ /**
+  * apparmor_socket_create - check perms before creating a new socket
+@@ -849,12 +930,7 @@ static int apparmor_socket_post_create(struct socket *sock, int family,
+ static int apparmor_socket_bind(struct socket *sock,
+                               struct sockaddr *address, int addrlen)
+ {
+-      AA_BUG(!sock);
+-      AA_BUG(!sock->sk);
+-      AA_BUG(!address);
+-      AA_BUG(in_interrupt());
+-
+-      return aa_sk_perm(OP_BIND, AA_MAY_BIND, sock->sk);
++      return aa_sock_bind_perm(sock, address, addrlen);
+ }
+ /**
+@@ -863,12 +939,7 @@ static int apparmor_socket_bind(struct socket *sock,
+ static int apparmor_socket_connect(struct socket *sock,
+                                  struct sockaddr *address, int addrlen)
+ {
+-      AA_BUG(!sock);
+-      AA_BUG(!sock->sk);
+-      AA_BUG(!address);
+-      AA_BUG(in_interrupt());
+-
+-      return aa_sk_perm(OP_CONNECT, AA_MAY_CONNECT, sock->sk);
++      return aa_sock_connect_perm(sock, address, addrlen);
+ }
+ /**
+@@ -876,11 +947,7 @@ static int apparmor_socket_connect(struct socket *sock,
+  */
+ static int apparmor_socket_listen(struct socket *sock, int backlog)
+ {
+-      AA_BUG(!sock);
+-      AA_BUG(!sock->sk);
+-      AA_BUG(in_interrupt());
+-
+-      return aa_sk_perm(OP_LISTEN, AA_MAY_LISTEN, sock->sk);
++      return aa_sock_listen_perm(sock, backlog);
+ }
+ /**
+@@ -891,23 +958,7 @@ static int apparmor_socket_listen(struct socket *sock, int backlog)
+  */
+ static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
+ {
+-      AA_BUG(!sock);
+-      AA_BUG(!sock->sk);
+-      AA_BUG(!newsock);
+-      AA_BUG(in_interrupt());
+-
+-      return aa_sk_perm(OP_ACCEPT, AA_MAY_ACCEPT, sock->sk);
+-}
+-
+-static int aa_sock_msg_perm(const char *op, u32 request, struct socket *sock,
+-                          struct msghdr *msg, int size)
+-{
+-      AA_BUG(!sock);
+-      AA_BUG(!sock->sk);
+-      AA_BUG(!msg);
+-      AA_BUG(in_interrupt());
+-
+-      return aa_sk_perm(op, request, sock->sk);
++      return aa_sock_accept_perm(sock, newsock);
+ }
+ /**
+@@ -928,16 +979,6 @@ static int apparmor_socket_recvmsg(struct socket *sock,
+       return aa_sock_msg_perm(OP_RECVMSG, AA_MAY_RECEIVE, sock, msg, size);
+ }
+-/* revaliation, get/set attr, shutdown */
+-static int aa_sock_perm(const char *op, u32 request, struct socket *sock)
+-{
+-      AA_BUG(!sock);
+-      AA_BUG(!sock->sk);
+-      AA_BUG(in_interrupt());
+-
+-      return aa_sk_perm(op, request, sock->sk);
+-}
+-
+ /**
+  * apparmor_socket_getsockname - check perms before getting the local address
+  */
+@@ -954,17 +995,6 @@ static int apparmor_socket_getpeername(struct socket *sock)
+       return aa_sock_perm(OP_GETPEERNAME, AA_MAY_GETATTR, sock);
+ }
+-/* revaliation, get/set attr, opt */
+-static int aa_sock_opt_perm(const char *op, u32 request, struct socket *sock,
+-                          int level, int optname)
+-{
+-      AA_BUG(!sock);
+-      AA_BUG(!sock->sk);
+-      AA_BUG(in_interrupt());
+-
+-      return aa_sk_perm(op, request, sock->sk);
+-}
+-
+ /**
+  * apparmor_getsockopt - check perms before getting socket options
+  */
+@@ -1009,11 +1039,25 @@ static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
+ static struct aa_label *sk_peer_label(struct sock *sk)
+ {
++      struct sock *peer_sk;
+       struct aa_sk_ctx *ctx = SK_CTX(sk);
+       if (ctx->peer)
+               return ctx->peer;
++      if (sk->sk_family != PF_UNIX)
++              return ERR_PTR(-ENOPROTOOPT);
++
++      /* check for sockpair peering which does not go through
++       * security_unix_stream_connect
++       */
++      peer_sk = unix_peer(sk);
++      if (peer_sk) {
++              ctx = SK_CTX(peer_sk);
++              if (ctx->label)
++                      return ctx->label;
++      }
++
+       return ERR_PTR(-ENOPROTOOPT);
+ }
+@@ -1137,6 +1181,9 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
+       LSM_HOOK_INIT(sk_free_security, apparmor_sk_free_security),
+       LSM_HOOK_INIT(sk_clone_security, apparmor_sk_clone_security),
++      LSM_HOOK_INIT(unix_stream_connect, apparmor_unix_stream_connect),
++      LSM_HOOK_INIT(unix_may_send, apparmor_unix_may_send),
++
+       LSM_HOOK_INIT(socket_create, apparmor_socket_create),
+       LSM_HOOK_INIT(socket_post_create, apparmor_socket_post_create),
+       LSM_HOOK_INIT(socket_bind, apparmor_socket_bind),
+diff --git a/security/apparmor/net.c b/security/apparmor/net.c
+index 33d54435f8d6..dd1953b08e58 100644
+--- a/security/apparmor/net.c
++++ b/security/apparmor/net.c
+@@ -12,6 +12,7 @@
+  * License.
+  */
++#include "include/af_unix.h"
+ #include "include/apparmor.h"
+ #include "include/audit.h"
+ #include "include/context.h"
+@@ -24,6 +25,7 @@
+ struct aa_sfs_entry aa_sfs_entry_network[] = {
+       AA_SFS_FILE_STRING("af_mask",   AA_SFS_AF_MASK),
++      AA_SFS_FILE_BOOLEAN("af_unix",  1),
+       { }
+ };
+@@ -69,6 +71,36 @@ static const char * const net_mask_names[] = {
+       "unknown",
+ };
++static void audit_unix_addr(struct audit_buffer *ab, const char *str,
++                          struct sockaddr_un *addr, int addrlen)
++{
++      int len = unix_addr_len(addrlen);
++
++      if (!addr || len <= 0) {
++              audit_log_format(ab, " %s=none", str);
++      } else if (addr->sun_path[0]) {
++              audit_log_format(ab, " %s=", str);
++              audit_log_untrustedstring(ab, addr->sun_path);
++      } else {
++              audit_log_format(ab, " %s=\"@", str);
++              if (audit_string_contains_control(&addr->sun_path[1], len - 1))
++                      audit_log_n_hex(ab, &addr->sun_path[1], len - 1);
++              else
++                      audit_log_format(ab, "%.*s", len - 1,
++                                       &addr->sun_path[1]);
++              audit_log_format(ab, "\"");
++      }
++}
++
++static void audit_unix_sk_addr(struct audit_buffer *ab, const char *str,
++                             struct sock *sk)
++{
++      struct unix_sock *u = unix_sk(sk);
++      if (u && u->addr)
++              audit_unix_addr(ab, str, u->addr->name, u->addr->len);
++      else
++              audit_unix_addr(ab, str, NULL, 0);
++}
+ /* audit callback for net specific fields */
+ void audit_net_cb(struct audit_buffer *ab, void *va)
+@@ -98,6 +130,23 @@ void audit_net_cb(struct audit_buffer *ab, void *va)
+                                          net_mask_names, NET_PERMS_MASK);
+               }
+       }
++      if (sa->u.net->family == AF_UNIX) {
++              if ((aad(sa)->request & ~NET_PEER_MASK) && aad(sa)->net.addr)
++                      audit_unix_addr(ab, "addr",
++                                      unix_addr(aad(sa)->net.addr),
++                                      aad(sa)->net.addrlen);
++              else
++                      audit_unix_sk_addr(ab, "addr", sa->u.net->sk);
++              if (aad(sa)->request & NET_PEER_MASK) {
++                      if (aad(sa)->net.addr)
++                              audit_unix_addr(ab, "peer_addr",
++                                              unix_addr(aad(sa)->net.addr),
++                                              aad(sa)->net.addrlen);
++                      else
++                              audit_unix_sk_addr(ab, "peer_addr",
++                                                 aad(sa)->net.peer_sk);
++              }
++      }
+       if (aad(sa)->peer) {
+               audit_log_format(ab, " peer=");
+               aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
+@@ -172,6 +221,127 @@ int aa_sk_perm(const char *op, u32 request, struct sock *sk)
+       return error;
+ }
++#define af_select(FAMILY, FN, DEF_FN)         \
++({                                            \
++      int __e;                                \
++      switch ((FAMILY)) {                     \
++      case AF_UNIX:                           \
++              __e = aa_unix_ ## FN;           \
++              break;                          \
++      default:                                \
++              __e = DEF_FN;                   \
++      }                                       \
++      __e;                                    \
++})
++
++/* TODO: push into lsm.c ???? */
++
++/* revaliation, get/set attr, shutdown */
++int aa_sock_perm(const char *op, u32 request, struct socket *sock)
++{
++      AA_BUG(!sock);
++      AA_BUG(!sock->sk);
++      AA_BUG(in_interrupt());
++
++      return af_select(sock->sk->sk_family,
++                       sock_perm(op, request, sock),
++                       aa_sk_perm(op, request, sock->sk));
++}
++
++int aa_sock_create_perm(struct aa_label *label, int family, int type,
++                      int protocol)
++{
++      AA_BUG(!label);
++      /* TODO: .... */
++      AA_BUG(in_interrupt());
++
++      return af_select(family,
++                       create_perm(label, family, type, protocol),
++                       aa_af_perm(label, OP_CREATE, AA_MAY_CREATE, family,
++                                  type, protocol));
++}
++
++int aa_sock_bind_perm(struct socket *sock, struct sockaddr *address,
++                    int addrlen)
++{
++      AA_BUG(!sock);
++      AA_BUG(!sock->sk);
++      AA_BUG(!address);
++      /* TODO: .... */
++      AA_BUG(in_interrupt());
++
++      return af_select(sock->sk->sk_family,
++                       bind_perm(sock, address, addrlen),
++                       aa_sk_perm(OP_BIND, AA_MAY_BIND, sock->sk));
++}
++
++int aa_sock_connect_perm(struct socket *sock, struct sockaddr *address,
++                       int addrlen)
++{
++      AA_BUG(!sock);
++      AA_BUG(!sock->sk);
++      AA_BUG(!address);
++      /* TODO: .... */
++      AA_BUG(in_interrupt());
++
++      return af_select(sock->sk->sk_family,
++                       connect_perm(sock, address, addrlen),
++                       aa_sk_perm(OP_CONNECT, AA_MAY_CONNECT, sock->sk));
++}
++
++int aa_sock_listen_perm(struct socket *sock, int backlog)
++{
++      AA_BUG(!sock);
++      AA_BUG(!sock->sk);
++      /* TODO: .... */
++      AA_BUG(in_interrupt());
++
++      return af_select(sock->sk->sk_family,
++                       listen_perm(sock, backlog),
++                       aa_sk_perm(OP_LISTEN, AA_MAY_LISTEN, sock->sk));
++}
++
++/* ability of sock to connect, not peer address binding */
++int aa_sock_accept_perm(struct socket *sock, struct socket *newsock)
++{
++      AA_BUG(!sock);
++      AA_BUG(!sock->sk);
++      AA_BUG(!newsock);
++      /* TODO: .... */
++      AA_BUG(in_interrupt());
++
++      return af_select(sock->sk->sk_family,
++                       accept_perm(sock, newsock),
++                       aa_sk_perm(OP_ACCEPT, AA_MAY_ACCEPT, sock->sk));
++}
++
++/* sendmsg, recvmsg */
++int aa_sock_msg_perm(const char *op, u32 request, struct socket *sock,
++                   struct msghdr *msg, int size)
++{
++      AA_BUG(!sock);
++      AA_BUG(!sock->sk);
++      AA_BUG(!msg);
++      /* TODO: .... */
++      AA_BUG(in_interrupt());
++
++      return af_select(sock->sk->sk_family,
++                       msg_perm(op, request, sock, msg, size),
++                       aa_sk_perm(op, request, sock->sk));
++}
++
++/* revaliation, get/set attr, opt */
++int aa_sock_opt_perm(const char *op, u32 request, struct socket *sock, int level,
++                   int optname)
++{
++      AA_BUG(!sock);
++      AA_BUG(!sock->sk);
++      AA_BUG(in_interrupt());
++
++      return af_select(sock->sk->sk_family,
++                       opt_perm(op, request, sock, level, optname),
++                       aa_sk_perm(op, request, sock->sk));
++}
+ int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request,
+                     struct socket *sock)
+@@ -180,5 +350,7 @@ int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request,
+       AA_BUG(!sock);
+       AA_BUG(!sock->sk);
+-      return aa_label_sk_perm(label, op, request, sock->sk);
++      return af_select(sock->sk->sk_family,
++                       file_perm(label, op, request, sock),
++                       aa_label_sk_perm(label, op, request, sock->sk));
+ }
+-- 
+2.11.0
+
diff --git a/kernel-apparmor-net-audit.patch b/kernel-apparmor-net-audit.patch
deleted file mode 100644 (file)
index 99184e6..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-commit b866a43c2897f5469c9d787426144074a3713f6a
-Author: John Johansen <john.johansen@canonical.com>
-Date:   Fri Jun 29 17:34:00 2012 -0700
-
-    apparmor: Fix quieting of audit messages for network mediation
-    
-    If a profile specified a quieting of network denials for a given rule by
-    either the quiet or deny rule qualifiers, the resultant quiet mask for
-    denied requests was applied incorrectly, resulting in two potential bugs.
-    1. The misapplied quiet mask would prevent denials from being correctly
-       tested against the kill mask/mode. Thus network access requests that
-       should have resulted in the application being killed did not.
-    
-    2. The actual quieting of the denied network request was not being applied.
-       This would result in network rejections always being logged even when
-       they had been specifically marked as quieted.
-    
-    Signed-off-by: John Johansen <john.johansen@canonical.com>
-
-diff --git a/security/apparmor/net.c b/security/apparmor/net.c
-index b9c8cd0e882e..5ba19ad1d65c 100644
---- a/security/apparmor/net.c
-+++ b/security/apparmor/net.c
-@@ -74,7 +74,7 @@ static int audit_net(struct aa_profile *profile, const char *op, u16 family,
-       } else {
-               u16 quiet_mask = profile->net.quiet[sa.u.net->family];
-               u16 kill_mask = 0;
--              u16 denied = (1 << aad(&sa)->net.type) & ~quiet_mask;
-+              u16 denied = (1 << aad(&sa)->net.type);
-               if (denied & kill_mask)
-                       audit_type = AUDIT_APPARMOR_KILL;
diff --git a/kernel-apparmor-net.patch b/kernel-apparmor-net.patch
deleted file mode 100644 (file)
index 21d7849..0000000
+++ /dev/null
@@ -1,589 +0,0 @@
-commit 97b3200925ba627346432edf521d49de8bb018a3
-Author: John Johansen <john.johansen@canonical.com>
-Date:   Mon Oct 4 15:03:36 2010 -0700
-
-    UBUNTU: SAUCE: AppArmor: basic networking rules
-    
-    Base support for network mediation.
-    
-    Signed-off-by: John Johansen <john.johansen@canonical.com>
-
-diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore
-index 9cdec70d72b8..d5b291e94264 100644
---- a/security/apparmor/.gitignore
-+++ b/security/apparmor/.gitignore
-@@ -1,5 +1,6 @@
- #
- # Generated include files
- #
-+net_names.h
- capability_names.h
- rlim_names.h
-diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
-index ad369a7aac24..a7dc10be232d 100644
---- a/security/apparmor/Makefile
-+++ b/security/apparmor/Makefile
-@@ -4,10 +4,10 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
- apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
-               path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
--              resource.o secid.o file.o policy_ns.o
-+              resource.o secid.o file.o policy_ns.o net.o
- apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
--clean-files := capability_names.h rlim_names.h
-+clean-files := capability_names.h rlim_names.h net_names.h
- # Build a lower case string table of capability names
-@@ -25,6 +25,38 @@ cmd_make-caps = echo "static const char *const capability_names[] = {" > $@ ;\
-           -e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/\L\1/p' | \
-            tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
-+# Build a lower case string table of address family names
-+# Transform lines from
-+#    define AF_LOCAL  1       /* POSIX name for AF_UNIX       */
-+#    #define AF_INET          2       /* Internet IP Protocol         */
-+# to
-+#    [1] = "local",
-+#    [2] = "inet",
-+#
-+# and build the securityfs entries for the mapping.
-+# Transforms lines from
-+#    #define AF_INET          2       /* Internet IP Protocol         */
-+# to
-+#    #define AA_FS_AF_MASK "local inet"
-+quiet_cmd_make-af = GEN     $@
-+cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\
-+      sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e \
-+       's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
-+      echo "};" >> $@ ;\
-+      echo -n '\#define AA_FS_AF_MASK "' >> $@ ;\
-+      sed -r -n 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\
-+       $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
-+
-+# Build a lower case string table of sock type names
-+# Transform lines from
-+#    SOCK_STREAM      = 1,
-+# to
-+#    [1] = "stream",
-+quiet_cmd_make-sock = GEN     $@
-+cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\
-+      sed $^ >>$@ -r -n \
-+      -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
-+      echo "};" >> $@
- # Build a lower case string table of rlimit names.
- # Transforms lines from
-@@ -61,6 +93,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \
-           tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
- $(obj)/capability.o : $(obj)/capability_names.h
-+$(obj)/net.o : $(obj)/net_names.h
- $(obj)/resource.o : $(obj)/rlim_names.h
- $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
-                           $(src)/Makefile
-@@ -68,3 +101,8 @@ $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
- $(obj)/rlim_names.h : $(srctree)/include/uapi/asm-generic/resource.h \
-                     $(src)/Makefile
-       $(call cmd,make-rlim)
-+$(obj)/net_names.h : $(srctree)/include/linux/socket.h \
-+                   $(srctree)/include/linux/net.h \
-+                   $(src)/Makefile
-+      $(call cmd,make-af)
-+      $(call cmd,make-sock)
-diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
-index 41073f70eb41..4d236736cfb8 100644
---- a/security/apparmor/apparmorfs.c
-+++ b/security/apparmor/apparmorfs.c
-@@ -1209,6 +1209,7 @@ static struct aa_fs_entry aa_fs_entry_features[] = {
-       AA_FS_DIR("policy",                     aa_fs_entry_policy),
-       AA_FS_DIR("domain",                     aa_fs_entry_domain),
-       AA_FS_DIR("file",                       aa_fs_entry_file),
-+      AA_FS_DIR("network",                    aa_fs_entry_network),
-       AA_FS_FILE_U64("capability",            VFS_CAP_FLAGS_MASK),
-       AA_FS_DIR("rlimit",                     aa_fs_entry_rlimit),
-       AA_FS_DIR("caps",                       aa_fs_entry_caps),
-diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
-index fdc4774318ba..0df708e8748b 100644
---- a/security/apparmor/include/audit.h
-+++ b/security/apparmor/include/audit.h
-@@ -127,6 +127,10 @@ struct apparmor_audit_data {
-                       int rlim;
-                       unsigned long max;
-               } rlim;
-+              struct {
-+                      int type, protocol;
-+                      struct sock *sk;
-+              } net;
-       };
- };
-diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
-new file mode 100644
-index 000000000000..55da1dad8720
---- /dev/null
-+++ b/security/apparmor/include/net.h
-@@ -0,0 +1,59 @@
-+/*
-+ * AppArmor security module
-+ *
-+ * This file contains AppArmor network mediation definitions.
-+ *
-+ * Copyright (C) 1998-2008 Novell/SUSE
-+ * Copyright 2009-2012 Canonical Ltd.
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License as
-+ * published by the Free Software Foundation, version 2 of the
-+ * License.
-+ */
-+
-+#ifndef __AA_NET_H
-+#define __AA_NET_H
-+
-+#include <net/sock.h>
-+
-+#include "apparmorfs.h"
-+
-+/* struct aa_net - network confinement data
-+ * @allowed: basic network families permissions
-+ * @audit_network: which network permissions to force audit
-+ * @quiet_network: which network permissions to quiet rejects
-+ */
-+struct aa_net {
-+      u16 allow[AF_MAX];
-+      u16 audit[AF_MAX];
-+      u16 quiet[AF_MAX];
-+};
-+
-+extern struct aa_fs_entry aa_fs_entry_network[];
-+
-+#define DEFINE_AUDIT_NET(NAME, OP, SK, F, T, P)                                 \
-+      struct lsm_network_audit NAME ## _net = { .sk = (SK),             \
-+                                                .family = (F)};         \
-+      DEFINE_AUDIT_DATA(NAME,                                           \
-+                        ((SK) && (F) != AF_UNIX) ? LSM_AUDIT_DATA_NET : \
-+                                                   LSM_AUDIT_DATA_NONE, \
-+                        OP);                                            \
-+      NAME.u.net = &(NAME ## _net);                                     \
-+      aad(&NAME)->net.type = (T);                                       \
-+      aad(&NAME)->net.protocol = (P)
-+
-+#define DEFINE_AUDIT_SK(NAME, OP, SK)                                 \
-+      DEFINE_AUDIT_NET(NAME, OP, SK, (SK)->sk_family, (SK)->sk_type,  \
-+                       (SK)->sk_protocol)
-+
-+extern int aa_net_perm(const char *op, struct aa_profile *profile, u16 family,
-+                     int type, int protocol, struct sock *sk);
-+extern int aa_revalidate_sk(const char *op, struct sock *sk);
-+
-+static inline void aa_free_net_rules(struct aa_net *new)
-+{
-+      /* NOP */
-+}
-+
-+#endif /* __AA_NET_H */
-diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
-index 67bc96afe541..a3d18ea8d730 100644
---- a/security/apparmor/include/policy.h
-+++ b/security/apparmor/include/policy.h
-@@ -28,6 +28,7 @@
- #include "capability.h"
- #include "domain.h"
- #include "file.h"
-+#include "net.h"
- #include "lib.h"
- #include "resource.h"
-@@ -132,6 +133,7 @@ struct aa_data {
-  * @policy: general match rules governing policy
-  * @file: The set of rules governing basic file access and domain transitions
-  * @caps: capabilities for the profile
-+ * @net: network controls for the profile
-  * @rlimits: rlimits for the profile
-  *
-  * @dents: dentries for the profiles file entries in apparmorfs
-@@ -174,6 +176,7 @@ struct aa_profile {
-       struct aa_policydb policy;
-       struct aa_file_rules file;
-       struct aa_caps caps;
-+      struct aa_net net;
-       struct aa_rlimit rlimits;
-       struct aa_loaddata *rawdata;
-diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
-index 709eacd23909..e3017129a404 100644
---- a/security/apparmor/lsm.c
-+++ b/security/apparmor/lsm.c
-@@ -33,6 +33,7 @@
- #include "include/context.h"
- #include "include/file.h"
- #include "include/ipc.h"
-+#include "include/net.h"
- #include "include/path.h"
- #include "include/policy.h"
- #include "include/policy_ns.h"
-@@ -587,6 +588,104 @@ static int apparmor_task_setrlimit(struct task_struct *task,
-       return error;
- }
-+static int apparmor_socket_create(int family, int type, int protocol, int kern)
-+{
-+      struct aa_profile *profile;
-+      int error = 0;
-+
-+      if (kern)
-+              return 0;
-+
-+      profile = __aa_current_profile();
-+      if (!unconfined(profile))
-+              error = aa_net_perm(OP_CREATE, profile, family, type, protocol,
-+                                  NULL);
-+      return error;
-+}
-+
-+static int apparmor_socket_bind(struct socket *sock,
-+                              struct sockaddr *address, int addrlen)
-+{
-+      struct sock *sk = sock->sk;
-+
-+      return aa_revalidate_sk(OP_BIND, sk);
-+}
-+
-+static int apparmor_socket_connect(struct socket *sock,
-+                                 struct sockaddr *address, int addrlen)
-+{
-+      struct sock *sk = sock->sk;
-+
-+      return aa_revalidate_sk(OP_CONNECT, sk);
-+}
-+
-+static int apparmor_socket_listen(struct socket *sock, int backlog)
-+{
-+      struct sock *sk = sock->sk;
-+
-+      return aa_revalidate_sk(OP_LISTEN, sk);
-+}
-+
-+static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
-+{
-+      struct sock *sk = sock->sk;
-+
-+      return aa_revalidate_sk(OP_ACCEPT, sk);
-+}
-+
-+static int apparmor_socket_sendmsg(struct socket *sock,
-+                                 struct msghdr *msg, int size)
-+{
-+      struct sock *sk = sock->sk;
-+
-+      return aa_revalidate_sk(OP_SENDMSG, sk);
-+}
-+
-+static int apparmor_socket_recvmsg(struct socket *sock,
-+                                 struct msghdr *msg, int size, int flags)
-+{
-+      struct sock *sk = sock->sk;
-+
-+      return aa_revalidate_sk(OP_RECVMSG, sk);
-+}
-+
-+static int apparmor_socket_getsockname(struct socket *sock)
-+{
-+      struct sock *sk = sock->sk;
-+
-+      return aa_revalidate_sk(OP_GETSOCKNAME, sk);
-+}
-+
-+static int apparmor_socket_getpeername(struct socket *sock)
-+{
-+      struct sock *sk = sock->sk;
-+
-+      return aa_revalidate_sk(OP_GETPEERNAME, sk);
-+}
-+
-+static int apparmor_socket_getsockopt(struct socket *sock, int level,
-+                                    int optname)
-+{
-+      struct sock *sk = sock->sk;
-+
-+      return aa_revalidate_sk(OP_GETSOCKOPT, sk);
-+}
-+
-+static int apparmor_socket_setsockopt(struct socket *sock, int level,
-+                                    int optname)
-+{
-+      struct sock *sk = sock->sk;
-+
-+      return aa_revalidate_sk(OP_SETSOCKOPT, sk);
-+}
-+
-+static int apparmor_socket_shutdown(struct socket *sock, int how)
-+{
-+      struct sock *sk = sock->sk;
-+
-+      return aa_revalidate_sk(OP_SHUTDOWN, sk);
-+}
-+
- static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
-       LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
-       LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
-@@ -616,6 +715,19 @@ static struct security_hook_list apparmor_hooks[] = {
-       LSM_HOOK_INIT(getprocattr, apparmor_getprocattr),
-       LSM_HOOK_INIT(setprocattr, apparmor_setprocattr),
-+      LSM_HOOK_INIT(socket_create, apparmor_socket_create),
-+      LSM_HOOK_INIT(socket_bind, apparmor_socket_bind),
-+      LSM_HOOK_INIT(socket_connect, apparmor_socket_connect),
-+      LSM_HOOK_INIT(socket_listen, apparmor_socket_listen),
-+      LSM_HOOK_INIT(socket_accept, apparmor_socket_accept),
-+      LSM_HOOK_INIT(socket_sendmsg, apparmor_socket_sendmsg),
-+      LSM_HOOK_INIT(socket_recvmsg, apparmor_socket_recvmsg),
-+      LSM_HOOK_INIT(socket_getsockname, apparmor_socket_getsockname),
-+      LSM_HOOK_INIT(socket_getpeername, apparmor_socket_getpeername),
-+      LSM_HOOK_INIT(socket_getsockopt, apparmor_socket_getsockopt),
-+      LSM_HOOK_INIT(socket_setsockopt, apparmor_socket_setsockopt),
-+      LSM_HOOK_INIT(socket_shutdown, apparmor_socket_shutdown),
-+
-       LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank),
-       LSM_HOOK_INIT(cred_free, apparmor_cred_free),
-       LSM_HOOK_INIT(cred_prepare, apparmor_cred_prepare),
-diff --git a/security/apparmor/net.c b/security/apparmor/net.c
-new file mode 100644
-index 000000000000..b9c8cd0e882e
---- /dev/null
-+++ b/security/apparmor/net.c
-@@ -0,0 +1,148 @@
-+/*
-+ * AppArmor security module
-+ *
-+ * This file contains AppArmor network mediation
-+ *
-+ * Copyright (C) 1998-2008 Novell/SUSE
-+ * Copyright 2009-2012 Canonical Ltd.
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License as
-+ * published by the Free Software Foundation, version 2 of the
-+ * License.
-+ */
-+
-+#include "include/apparmor.h"
-+#include "include/audit.h"
-+#include "include/context.h"
-+#include "include/net.h"
-+#include "include/policy.h"
-+
-+#include "net_names.h"
-+
-+struct aa_fs_entry aa_fs_entry_network[] = {
-+      AA_FS_FILE_STRING("af_mask", AA_FS_AF_MASK),
-+      { }
-+};
-+
-+/* audit callback for net specific fields */
-+static void audit_cb(struct audit_buffer *ab, void *va)
-+{
-+      struct common_audit_data *sa = va;
-+
-+      audit_log_format(ab, " family=");
-+      if (address_family_names[sa->u.net->family]) {
-+              audit_log_string(ab, address_family_names[sa->u.net->family]);
-+      } else {
-+              audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family);
-+      }
-+      audit_log_format(ab, " sock_type=");
-+      if (sock_type_names[aad(sa)->net.type]) {
-+              audit_log_string(ab, sock_type_names[aad(sa)->net.type]);
-+      } else {
-+              audit_log_format(ab, "\"unknown(%d)\"", aad(sa)->net.type);
-+      }
-+      audit_log_format(ab, " protocol=%d", aad(sa)->net.protocol);
-+}
-+
-+/**
-+ * audit_net - audit network access
-+ * @profile: profile being enforced  (NOT NULL)
-+ * @op: operation being checked
-+ * @family: network family
-+ * @type:   network type
-+ * @protocol: network protocol
-+ * @sk: socket auditing is being applied to
-+ * @error: error code for failure else 0
-+ *
-+ * Returns: %0 or sa->error else other errorcode on failure
-+ */
-+static int audit_net(struct aa_profile *profile, const char *op, u16 family,
-+                   int type, int protocol, struct sock *sk, int error)
-+{
-+      int audit_type = AUDIT_APPARMOR_AUTO;
-+      DEFINE_AUDIT_NET(sa, op, sk, family, type, protocol);
-+
-+      aad(&sa)->error = error;
-+
-+      if (likely(!aad(&sa)->error)) {
-+              u16 audit_mask = profile->net.audit[sa.u.net->family];
-+              if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
-+                         !(1 << aad(&sa)->net.type & audit_mask)))
-+                      return 0;
-+              audit_type = AUDIT_APPARMOR_AUDIT;
-+      } else {
-+              u16 quiet_mask = profile->net.quiet[sa.u.net->family];
-+              u16 kill_mask = 0;
-+              u16 denied = (1 << aad(&sa)->net.type) & ~quiet_mask;
-+
-+              if (denied & kill_mask)
-+                      audit_type = AUDIT_APPARMOR_KILL;
-+
-+              if ((denied & quiet_mask) &&
-+                  AUDIT_MODE(profile) != AUDIT_NOQUIET &&
-+                  AUDIT_MODE(profile) != AUDIT_ALL)
-+                      return COMPLAIN_MODE(profile) ? 0 : aad(&sa)->error;
-+      }
-+
-+      return aa_audit(audit_type, profile, &sa, audit_cb);
-+}
-+
-+/**
-+ * aa_net_perm - very course network access check
-+ * @op: operation being checked
-+ * @profile: profile being enforced  (NOT NULL)
-+ * @family: network family
-+ * @type:   network type
-+ * @protocol: network protocol
-+ *
-+ * Returns: %0 else error if permission denied
-+ */
-+int aa_net_perm(const char *op, struct aa_profile *profile, u16 family,
-+              int type, int protocol, struct sock *sk)
-+{
-+      u16 family_mask;
-+      int error;
-+
-+      if ((family < 0) || (family >= AF_MAX))
-+              return -EINVAL;
-+
-+      if ((type < 0) || (type >= SOCK_MAX))
-+              return -EINVAL;
-+
-+      /* unix domain and netlink sockets are handled by ipc */
-+      if (family == AF_UNIX || family == AF_NETLINK)
-+              return 0;
-+
-+      family_mask = profile->net.allow[family];
-+
-+      error = (family_mask & (1 << type)) ? 0 : -EACCES;
-+
-+      return audit_net(profile, op, family, type, protocol, sk, error);
-+}
-+
-+/**
-+ * aa_revalidate_sk - Revalidate access to a sock
-+ * @op: operation being checked
-+ * @sk: sock being revalidated  (NOT NULL)
-+ *
-+ * Returns: %0 else error if permission denied
-+ */
-+int aa_revalidate_sk(const char *op, struct sock *sk)
-+{
-+      struct aa_profile *profile;
-+      int error = 0;
-+
-+      /* aa_revalidate_sk should not be called from interrupt context
-+       * don't mediate these calls as they are not task related
-+       */
-+      if (in_interrupt())
-+              return 0;
-+
-+      profile = __aa_current_profile();
-+      if (!unconfined(profile))
-+              error = aa_net_perm(op, profile, sk->sk_family, sk->sk_type,
-+                                  sk->sk_protocol, sk);
-+
-+      return error;
-+}
-diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
-index def1fbd6bdfd..9fe7b9d4500f 100644
---- a/security/apparmor/policy.c
-+++ b/security/apparmor/policy.c
-@@ -237,6 +237,7 @@ void aa_free_profile(struct aa_profile *profile)
-       aa_free_file_rules(&profile->file);
-       aa_free_cap_rules(&profile->caps);
-+      aa_free_net_rules(&profile->net);
-       aa_free_rlimit_rules(&profile->rlimits);
-       kzfree(profile->dirname);
-diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
-index 2e37c9c26bbd..bc23a5b3b113 100644
---- a/security/apparmor/policy_unpack.c
-+++ b/security/apparmor/policy_unpack.c
-@@ -217,6 +217,19 @@ static bool unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name)
-       return 0;
- }
-+static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name)
-+{
-+      if (unpack_nameX(e, AA_U16, name)) {
-+              if (!inbounds(e, sizeof(u16)))
-+                      return 0;
-+              if (data)
-+                      *data = le16_to_cpu(get_unaligned((u16 *) e->pos));
-+              e->pos += sizeof(u16);
-+              return 1;
-+      }
-+      return 0;
-+}
-+
- static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
- {
-       if (unpack_nameX(e, AA_U32, name)) {
-@@ -519,7 +532,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
- {
-       struct aa_profile *profile = NULL;
-       const char *tmpname, *tmpns = NULL, *name = NULL;
--      size_t ns_len;
-+      size_t ns_len, size = 0;
-       struct rhashtable_params params = { 0 };
-       char *key = NULL;
-       struct aa_data *data;
-@@ -635,6 +648,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
-       if (!unpack_rlimits(e, profile))
-               goto fail;
-+      size = unpack_array(e, "net_allowed_af");
-+      if (size) {
-+
-+              for (i = 0; i < size; i++) {
-+                      /* discard extraneous rules that this kernel will
-+                       * never request
-+                       */
-+                      if (i >= AF_MAX) {
-+                              u16 tmp;
-+                              if (!unpack_u16(e, &tmp, NULL) ||
-+                                  !unpack_u16(e, &tmp, NULL) ||
-+                                  !unpack_u16(e, &tmp, NULL))
-+                                      goto fail;
-+                              continue;
-+                      }
-+                      if (!unpack_u16(e, &profile->net.allow[i], NULL))
-+                              goto fail;
-+                      if (!unpack_u16(e, &profile->net.audit[i], NULL))
-+                              goto fail;
-+                      if (!unpack_u16(e, &profile->net.quiet[i], NULL))
-+                              goto fail;
-+              }
-+              if (!unpack_nameX(e, AA_ARRAYEND, NULL))
-+                      goto fail;
-+      }
-+      /*
-+       * allow unix domain and netlink sockets they are handled
-+       * by IPC
-+       */
-+      profile->net.allow[AF_UNIX] = 0xffff;
-+      profile->net.allow[AF_NETLINK] = 0xffff;
-+
-       if (unpack_nameX(e, AA_STRUCT, "policydb")) {
-               /* generic policy dfa - optional and may be NULL */
-               profile->policy.dfa = unpack_dfa(e);
index 3588cc29fdb992da58e26fdd7f0e90a3fbed16f6..8da51bfea387ec03aae782045e0545183559bc08 100644 (file)
@@ -30,7 +30,7 @@
 %bcond_without ipv6            # ipv6 support
 
 %bcond_without aufs            # aufs4 support
-%bcond_with    apparmor        # UBUNTU SAUCE apparmor patches
+%bcond_without apparmor        # UBUNTU SAUCE apparmor patches
 
 %bcond_with    vserver         # support for VServer
 
@@ -69,7 +69,7 @@
 %define                have_pcmcia     0
 %endif
 
-%define                rel             1
+%define                rel             2
 %define                basever         4.13
 %define                postver         .2
 
@@ -218,11 +218,24 @@ Patch2000:        kernel-small_fixes.patch
 Patch2001:     kernel-pwc-uncompress.patch
 Patch2003:     kernel-regressions.patch
 
-# git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor
-# branch v4.7-aa2.8-out-of-tree
-Patch5000:     kernel-apparmor-net.patch
-Patch5001:     kernel-apparmor-net-audit.patch
-Patch5002:     kernel-apparmor-mount.patch
+# http://bazaar.launchpad.net/~apparmor-dev/apparmor/master/files/head:/kernel-patches/v4.13/
+Patch5000:     0001-UBUNTU-SAUCE-efi-lockdown-MODSIGN-Fix-module-signatu.patch
+Patch5001:     0002-apparmor-Fix-shadowed-local-variable-in-unpack_trans.patch
+Patch5002:     0003-apparmor-Fix-logical-error-in-verify_header.patch
+Patch5003:     0004-apparmor-Fix-an-error-code-in-aafs_create.patch
+Patch5004:     0005-apparmor-Redundant-condition-prev_ns.-in-label.c-149.patch
+Patch5005:     0006-apparmor-add-the-ability-to-mediate-signals.patch
+Patch5006:     0007-apparmor-add-mount-mediation.patch
+Patch5007:     0008-apparmor-cleanup-conditional-check-for-label-in-labe.patch
+Patch5008:     0009-apparmor-add-support-for-absolute-root-view-based-la.patch
+Patch5009:     0010-apparmor-make-policy_unpack-able-to-audit-different-.patch
+Patch5010:     0011-apparmor-add-more-debug-asserts-to-apparmorfs.patch
+Patch5011:     0012-apparmor-add-base-infastructure-for-socket-mediation.patch
+Patch5012:     0013-apparmor-move-new_null_profile-to-after-profile-look.patch
+Patch5013:     0014-apparmor-fix-race-condition-in-null-profile-creation.patch
+Patch5014:     0015-apparmor-ensure-unconfined-profiles-have-dfas-initia.patch
+Patch5015:     0016-apparmor-fix-incorrect-type-assignment-when-freeing-.patch
+Patch5016:     0017-UBUNTU-SAUCE-apparmor-af_unix-mediation.patch
 
 # for rescuecd
 # based on ftp://ftp.leg.uct.ac.za/pub/linux/rip/tmpfs_root-2.6.30.diff.gz
@@ -696,6 +709,20 @@ rm -f localversion-rt
 %patch5000 -p1
 %patch5001 -p1
 %patch5002 -p1
+%patch5003 -p1
+%patch5004 -p1
+%patch5005 -p1
+%patch5006 -p1
+%patch5007 -p1
+%patch5008 -p1
+%patch5009 -p1
+%patch5010 -p1
+%patch5011 -p1
+%patch5012 -p1
+%patch5013 -p1
+%patch5014 -p1
+%patch5015 -p1
+%patch5016 -p1
 %endif
 
 %patch250 -p1
This page took 0.511283 seconds and 4 git commands to generate.