aboutsummaryrefslogtreecommitdiffstats
path: root/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/smack/0001-Smack-Local-IPv6-port-based-controls.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-rcar-gen2/recipes-kernel/linux/linux-renesas/smack/0001-Smack-Local-IPv6-port-based-controls.patch')
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/smack/0001-Smack-Local-IPv6-port-based-controls.patch509
1 files changed, 509 insertions, 0 deletions
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/smack/0001-Smack-Local-IPv6-port-based-controls.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/smack/0001-Smack-Local-IPv6-port-based-controls.patch
new file mode 100644
index 0000000..d41501b
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/smack/0001-Smack-Local-IPv6-port-based-controls.patch
@@ -0,0 +1,509 @@
+From 2a16c72fa63c1de2e5c591f0afe5b575cac3b237 Mon Sep 17 00:00:00 2001
+From: Casey Schaufler <casey@schaufler-ca.com>
+Date: Wed, 22 May 2013 18:42:56 -0700
+Subject: [PATCH 01/54] Smack: Local IPv6 port based controls
+
+Smack does not provide access controls on IPv6 communications.
+This patch introduces a mechanism for maintaining Smack lables
+for local IPv6 communications. It is based on labeling local ports.
+The behavior should be compatible with any future "real" IPv6
+support as it provides no interfaces for users to manipulate
+the labeling. Remote IPv6 connections use the ambient label
+the same way that unlabeled IPv4 packets are treated.
+
+Targeted for git://git.gitorious.org/smack-next/kernel.git
+
+Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
+---
+ security/smack/smack.h | 11 ++
+ security/smack/smack_lsm.c | 348 +++++++++++++++++++++++++++++++++++++++------
+ 2 files changed, 319 insertions(+), 40 deletions(-)
+
+diff --git a/security/smack/smack.h b/security/smack/smack.h
+index 8ad3095..bb28e09 100644
+--- a/security/smack/smack.h
++++ b/security/smack/smack.h
+@@ -94,6 +94,17 @@ struct smk_netlbladdr {
+ };
+
+ /*
++ * An entry in the table identifying ports.
++ */
++struct smk_port_label {
++ struct list_head list;
++ struct sock *smk_sock; /* socket initialized on */
++ unsigned short smk_port; /* the port number */
++ char *smk_in; /* incoming label */
++ char *smk_out; /* outgoing label */
++};
++
++/*
+ * This is the repository for labels seen so that it is
+ * not necessary to keep allocating tiny chuncks of memory
+ * and so that they can be shared.
+diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
+index d52c780..609e89d 100644
+--- a/security/smack/smack_lsm.c
++++ b/security/smack/smack_lsm.c
+@@ -27,10 +27,13 @@
+ #include <linux/ip.h>
+ #include <linux/tcp.h>
+ #include <linux/udp.h>
++#include <linux/dccp.h>
+ #include <linux/slab.h>
+ #include <linux/mutex.h>
+ #include <linux/pipe_fs_i.h>
+ #include <net/cipso_ipv4.h>
++#include <net/ip.h>
++#include <net/ipv6.h>
+ #include <linux/audit.h>
+ #include <linux/magic.h>
+ #include <linux/dcache.h>
+@@ -45,6 +48,12 @@
+ #define TRANS_TRUE "TRUE"
+ #define TRANS_TRUE_SIZE 4
+
++#define SMK_CONNECTING 0
++#define SMK_RECEIVING 1
++#define SMK_SENDING 2
++
++LIST_HEAD(smk_ipv6_port_list);
++
+ /**
+ * smk_fetch - Fetch the smack label from a file.
+ * @ip: a pointer to the inode
+@@ -1878,6 +1887,155 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
+ }
+
+ /**
++ * smk_ipv6_port_label - Smack port access table management
++ * @sock: socket
++ * @address: address
++ *
++ * Create or update the port list entry
++ */
++static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address)
++{
++ struct sock *sk = sock->sk;
++ struct sockaddr_in6 *addr6;
++ struct socket_smack *ssp = sock->sk->sk_security;
++ struct smk_port_label *spp;
++ unsigned short port = 0;
++
++ if (address == NULL) {
++ /*
++ * This operation is changing the Smack information
++ * on the bound socket. Take the changes to the port
++ * as well.
++ */
++ list_for_each_entry(spp, &smk_ipv6_port_list, list) {
++ if (sk != spp->smk_sock)
++ continue;
++ spp->smk_in = ssp->smk_in;
++ spp->smk_out = ssp->smk_out;
++ return;
++ }
++ /*
++ * A NULL address is only used for updating existing
++ * bound entries. If there isn't one, it's OK.
++ */
++ return;
++ }
++
++ addr6 = (struct sockaddr_in6 *)address;
++ port = ntohs(addr6->sin6_port);
++ /*
++ * This is a special case that is safely ignored.
++ */
++ if (port == 0)
++ return;
++
++ /*
++ * Look for an existing port list entry.
++ * This is an indication that a port is getting reused.
++ */
++ list_for_each_entry(spp, &smk_ipv6_port_list, list) {
++ if (spp->smk_port != port)
++ continue;
++ spp->smk_port = port;
++ spp->smk_sock = sk;
++ spp->smk_in = ssp->smk_in;
++ spp->smk_out = ssp->smk_out;
++ return;
++ }
++
++ /*
++ * A new port entry is required.
++ */
++ spp = kzalloc(sizeof(*spp), GFP_KERNEL);
++ if (spp == NULL)
++ return;
++
++ spp->smk_port = port;
++ spp->smk_sock = sk;
++ spp->smk_in = ssp->smk_in;
++ spp->smk_out = ssp->smk_out;
++
++ list_add(&spp->list, &smk_ipv6_port_list);
++ return;
++}
++
++/**
++ * smk_ipv6_port_check - check Smack port access
++ * @sock: socket
++ * @address: address
++ *
++ * Create or update the port list entry
++ */
++static int smk_ipv6_port_check(struct sock *sk, struct sockaddr *address,
++ int act)
++{
++ __be16 *bep;
++ __be32 *be32p;
++ struct sockaddr_in6 *addr6;
++ struct smk_port_label *spp;
++ struct socket_smack *ssp = sk->sk_security;
++ unsigned short port = 0;
++ char *subject;
++ char *object;
++ struct smk_audit_info ad;
++#ifdef CONFIG_AUDIT
++ struct lsm_network_audit net;
++#endif
++
++ if (act == SMK_RECEIVING) {
++ subject = smack_net_ambient;
++ object = ssp->smk_in;
++ } else {
++ subject = ssp->smk_out;
++ object = smack_net_ambient;
++ }
++
++ /*
++ * Get the IP address and port from the address.
++ */
++ addr6 = (struct sockaddr_in6 *)address;
++ port = ntohs(addr6->sin6_port);
++ bep = (__be16 *)(&addr6->sin6_addr);
++ be32p = (__be32 *)(&addr6->sin6_addr);
++
++ /*
++ * It's remote, so port lookup does no good.
++ */
++ if (be32p[0] || be32p[1] || be32p[2] || bep[6] || ntohs(bep[7]) != 1)
++ goto auditout;
++
++ /*
++ * It's local so the send check has to have passed.
++ */
++ if (act == SMK_RECEIVING) {
++ subject = smack_known_web.smk_known;
++ goto auditout;
++ }
++
++ list_for_each_entry(spp, &smk_ipv6_port_list, list) {
++ if (spp->smk_port != port)
++ continue;
++ object = spp->smk_in;
++ if (act == SMK_CONNECTING)
++ ssp->smk_packet = spp->smk_out;
++ break;
++ }
++
++auditout:
++
++#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->dport = port;
++ if (act == SMK_RECEIVING)
++ ad.a.u.net->v6info.saddr = addr6->sin6_addr;
++ else
++ ad.a.u.net->v6info.daddr = addr6->sin6_addr;
++#endif
++ return smk_access(subject, object, MAY_WRITE, &ad);
++}
++
++/**
+ * smack_inode_setsecurity - set smack xattrs
+ * @inode: the object
+ * @name: attribute name
+@@ -1926,7 +2084,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
+ ssp->smk_in = sp;
+ else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) {
+ ssp->smk_out = sp;
+- if (sock->sk->sk_family != PF_UNIX) {
++ if (sock->sk->sk_family == PF_INET) {
+ rc = smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
+ if (rc != 0)
+ printk(KERN_WARNING
+@@ -1936,6 +2094,9 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
+ } else
+ return -EOPNOTSUPP;
+
++ if (sock->sk->sk_family == PF_INET6)
++ smk_ipv6_port_label(sock, NULL);
++
+ return 0;
+ }
+
+@@ -1963,6 +2124,25 @@ static int smack_socket_post_create(struct socket *sock, int family,
+ }
+
+ /**
++ * smack_socket_bind - record port binding information.
++ * @sock: the socket
++ * @address: the port address
++ * @addrlen: size of the address
++ *
++ * Records the label bound to a port.
++ *
++ * Returns 0
++ */
++static int smack_socket_bind(struct socket *sock, struct sockaddr *address,
++ int addrlen)
++{
++ if (sock->sk != NULL && sock->sk->sk_family == PF_INET6)
++ smk_ipv6_port_label(sock, address);
++
++ return 0;
++}
++
++/**
+ * smack_socket_connect - connect access check
+ * @sock: the socket
+ * @sap: the other end
+@@ -1975,12 +2155,24 @@ static int smack_socket_post_create(struct socket *sock, int family,
+ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,
+ int addrlen)
+ {
+- if (sock->sk == NULL || sock->sk->sk_family != PF_INET)
++ int rc = 0;
++
++ if (sock->sk == NULL)
+ return 0;
+- if (addrlen < sizeof(struct sockaddr_in))
+- return -EINVAL;
+
+- return smack_netlabel_send(sock->sk, (struct sockaddr_in *)sap);
++ switch (sock->sk->sk_family) {
++ case PF_INET:
++ if (addrlen < sizeof(struct sockaddr_in))
++ return -EINVAL;
++ rc = smack_netlabel_send(sock->sk, (struct sockaddr_in *)sap);
++ break;
++ case PF_INET6:
++ if (addrlen < sizeof(struct sockaddr_in6))
++ return -EINVAL;
++ rc = smk_ipv6_port_check(sock->sk, sap, SMK_CONNECTING);
++ break;
++ }
++ return rc;
+ }
+
+ /**
+@@ -2792,22 +2984,32 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
+ * @msg: the message
+ * @size: the size of the message
+ *
+- * Return 0 if the current subject can write to the destination
+- * host. This is only a question if the destination is a single
+- * label host.
++ * Return 0 if the current subject can write to the destination host.
++ * For IPv4 this is only a question if the destination is a single label host.
++ * For IPv6 this is a check against the label of the port.
+ */
+ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
+ int size)
+ {
+ struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name;
++ struct sockaddr *sap = (struct sockaddr *) msg->msg_name;
++ int rc = 0;
+
+ /*
+ * Perfectly reasonable for this to be NULL
+ */
+- if (sip == NULL || sip->sin_family != AF_INET)
++ if (sip == NULL)
+ return 0;
+
+- return smack_netlabel_send(sock->sk, sip);
++ switch (sip->sin_family) {
++ case AF_INET:
++ rc = smack_netlabel_send(sock->sk, sip);
++ break;
++ case AF_INET6:
++ rc = smk_ipv6_port_check(sock->sk, sap, SMK_SENDING);
++ break;
++ }
++ return rc;
+ }
+
+ /**
+@@ -2878,6 +3080,54 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap,
+ return smack_net_ambient;
+ }
+
++static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr *sap)
++{
++ struct sockaddr_in6 *sip = (struct sockaddr_in6 *)sap;
++ u8 nexthdr;
++ int offset;
++ int proto = -EINVAL;
++ struct ipv6hdr _ipv6h;
++ struct ipv6hdr *ip6;
++ __be16 frag_off;
++ struct tcphdr _tcph, *th;
++ struct udphdr _udph, *uh;
++ struct dccp_hdr _dccph, *dh;
++
++ sip->sin6_port = 0;
++
++ offset = skb_network_offset(skb);
++ ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
++ if (ip6 == NULL)
++ return -EINVAL;
++ sip->sin6_addr = ip6->saddr;
++
++ nexthdr = ip6->nexthdr;
++ offset += sizeof(_ipv6h);
++ offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off);
++ if (offset < 0)
++ return -EINVAL;
++
++ proto = nexthdr;
++ switch (proto) {
++ case IPPROTO_TCP:
++ th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
++ if (th != NULL)
++ sip->sin6_port = th->source;
++ break;
++ case IPPROTO_UDP:
++ uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
++ if (uh != NULL)
++ sip->sin6_port = uh->source;
++ break;
++ case IPPROTO_DCCP:
++ dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
++ if (dh != NULL)
++ sip->sin6_port = dh->dccph_sport;
++ break;
++ }
++ return proto;
++}
++
+ /**
+ * smack_socket_sock_rcv_skb - Smack packet delivery access check
+ * @sk: socket
+@@ -2889,43 +3139,52 @@ 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 sockaddr sadd;
+ char *csp;
+- int rc;
++ int rc = 0;
+ struct smk_audit_info ad;
+ #ifdef CONFIG_AUDIT
+ struct lsm_network_audit net;
+ #endif
+- if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
+- return 0;
+-
+- /*
+- * Translate what netlabel gave us.
+- */
+- netlbl_secattr_init(&secattr);
++ switch (sk->sk_family) {
++ case PF_INET:
++ /*
++ * Translate what netlabel gave us.
++ */
++ netlbl_secattr_init(&secattr);
+
+- rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr);
+- if (rc == 0)
+- csp = smack_from_secattr(&secattr, ssp);
+- else
+- csp = smack_net_ambient;
++ rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr);
++ if (rc == 0)
++ csp = smack_from_secattr(&secattr, ssp);
++ else
++ csp = smack_net_ambient;
+
+- netlbl_secattr_destroy(&secattr);
++ netlbl_secattr_destroy(&secattr);
+
+ #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;
+- ipv4_skb_to_auditdata(skb, &ad.a, NULL);
++ 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;
++ ipv4_skb_to_auditdata(skb, &ad.a, NULL);
+ #endif
+- /*
+- * Receiving a packet requires that the other end
+- * be able to write here. Read access is not required.
+- * This is the simplist possible security model
+- * for networking.
+- */
+- rc = smk_access(csp, ssp->smk_in, MAY_WRITE, &ad);
+- if (rc != 0)
+- netlbl_skbuff_err(skb, rc, 0);
++ /*
++ * Receiving a packet requires that the other end
++ * be able to write here. Read access is not required.
++ * This is the simplist possible security model
++ * for networking.
++ */
++ rc = smk_access(csp, ssp->smk_in, MAY_WRITE, &ad);
++ if (rc != 0)
++ netlbl_skbuff_err(skb, rc, 0);
++ break;
++ 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);
++ else
++ rc = 0;
++ break;
++ }
+ return rc;
+ }
+
+@@ -3063,9 +3322,17 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
+ struct lsm_network_audit net;
+ #endif
+
+- /* handle mapped IPv4 packets arriving via IPv6 sockets */
+- if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
+- family = PF_INET;
++ if (family == PF_INET6) {
++ /*
++ * Handle mapped IPv4 packets arriving
++ * via IPv6 sockets. Don't set up netlabel
++ * processing on IPv6.
++ */
++ if (skb->protocol == htons(ETH_P_IP))
++ family = PF_INET;
++ else
++ return 0;
++ }
+
+ netlbl_secattr_init(&secattr);
+ rc = netlbl_skbuff_getattr(skb, family, &secattr);
+@@ -3498,6 +3765,7 @@ struct security_operations smack_ops = {
+ .unix_may_send = smack_unix_may_send,
+
+ .socket_post_create = smack_socket_post_create,
++ .socket_bind = smack_socket_bind,
+ .socket_connect = smack_socket_connect,
+ .socket_sendmsg = smack_socket_sendmsg,
+ .socket_sock_rcv_skb = smack_socket_sock_rcv_skb,
+--
+2.1.4
+