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