Merge branch 'smack-for-3.20-rebased' of git://git.gitorious.org/smack-next/kernel...
authorJames Morris <james.l.morris@oracle.com>
Thu, 22 Jan 2015 02:22:23 +0000 (13:22 +1100)
committerJames Morris <james.l.morris@oracle.com>
Thu, 22 Jan 2015 02:22:23 +0000 (13:22 +1100)
security/smack/Kconfig
security/smack/Makefile
security/smack/smack.h
security/smack/smack_lsm.c
security/smack/smack_netfilter.c [new file with mode: 0644]

index b065f97..271adae 100644 (file)
@@ -28,3 +28,15 @@ config SECURITY_SMACK_BRINGUP
          access rule set once the behavior is well understood.
          This is a superior mechanism to the oft abused
          "permissive" mode of other systems.
+         If you are unsure how to answer this question, answer N.
+
+config SECURITY_SMACK_NETFILTER
+       bool "Packet marking using secmarks for netfilter"
+       depends on SECURITY_SMACK
+       depends on NETWORK_SECMARK
+       depends on NETFILTER
+       default n
+       help
+         This enables security marking of network packets using
+         Smack labels.
+         If you are unsure how to answer this question, answer N.
index 67a63aa..616cf93 100644 (file)
@@ -5,3 +5,4 @@
 obj-$(CONFIG_SECURITY_SMACK) := smack.o
 
 smack-y := smack_lsm.o smack_access.o smackfs.o
+smack-$(CONFIG_NETFILTER) += smack_netfilter.o
index b828a37..67ccb7b 100644 (file)
@@ -248,6 +248,7 @@ struct smack_known *smk_find_entry(const char *);
 /*
  * Shared data.
  */
+extern int smack_enabled;
 extern int smack_cipso_direct;
 extern int smack_cipso_mapped;
 extern struct smack_known *smack_net_ambient;
@@ -298,6 +299,16 @@ static inline struct smack_known *smk_of_task(const struct task_smack *tsp)
        return tsp->smk_task;
 }
 
+static inline struct smack_known *smk_of_task_struct(const struct task_struct *t)
+{
+       struct smack_known *skp;
+
+       rcu_read_lock();
+       skp = smk_of_task(__task_cred(t)->security);
+       rcu_read_unlock();
+       return skp;
+}
+
 /*
  * Present a pointer to the forked smack label entry in an task blob.
  */
index f1b17a4..a0ccce4 100644 (file)
@@ -43,8 +43,6 @@
 #include <linux/binfmts.h>
 #include "smack.h"
 
-#define task_security(task)    (task_cred_xxx((task), security))
-
 #define TRANS_TRUE     "TRUE"
 #define TRANS_TRUE_SIZE        4
 
 #define SMK_RECEIVING  1
 #define SMK_SENDING    2
 
+#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
 LIST_HEAD(smk_ipv6_port_list);
+#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
 static struct kmem_cache *smack_inode_cache;
+int smack_enabled;
 
 #ifdef CONFIG_SECURITY_SMACK_BRINGUP
 static void smk_bu_mode(int mode, char *s)
@@ -120,7 +121,7 @@ static int smk_bu_current(char *note, struct smack_known *oskp,
 static int smk_bu_task(struct task_struct *otp, int mode, int rc)
 {
        struct task_smack *tsp = current_security();
-       struct task_smack *otsp = task_security(otp);
+       struct smack_known *smk_task = smk_of_task_struct(otp);
        char acc[SMK_NUM_ACCESS_TYPE + 1];
 
        if (rc <= 0)
@@ -128,7 +129,7 @@ static int smk_bu_task(struct task_struct *otp, int mode, int rc)
 
        smk_bu_mode(mode, acc);
        pr_info("Smack Bringup: (%s %s %s) %s to %s\n",
-               tsp->smk_task->smk_known, otsp->smk_task->smk_known, acc,
+               tsp->smk_task->smk_known, smk_task->smk_known, acc,
                current->comm, otp->comm);
        return 0;
 }
@@ -160,7 +161,7 @@ static int smk_bu_file(struct file *file, int mode, int rc)
 {
        struct task_smack *tsp = current_security();
        struct smack_known *sskp = tsp->smk_task;
-       struct inode *inode = file->f_inode;
+       struct inode *inode = file_inode(file);
        char acc[SMK_NUM_ACCESS_TYPE + 1];
 
        if (rc <= 0)
@@ -168,7 +169,7 @@ static int smk_bu_file(struct file *file, int mode, int rc)
 
        smk_bu_mode(mode, acc);
        pr_info("Smack Bringup: (%s %s %s) file=(%s %ld %pD) %s\n",
-               sskp->smk_known, (char *)file->f_security, acc,
+               sskp->smk_known, smk_of_inode(inode)->smk_known, acc,
                inode->i_sb->s_id, inode->i_ino, file,
                current->comm);
        return 0;
@@ -202,6 +203,7 @@ static int smk_bu_credfile(const struct cred *cred, struct file *file,
 
 /**
  * smk_fetch - Fetch the smack label from a file.
+ * @name: type of the label (attribute)
  * @ip: a pointer to the inode
  * @dp: a pointer to the dentry
  *
@@ -254,7 +256,9 @@ struct inode_smack *new_inode_smack(struct smack_known *skp)
 
 /**
  * new_task_smack - allocate a task security blob
- * @smack: a pointer to the Smack label to use in the blob
+ * @task: a pointer to the Smack label for the running task
+ * @forked: a pointer to the Smack label for the forked task
+ * @gfp: type of the memory for the allocation
  *
  * Returns the new blob or NULL if there's no memory available
  */
@@ -277,8 +281,9 @@ static struct task_smack *new_task_smack(struct smack_known *task,
 
 /**
  * smk_copy_rules - copy a rule set
- * @nhead - new rules header pointer
- * @ohead - old rules header pointer
+ * @nhead: new rules header pointer
+ * @ohead: old rules header pointer
+ * @gfp: type of the memory for the allocation
  *
  * Returns 0 on success, -ENOMEM on error
  */
@@ -345,7 +350,8 @@ static int smk_ptrace_rule_check(struct task_struct *tracer,
                saip = &ad;
        }
 
-       tsp = task_security(tracer);
+       rcu_read_lock();
+       tsp = __task_cred(tracer)->security;
        tracer_known = smk_of_task(tsp);
 
        if ((mode & PTRACE_MODE_ATTACH) &&
@@ -365,11 +371,14 @@ static int smk_ptrace_rule_check(struct task_struct *tracer,
                                  tracee_known->smk_known,
                                  0, rc, saip);
 
+               rcu_read_unlock();
                return rc;
        }
 
        /* In case of rule==SMACK_PTRACE_DEFAULT or mode==PTRACE_MODE_READ */
        rc = smk_tskacc(tsp, tracee_known, smk_ptrace_mode(mode), saip);
+
+       rcu_read_unlock();
        return rc;
 }
 
@@ -396,7 +405,7 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
        if (rc != 0)
                return rc;
 
-       skp = smk_of_task(task_security(ctp));
+       skp = smk_of_task_struct(ctp);
 
        rc = smk_ptrace_rule_check(current, skp, mode, __func__);
        return rc;
@@ -796,7 +805,7 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
        if (name)
                *name = XATTR_SMACK_SUFFIX;
 
-       if (value) {
+       if (value && len) {
                rcu_read_lock();
                may = smk_access_entry(skp->smk_known, dsp->smk_known,
                                       &skp->smk_rules);
@@ -817,10 +826,9 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
                *value = kstrdup(isp->smk_known, GFP_NOFS);
                if (*value == NULL)
                        return -ENOMEM;
-       }
 
-       if (len)
                *len = strlen(isp->smk_known);
+       }
 
        return 0;
 }
@@ -1344,6 +1352,9 @@ static int smack_file_permission(struct file *file, int mask)
  * The security blob for a file is a pointer to the master
  * label list, so no allocation is done.
  *
+ * f_security is the owner security information. It
+ * isn't used on file access checks, it's for send_sigio.
+ *
  * Returns 0
  */
 static int smack_file_alloc_security(struct file *file)
@@ -1381,17 +1392,18 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd,
 {
        int rc = 0;
        struct smk_audit_info ad;
+       struct inode *inode = file_inode(file);
 
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
        smk_ad_setfield_u_fs_path(&ad, file->f_path);
 
        if (_IOC_DIR(cmd) & _IOC_WRITE) {
-               rc = smk_curacc(file->f_security, MAY_WRITE, &ad);
+               rc = smk_curacc(smk_of_inode(inode), MAY_WRITE, &ad);
                rc = smk_bu_file(file, MAY_WRITE, rc);
        }
 
        if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ)) {
-               rc = smk_curacc(file->f_security, MAY_READ, &ad);
+               rc = smk_curacc(smk_of_inode(inode), MAY_READ, &ad);
                rc = smk_bu_file(file, MAY_READ, rc);
        }
 
@@ -1409,10 +1421,11 @@ static int smack_file_lock(struct file *file, unsigned int cmd)
 {
        struct smk_audit_info ad;
        int rc;
+       struct inode *inode = file_inode(file);
 
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
        smk_ad_setfield_u_fs_path(&ad, file->f_path);
-       rc = smk_curacc(file->f_security, MAY_LOCK, &ad);
+       rc = smk_curacc(smk_of_inode(inode), MAY_LOCK, &ad);
        rc = smk_bu_file(file, MAY_LOCK, rc);
        return rc;
 }
@@ -1434,7 +1447,7 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,
 {
        struct smk_audit_info ad;
        int rc = 0;
-
+       struct inode *inode = file_inode(file);
 
        switch (cmd) {
        case F_GETLK:
@@ -1443,14 +1456,14 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,
        case F_SETLKW:
                smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
                smk_ad_setfield_u_fs_path(&ad, file->f_path);
-               rc = smk_curacc(file->f_security, MAY_LOCK, &ad);
+               rc = smk_curacc(smk_of_inode(inode), MAY_LOCK, &ad);
                rc = smk_bu_file(file, MAY_LOCK, rc);
                break;
        case F_SETOWN:
        case F_SETSIG:
                smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
                smk_ad_setfield_u_fs_path(&ad, file->f_path);
-               rc = smk_curacc(file->f_security, MAY_WRITE, &ad);
+               rc = smk_curacc(smk_of_inode(inode), MAY_WRITE, &ad);
                rc = smk_bu_file(file, MAY_WRITE, rc);
                break;
        default:
@@ -1568,14 +1581,10 @@ static int smack_mmap_file(struct file *file,
  * smack_file_set_fowner - set the file security blob value
  * @file: object in question
  *
- * Returns 0
- * Further research may be required on this one.
  */
 static void smack_file_set_fowner(struct file *file)
 {
-       struct smack_known *skp = smk_of_current();
-
-       file->f_security = skp;
+       file->f_security = smk_of_current();
 }
 
 /**
@@ -1627,6 +1636,7 @@ static int smack_file_receive(struct file *file)
        int rc;
        int may = 0;
        struct smk_audit_info ad;
+       struct inode *inode = file_inode(file);
 
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
        smk_ad_setfield_u_fs_path(&ad, file->f_path);
@@ -1638,7 +1648,7 @@ static int smack_file_receive(struct file *file)
        if (file->f_mode & FMODE_WRITE)
                may |= MAY_WRITE;
 
-       rc = smk_curacc(file->f_security, may, &ad);
+       rc = smk_curacc(smk_of_inode(inode), may, &ad);
        rc = smk_bu_file(file, may, rc);
        return rc;
 }
@@ -1658,21 +1668,17 @@ static int smack_file_receive(struct file *file)
 static int smack_file_open(struct file *file, const struct cred *cred)
 {
        struct task_smack *tsp = cred->security;
-       struct inode_smack *isp = file_inode(file)->i_security;
+       struct inode *inode = file_inode(file);
        struct smk_audit_info ad;
        int rc;
 
-       if (smack_privileged(CAP_MAC_OVERRIDE)) {
-               file->f_security = isp->smk_inode;
+       if (smack_privileged(CAP_MAC_OVERRIDE))
                return 0;
-       }
 
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
        smk_ad_setfield_u_fs_path(&ad, file->f_path);
-       rc = smk_access(tsp->smk_task, isp->smk_inode, MAY_READ, &ad);
+       rc = smk_access(tsp->smk_task, smk_of_inode(inode), MAY_READ, &ad);
        rc = smk_bu_credfile(cred, file, MAY_READ, rc);
-       if (rc == 0)
-               file->f_security = isp->smk_inode;
 
        return rc;
 }
@@ -1826,7 +1832,7 @@ static int smk_curacc_on_task(struct task_struct *p, int access,
                                const char *caller)
 {
        struct smk_audit_info ad;
-       struct smack_known *skp = smk_of_task(task_security(p));
+       struct smack_known *skp = smk_of_task_struct(p);
        int rc;
 
        smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK);
@@ -1879,7 +1885,7 @@ static int smack_task_getsid(struct task_struct *p)
  */
 static void smack_task_getsecid(struct task_struct *p, u32 *secid)
 {
-       struct smack_known *skp = smk_of_task(task_security(p));
+       struct smack_known *skp = smk_of_task_struct(p);
 
        *secid = skp->smk_secid;
 }
@@ -1986,7 +1992,7 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
 {
        struct smk_audit_info ad;
        struct smack_known *skp;
-       struct smack_known *tkp = smk_of_task(task_security(p));
+       struct smack_known *tkp = smk_of_task_struct(p);
        int rc;
 
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
@@ -2040,7 +2046,7 @@ static int smack_task_wait(struct task_struct *p)
 static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
 {
        struct inode_smack *isp = inode->i_security;
-       struct smack_known *skp = smk_of_task(task_security(p));
+       struct smack_known *skp = smk_of_task_struct(p);
 
        isp->smk_inode = skp;
 }
@@ -2212,6 +2218,7 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
        return smack_netlabel(sk, sk_lbl);
 }
 
+#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
 /**
  * smk_ipv6_port_label - Smack port access table management
  * @sock: socket
@@ -2361,6 +2368,7 @@ auditout:
        rc = smk_bu_note("IPv6 port check", skp, object, MAY_WRITE, rc);
        return rc;
 }
+#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
 
 /**
  * smack_inode_setsecurity - set smack xattrs
@@ -2421,8 +2429,10 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
        } else
                return -EOPNOTSUPP;
 
+#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
        if (sock->sk->sk_family == PF_INET6)
                smk_ipv6_port_label(sock, NULL);
+#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
 
        return 0;
 }
@@ -2450,6 +2460,7 @@ static int smack_socket_post_create(struct socket *sock, int family,
        return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
 }
 
+#ifndef CONFIG_SECURITY_SMACK_NETFILTER
 /**
  * smack_socket_bind - record port binding information.
  * @sock: the socket
@@ -2463,11 +2474,14 @@ static int smack_socket_post_create(struct socket *sock, int family,
 static int smack_socket_bind(struct socket *sock, struct sockaddr *address,
                                int addrlen)
 {
+#if IS_ENABLED(CONFIG_IPV6)
        if (sock->sk != NULL && sock->sk->sk_family == PF_INET6)
                smk_ipv6_port_label(sock, address);
+#endif
 
        return 0;
 }
+#endif /* !CONFIG_SECURITY_SMACK_NETFILTER */
 
 /**
  * smack_socket_connect - connect access check
@@ -2496,8 +2510,10 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,
        case PF_INET6:
                if (addrlen < sizeof(struct sockaddr_in6))
                        return -EINVAL;
+#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
                rc = smk_ipv6_port_check(sock->sk, (struct sockaddr_in6 *)sap,
                                                SMK_CONNECTING);
+#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
                break;
        }
        return rc;
@@ -3033,7 +3049,8 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
         * of the superblock.
         */
        if (opt_dentry->d_parent == opt_dentry) {
-               if (sbp->s_magic == CGROUP_SUPER_MAGIC) {
+               switch (sbp->s_magic) {
+               case CGROUP_SUPER_MAGIC:
                        /*
                         * The cgroup filesystem is never mounted,
                         * so there's no opportunity to set the mount
@@ -3041,8 +3058,19 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
                         */
                        sbsp->smk_root = &smack_known_star;
                        sbsp->smk_default = &smack_known_star;
+                       isp->smk_inode = sbsp->smk_root;
+                       break;
+               case TMPFS_MAGIC:
+                       /*
+                        * What about shmem/tmpfs anonymous files with dentry
+                        * obtained from d_alloc_pseudo()?
+                        */
+                       isp->smk_inode = smk_of_current();
+                       break;
+               default:
+                       isp->smk_inode = sbsp->smk_root;
+                       break;
                }
-               isp->smk_inode = sbsp->smk_root;
                isp->smk_flags |= SMK_INODE_INSTANT;
                goto unlockandout;
        }
@@ -3200,7 +3228,7 @@ unlockandout:
  */
 static int smack_getprocattr(struct task_struct *p, char *name, char **value)
 {
-       struct smack_known *skp = smk_of_task(task_security(p));
+       struct smack_known *skp = smk_of_task_struct(p);
        char *cp;
        int slen;
 
@@ -3297,7 +3325,7 @@ static int smack_unix_stream_connect(struct sock *sock,
 
        if (!smack_privileged(CAP_MAC_OVERRIDE)) {
                skp = ssp->smk_out;
-               okp = osp->smk_out;
+               okp = osp->smk_in;
 #ifdef CONFIG_AUDIT
                smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
                smk_ad_setfield_u_net_sk(&ad, other);
@@ -3305,7 +3333,9 @@ static int smack_unix_stream_connect(struct sock *sock,
                rc = smk_access(skp, okp, MAY_WRITE, &ad);
                rc = smk_bu_note("UDS connect", skp, okp, MAY_WRITE, rc);
                if (rc == 0) {
-                       rc = smk_access(okp, skp, MAY_WRITE, NULL);
+                       okp = osp->smk_out;
+                       skp = ssp->smk_in;
+                       rc = smk_access(okp, skp, MAY_WRITE, &ad);
                        rc = smk_bu_note("UDS connect", okp, skp,
                                                MAY_WRITE, rc);
                }
@@ -3366,7 +3396,9 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
                                int size)
 {
        struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name;
+#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
        struct sockaddr_in6 *sap = (struct sockaddr_in6 *) msg->msg_name;
+#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
        int rc = 0;
 
        /*
@@ -3380,7 +3412,9 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
                rc = smack_netlabel_send(sock->sk, sip);
                break;
        case AF_INET6:
+#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
                rc = smk_ipv6_port_check(sock->sk, sap, SMK_SENDING);
+#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
                break;
        }
        return rc;
@@ -3471,6 +3505,7 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap,
        return smack_net_ambient;
 }
 
+#if IS_ENABLED(CONFIG_IPV6)
 static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr_in6 *sip)
 {
        u8 nexthdr;
@@ -3517,6 +3552,7 @@ static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr_in6 *sip)
        }
        return proto;
 }
+#endif /* CONFIG_IPV6 */
 
 /**
  * smack_socket_sock_rcv_skb - Smack packet delivery access check
@@ -3529,15 +3565,30 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
        struct netlbl_lsm_secattr secattr;
        struct socket_smack *ssp = sk->sk_security;
-       struct smack_known *skp;
-       struct sockaddr_in6 sadd;
+       struct smack_known *skp = NULL;
        int rc = 0;
        struct smk_audit_info ad;
 #ifdef CONFIG_AUDIT
        struct lsm_network_audit net;
 #endif
+#if IS_ENABLED(CONFIG_IPV6)
+       struct sockaddr_in6 sadd;
+       int proto;
+#endif /* CONFIG_IPV6 */
+
        switch (sk->sk_family) {
        case PF_INET:
+#ifdef CONFIG_SECURITY_SMACK_NETFILTER
+               /*
+                * If there is a secmark use it rather than the CIPSO label.
+                * If there is no secmark fall back to CIPSO.
+                * The secmark is assumed to reflect policy better.
+                */
+               if (skb && skb->secmark != 0) {
+                       skp = smack_from_secid(skb->secmark);
+                       goto access_check;
+               }
+#endif /* CONFIG_SECURITY_SMACK_NETFILTER */
                /*
                 * Translate what netlabel gave us.
                 */
@@ -3551,6 +3602,9 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
 
                netlbl_secattr_destroy(&secattr);
 
+#ifdef CONFIG_SECURITY_SMACK_NETFILTER
+access_check:
+#endif
 #ifdef CONFIG_AUDIT
                smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
                ad.a.u.net->family = sk->sk_family;
@@ -3569,14 +3623,32 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
                if (rc != 0)
                        netlbl_skbuff_err(skb, rc, 0);
                break;
+#if IS_ENABLED(CONFIG_IPV6)
        case PF_INET6:
-               rc = smk_skb_to_addr_ipv6(skb, &sadd);
-               if (rc == IPPROTO_UDP || rc == IPPROTO_TCP)
-                       rc = smk_ipv6_port_check(sk, &sadd, SMK_RECEIVING);
+               proto = smk_skb_to_addr_ipv6(skb, &sadd);
+               if (proto != IPPROTO_UDP && proto != IPPROTO_TCP)
+                       break;
+#ifdef CONFIG_SECURITY_SMACK_NETFILTER
+               if (skb && skb->secmark != 0)
+                       skp = smack_from_secid(skb->secmark);
                else
-                       rc = 0;
+                       skp = smack_net_ambient;
+#ifdef CONFIG_AUDIT
+               smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
+               ad.a.u.net->family = sk->sk_family;
+               ad.a.u.net->netif = skb->skb_iif;
+               ipv6_skb_to_auditdata(skb, &ad.a, NULL);
+#endif /* CONFIG_AUDIT */
+               rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad);
+               rc = smk_bu_note("IPv6 delivery", skp, ssp->smk_in,
+                                       MAY_WRITE, rc);
+#else /* CONFIG_SECURITY_SMACK_NETFILTER */
+               rc = smk_ipv6_port_check(sk, &sadd, SMK_RECEIVING);
+#endif /* CONFIG_SECURITY_SMACK_NETFILTER */
                break;
+#endif /* CONFIG_IPV6 */
        }
+
        return rc;
 }
 
@@ -3638,16 +3710,25 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
        if (skb != NULL) {
                if (skb->protocol == htons(ETH_P_IP))
                        family = PF_INET;
+#if IS_ENABLED(CONFIG_IPV6)
                else if (skb->protocol == htons(ETH_P_IPV6))
                        family = PF_INET6;
+#endif /* CONFIG_IPV6 */
        }
        if (family == PF_UNSPEC && sock != NULL)
                family = sock->sk->sk_family;
 
-       if (family == PF_UNIX) {
+       switch (family) {
+       case PF_UNIX:
                ssp = sock->sk->sk_security;
                s = ssp->smk_out->smk_secid;
-       } else if (family == PF_INET || family == PF_INET6) {
+               break;
+       case PF_INET:
+#ifdef CONFIG_SECURITY_SMACK_NETFILTER
+               s = skb->secmark;
+               if (s != 0)
+                       break;
+#endif
                /*
                 * Translate what netlabel gave us.
                 */
@@ -3660,6 +3741,14 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
                        s = skp->smk_secid;
                }
                netlbl_secattr_destroy(&secattr);
+               break;
+#if IS_ENABLED(CONFIG_IPV6)
+       case PF_INET6:
+#ifdef CONFIG_SECURITY_SMACK_NETFILTER
+               s = skb->secmark;
+#endif /* CONFIG_SECURITY_SMACK_NETFILTER */
+               break;
+#endif /* CONFIG_IPV6 */
        }
        *secid = s;
        if (s == 0)
@@ -3715,6 +3804,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
        struct lsm_network_audit net;
 #endif
 
+#if IS_ENABLED(CONFIG_IPV6)
        if (family == PF_INET6) {
                /*
                 * Handle mapped IPv4 packets arriving
@@ -3726,6 +3816,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
                else
                        return 0;
        }
+#endif /* CONFIG_IPV6 */
 
        netlbl_secattr_init(&secattr);
        rc = netlbl_skbuff_getattr(skb, family, &secattr);
@@ -3834,11 +3925,11 @@ static void smack_key_free(struct key *key)
        key->security = NULL;
 }
 
-/*
+/**
  * smack_key_permission - Smack access on a key
  * @key_ref: gets to the object
  * @cred: the credentials to use
- * @perm: unused
+ * @perm: requested key permissions
  *
  * Return 0 if the task has read and write to the object,
  * an error code otherwise
@@ -4184,7 +4275,9 @@ struct security_operations smack_ops = {
        .unix_may_send =                smack_unix_may_send,
 
        .socket_post_create =           smack_socket_post_create,
+#ifndef CONFIG_SECURITY_SMACK_NETFILTER
        .socket_bind =                  smack_socket_bind,
+#endif /* CONFIG_SECURITY_SMACK_NETFILTER */
        .socket_connect =               smack_socket_connect,
        .socket_sendmsg =               smack_socket_sendmsg,
        .socket_sock_rcv_skb =          smack_socket_sock_rcv_skb,
@@ -4265,6 +4358,8 @@ static __init int smack_init(void)
        if (!security_module_enable(&smack_ops))
                return 0;
 
+       smack_enabled = 1;
+
        smack_inode_cache = KMEM_CACHE(inode_smack, 0);
        if (!smack_inode_cache)
                return -ENOMEM;
diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c
new file mode 100644 (file)
index 0000000..c952632
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ *  Simplified MAC Kernel (smack) security module
+ *
+ *  This file contains the Smack netfilter implementation
+ *
+ *  Author:
+ *     Casey Schaufler <casey@schaufler-ca.com>
+ *
+ *  Copyright (C) 2014 Casey Schaufler <casey@schaufler-ca.com>
+ *  Copyright (C) 2014 Intel Corporation.
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2,
+ *     as published by the Free Software Foundation.
+ */
+
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv6.h>
+#include <linux/netdevice.h>
+#include "smack.h"
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+
+static unsigned int smack_ipv6_output(const struct nf_hook_ops *ops,
+                                       struct sk_buff *skb,
+                                       const struct net_device *in,
+                                       const struct net_device *out,
+                                       int (*okfn)(struct sk_buff *))
+{
+       struct socket_smack *ssp;
+       struct smack_known *skp;
+
+       if (skb && skb->sk && skb->sk->sk_security) {
+               ssp = skb->sk->sk_security;
+               skp = ssp->smk_out;
+               skb->secmark = skp->smk_secid;
+       }
+
+       return NF_ACCEPT;
+}
+#endif /* IPV6 */
+
+static unsigned int smack_ipv4_output(const struct nf_hook_ops *ops,
+                                       struct sk_buff *skb,
+                                       const struct net_device *in,
+                                       const struct net_device *out,
+                                       int (*okfn)(struct sk_buff *))
+{
+       struct socket_smack *ssp;
+       struct smack_known *skp;
+
+       if (skb && skb->sk && skb->sk->sk_security) {
+               ssp = skb->sk->sk_security;
+               skp = ssp->smk_out;
+               skb->secmark = skp->smk_secid;
+       }
+
+       return NF_ACCEPT;
+}
+
+static struct nf_hook_ops smack_nf_ops[] = {
+       {
+               .hook =         smack_ipv4_output,
+               .owner =        THIS_MODULE,
+               .pf =           NFPROTO_IPV4,
+               .hooknum =      NF_INET_LOCAL_OUT,
+               .priority =     NF_IP_PRI_SELINUX_FIRST,
+       },
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       {
+               .hook =         smack_ipv6_output,
+               .owner =        THIS_MODULE,
+               .pf =           NFPROTO_IPV6,
+               .hooknum =      NF_INET_LOCAL_OUT,
+               .priority =     NF_IP6_PRI_SELINUX_FIRST,
+       },
+#endif /* IPV6 */
+};
+
+static int __init smack_nf_ip_init(void)
+{
+       int err;
+
+       if (smack_enabled == 0)
+               return 0;
+
+       printk(KERN_DEBUG "Smack: Registering netfilter hooks\n");
+
+       err = nf_register_hooks(smack_nf_ops, ARRAY_SIZE(smack_nf_ops));
+       if (err)
+               pr_info("Smack: nf_register_hooks: error %d\n", err);
+
+       return 0;
+}
+
+__initcall(smack_nf_ip_init);