[packages/kernel] - rel 2; apparmor is back (upstream merged all apparmor patches, so upcoming 4.14 kernel should look

arekm arekm at pld-linux.org
Fri Sep 15 09:15:23 CEST 2017


commit daaa955e189a32b19c81af123dfa0306edfe9457
Author: Arkadiusz Miśkiewicz <arekm at maven.pl>
Date:   Fri Sep 15 09:15:06 2017 +0200

    - rel 2; apparmor is back (upstream merged all apparmor patches, so upcoming 4.14 kernel should look much better)

 ..._CONSTANTS-The-error-messages-regarding-y.patch |   26 +
 ...E-efi-lockdown-MODSIGN-Fix-module-signatu.patch |   41 +
 ...x-shadowed-local-variable-in-unpack_trans.patch |   51 +
 ...parmor-Fix-logical-error-in-verify_header.patch |   32 +
 ...apparmor-Fix-an-error-code-in-aafs_create.patch |   37 +
 ...dundant-condition-prev_ns.-in-label.c-149.patch |   29 +
 ...parmor-add-the-ability-to-mediate-signals.patch |  397 ++++++
 ...atch => 0007-apparmor-add-mount-mediation.patch |  780 ++++++-----
 ...eanup-conditional-check-for-label-in-labe.patch |   71 +
 ...d-support-for-absolute-root-view-based-la.patch |   63 +
 ...ke-policy_unpack-able-to-audit-different-.patch |  219 +++
 ...rmor-add-more-debug-asserts-to-apparmorfs.patch |   78 ++
 ...d-base-infastructure-for-socket-mediation.patch | 1123 ++++++++++++++++
 ...ve-new_null_profile-to-after-profile-look.patch |  194 +++
 ...x-race-condition-in-null-profile-creation.patch |   60 +
 ...sure-unconfined-profiles-have-dfas-initia.patch |   36 +
 ...x-incorrect-type-assignment-when-freeing-.patch |   39 +
 0017-UBUNTU-SAUCE-apparmor-af_unix-mediation.patch | 1394 ++++++++++++++++++++
 kernel-apparmor-net-audit.patch                    |   32 -
 kernel-apparmor-net.patch                          |  589 ---------
 kernel.spec                                        |   41 +-
 21 files changed, 4378 insertions(+), 954 deletions(-)
---
diff --git a/kernel.spec b/kernel.spec
index 3588cc29..8da51bfe 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -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
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
index 00000000..7b354836
--- /dev/null
+++ b/0001-Enable-SCSI_CONSTANTS-The-error-messages-regarding-y.patch
@@ -0,0 +1,26 @@
+From 3cf99fb519595e3934882ac9ea32409badc6b57a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Arkadiusz=20Mi=C5=9Bkiewicz?= <arekm at 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
index 00000000..6401a552
--- /dev/null
+++ b/0001-UBUNTU-SAUCE-efi-lockdown-MODSIGN-Fix-module-signatu.patch
@@ -0,0 +1,41 @@
+From 00c72bc198aa85e5da02de2c0c4cc423c82a54f1 Mon Sep 17 00:00:00 2001
+From: Fedora Kernel Team <kernel-team at 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 at 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
index 00000000..4d9836d9
--- /dev/null
+++ b/0002-apparmor-Fix-shadowed-local-variable-in-unpack_trans.patch
@@ -0,0 +1,51 @@
+From c6cad5e65a23dcafa1821ca381901297664d9c64 Mon Sep 17 00:00:00 2001
+From: Geert Uytterhoeven <geert at 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 at linux-m68k.org>
+Reviewed-by: Serge Hallyn <serge at hallyn.com>
+Signed-off-by: John Johansen <john.johansen at 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
index 00000000..be4f854c
--- /dev/null
+++ b/0003-apparmor-Fix-logical-error-in-verify_header.patch
@@ -0,0 +1,32 @@
+From 9934296cba701d429a0fc0cf071a40c8c3a1587e Mon Sep 17 00:00:00 2001
+From: Christos Gkekas <chris.gekas at 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 at gmail.com>
+Signed-off-by: John Johansen <john.johansen at 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
index 00000000..4e937e00
--- /dev/null
+++ b/0004-apparmor-Fix-an-error-code-in-aafs_create.patch
@@ -0,0 +1,37 @@
+From 8b3851c7b83f32f2be9d4b48371ddf033afedf62 Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter at 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 at oracle.com>
+Acked-by: Serge Hallyn <serge at hallyn.com>
+Signed-off-by: John Johansen <john.johansen at 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
index 00000000..beea3de9
--- /dev/null
+++ b/0005-apparmor-Redundant-condition-prev_ns.-in-label.c-149.patch
@@ -0,0 +1,29 @@
+From 4b56e146905bbad2c79ea92e3f49e210ca527572 Mon Sep 17 00:00:00 2001
+From: John Johansen <john.johansen at 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 at hotmail.com>
+Signed-off-by: John Johansen <john.johansen at 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
index 00000000..ee3672db
--- /dev/null
+++ b/0006-apparmor-add-the-ability-to-mediate-signals.patch
@@ -0,0 +1,397 @@
+From f9e20353a6c5726775867db81b6085e8ab425a36 Mon Sep 17 00:00:00 2001
+From: John Johansen <john.johansen at 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 at canonical.com>
+Acked-by: Seth Arnold <seth.arnold at 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
+
diff --git a/kernel-apparmor-mount.patch b/0007-apparmor-add-mount-mediation.patch
similarity index 50%
rename from kernel-apparmor-mount.patch
rename to 0007-apparmor-add-mount-mediation.patch
index 3c9a0978..99dac5c1 100644
--- a/kernel-apparmor-mount.patch
+++ b/0007-apparmor-add-mount-mediation.patch
@@ -1,124 +1,155 @@
-commit 4429c3f9522b608300cfe1ae148dc6cdadf3d76c
-Author: John Johansen <john.johansen at 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 at 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 at canonical.com>
-    Acked-by: Kees Cook <kees at 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 at canonical.com>
+Acked-by: Seth Arnold <seth.arnold at 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
index 00000000..20892df4
--- /dev/null
+++ b/0008-apparmor-cleanup-conditional-check-for-label-in-labe.patch
@@ -0,0 +1,71 @@
+From 763d17c9a18b0df7dbec2740f10dc40d378e3cc1 Mon Sep 17 00:00:00 2001
+From: John Johansen <john.johansen at 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 at canonical.com>
+Acked-by: Seth Arnold <seth.arnold at 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
index 00000000..84ee7a1d
--- /dev/null
+++ b/0009-apparmor-add-support-for-absolute-root-view-based-la.patch
@@ -0,0 +1,63 @@
+From 6b092bbbf9e17b10f709d11b3bc2d7e493617934 Mon Sep 17 00:00:00 2001
+From: John Johansen <john.johansen at 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 at canonical.com>
+Acked-by: Seth Arnold <seth.arnold at 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
index 00000000..7e481b28
--- /dev/null
+++ b/0010-apparmor-make-policy_unpack-able-to-audit-different-.patch
@@ -0,0 +1,219 @@
+From aa4b6bded85552bc5f9f22d2e18ce86c5c17947c Mon Sep 17 00:00:00 2001
+From: John Johansen <john.johansen at 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 at canonical.com>
+Acked-by: Seth Arnold <seth.arnold at 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
index 00000000..85eafc85
--- /dev/null
+++ b/0011-apparmor-add-more-debug-asserts-to-apparmorfs.patch
@@ -0,0 +1,78 @@
+From ba3f778a2ef31454032c2ca9c99d9212feb4dcf1 Mon Sep 17 00:00:00 2001
+From: John Johansen <john.johansen at 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 at canonical.com>
+Acked-by: Seth Arnold <seth.arnold at 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
index 00000000..2a29c960
--- /dev/null
+++ b/0012-apparmor-add-base-infastructure-for-socket-mediation.patch
@@ -0,0 +1,1123 @@
+From 853cbdfb6924857a2ee2a1cd5b9fa494f8e7efa2 Mon Sep 17 00:00:00 2001
+From: John Johansen <john.johansen at 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 at canonical.com>
+Acked-by: Seth Arnold <seth.arnold at 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
index 00000000..f1337f3c
--- /dev/null
+++ b/0013-apparmor-move-new_null_profile-to-after-profile-look.patch
@@ -0,0 +1,194 @@
+From 50d30adbef98a0b6cc531a9413d05f564eb633ee Mon Sep 17 00:00:00 2001
+From: John Johansen <john.johansen at 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 at 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
index 00000000..ae57b4bd
--- /dev/null
+++ b/0014-apparmor-fix-race-condition-in-null-profile-creation.patch
@@ -0,0 +1,60 @@
+From ab3b869791b6122c7be7e68ca4c08e2c2e8815ac Mon Sep 17 00:00:00 2001
+From: John Johansen <john.johansen at 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 at 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
index 00000000..1ceb9900
--- /dev/null
+++ b/0015-apparmor-ensure-unconfined-profiles-have-dfas-initia.patch
@@ -0,0 +1,36 @@
+From 7f2cdd6453518ff76c3855255c91306a2b928c9a Mon Sep 17 00:00:00 2001
+From: John Johansen <john.johansen at 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 at 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
index 00000000..9ff09f80
--- /dev/null
+++ b/0016-apparmor-fix-incorrect-type-assignment-when-freeing-.patch
@@ -0,0 +1,39 @@
+From 8daf877473653c06a28c86bf72d63ce7e5c1d542 Mon Sep 17 00:00:00 2001
+From: John Johansen <john.johansen at 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 at 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
index 00000000..5a1b2208
--- /dev/null
+++ b/0017-UBUNTU-SAUCE-apparmor-af_unix-mediation.patch
@@ -0,0 +1,1394 @@
+From a3b0cb6676a04cdad5cc357bc422d0398083b435 Mon Sep 17 00:00:00 2001
+From: John Johansen <john.johansen at 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 at 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)
++{
<Skipped 1891 lines>
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/kernel.git/commitdiff/daaa955e189a32b19c81af123dfa0306edfe9457



More information about the pld-cvs-commit mailing list