#
 # Generated include files
 #
+net_names.h
 capability_names.h
 rlim_names.h
 
 
 apparmor-y := apparmorfs.o audit.o capability.o task.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
            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
 $(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)
 
        AA_SFS_FILE_BOOLEAN("v5",       1),
        AA_SFS_FILE_BOOLEAN("v6",       1),
        AA_SFS_FILE_BOOLEAN("v7",       1),
+       AA_SFS_FILE_BOOLEAN("v8",       1),
        { }
 };
 
        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_v8",                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),
 
 #include "include/cred.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"
        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
                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();
 
 
 #define AA_CLASS_UNKNOWN       1
 #define AA_CLASS_FILE          2
 #define AA_CLASS_CAP           3
-#define AA_CLASS_NET           4
+#define AA_CLASS_DEPRECATED    4
 #define AA_CLASS_RLIMITS       5
 #define AA_CLASS_DOMAIN                6
 #define AA_CLASS_MOUNT         7
 #define AA_CLASS_PTRACE                9
 #define AA_CLASS_SIGNAL                10
+#define AA_CLASS_NET           14
 #define AA_CLASS_LABEL         16
 
 #define AA_CLASS_LAST          AA_CLASS_LABEL
 
                                        int signal;
                                        int unmappedsig;
                                };
+                               struct {
+                                       int type, protocol;
+                                       struct sock *peer_sk;
+                                       void *addr;
+                                       int addrlen;
+                               } net;
                        };
                };
                struct {
 
--- /dev/null
+/*
+ * 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;
+};
+
+#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)
+
+
+#define af_select(FAMILY, FN, DEF_FN)          \
+({                                             \
+       int __e;                                \
+       switch ((FAMILY)) {                     \
+       default:                                \
+               __e = DEF_FN;                   \
+       }                                       \
+       __e;                                    \
+})
+
+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);
+
+#endif /* __AA_NET_H */
 
 
 
 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,
 
 #include "file.h"
 #include "lib.h"
 #include "label.h"
+#include "net.h"
 #include "perms.h"
 #include "resource.h"
 
        return 0;
 }
 
+static inline unsigned int PROFILE_MEDIATES_AF(struct aa_profile *profile,
+                                              u16 AF) {
+       unsigned int state = PROFILE_MEDIATES(profile, AA_CLASS_NET);
+       __be16 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)
 
        *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;
 }
 
 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];
 
 
 #include "include/cred.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"
        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);
+       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);
+}
+
+/**
+ * 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;
+
+       AA_BUG(in_interrupt());
+
+       label = begin_current_label_crit_section();
+       if (!(kern || unconfined(label)))
+               error = af_select(family,
+                                 create_perm(label, family, type, protocol),
+                                 aa_af_perm(label, OP_CREATE, AA_MAY_CREATE,
+                                            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 af_select(sock->sk->sk_family,
+                        bind_perm(sock, address, addrlen),
+                        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 af_select(sock->sk->sk_family,
+                        connect_perm(sock, address, addrlen),
+                        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 af_select(sock->sk->sk_family,
+                        listen_perm(sock, backlog),
+                        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 af_select(sock->sk->sk_family,
+                        accept_perm(sock, newsock),
+                        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 af_select(sock->sk->sk_family,
+                        msg_perm(op, request, sock, msg, size),
+                        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 af_select(sock->sk->sk_family,
+                        sock_perm(op, request, sock),
+                        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 af_select(sock->sk->sk_family,
+                        opt_perm(op, request, sock, level, optname),
+                        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),
        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),
 
--- /dev/null
+/*
+ * 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/cred.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 = { };
+       unsigned int state;
+       __be16 buffer[2];
+
+       AA_BUG(family >= AF_MAX);
+       AA_BUG(type < 0 || type >= SOCK_MAX);
+
+       if (profile_unconfined(profile))
+               return 0;
+       state = PROFILE_MEDIATES(profile, AA_CLASS_NET);
+       if (!state)
+               return 0;
+
+       buffer[0] = cpu_to_be16(family);
+       buffer[1] = cpu_to_be16((u16) type);
+       state = aa_dfa_match_len(profile->policy.dfa, state, (char *) &buffer,
+                                4);
+       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);
+}
+
+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);
+}
 
 
 #define v5     5       /* base version */
 #define v6     6       /* per entry policydb mediation check */
-#define v7     7       /* full network masking */
+#define v7     7
+#define v8     8       /* full network masking */
 
 /*
  * The AppArmor interface treats data as a type byte followed by the