]> err.no Git - linux-2.6/blobdiff - security/selinux/hooks.c
[SELinux]: Add support for DCCP
[linux-2.6] / security / selinux / hooks.c
index 956137baf3e76771924f5e98a89ed296c6eaccef..0cf98740ddc6efb51d482638b2cf387eea0410b4 100644 (file)
@@ -58,6 +58,7 @@
 #include <linux/netlink.h>
 #include <linux/tcp.h>
 #include <linux/udp.h>
+#include <linux/dccp.h>
 #include <linux/quota.h>
 #include <linux/un.h>          /* for Unix socket types */
 #include <net/af_unix.h>       /* for Unix socket types */
@@ -751,6 +752,8 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc
                                return SECCLASS_UDP_SOCKET;
                        else
                                return SECCLASS_RAWIP_SOCKET;
+               case SOCK_DCCP:
+                       return SECCLASS_DCCP_SOCKET;
                default:
                        return SECCLASS_RAWIP_SOCKET;
                }
@@ -2944,6 +2947,22 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb,
                break;
         }
 
+       case IPPROTO_DCCP: {
+               struct dccp_hdr _dccph, *dh;
+
+               if (ntohs(ih->frag_off) & IP_OFFSET)
+                       break;
+
+               offset += ihlen;
+               dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
+               if (dh == NULL)
+                       break;
+
+               ad->u.net.sport = dh->dccph_sport;
+               ad->u.net.dport = dh->dccph_dport;
+               break;
+        }
+
         default:
                break;
         }
@@ -3004,6 +3023,18 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb,
                break;
        }
 
+       case IPPROTO_DCCP: {
+               struct dccp_hdr _dccph, *dh;
+
+               dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
+               if (dh == NULL)
+                       break;
+
+               ad->u.net.sport = dh->dccph_sport;
+               ad->u.net.dport = dh->dccph_dport;
+               break;
+        }
+
        /* includes fragments */
        default:
                break;
@@ -3188,7 +3219,11 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                case SECCLASS_UDP_SOCKET:
                        node_perm = UDP_SOCKET__NODE_BIND;
                        break;
-                       
+
+               case SECCLASS_DCCP_SOCKET:
+                       node_perm = DCCP_SOCKET__NODE_BIND;
+                       break;
+
                default:
                        node_perm = RAWIP_SOCKET__NODE_BIND;
                        break;
@@ -3226,16 +3261,17 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
                return err;
 
        /*
-        * If a TCP socket, check name_connect permission for the port.
+        * If a TCP or DCCP socket, check name_connect permission for the port.
         */
        isec = SOCK_INODE(sock)->i_security;
-       if (isec->sclass == SECCLASS_TCP_SOCKET) {
+       if (isec->sclass == SECCLASS_TCP_SOCKET ||
+           isec->sclass == SECCLASS_DCCP_SOCKET) {
                struct sock *sk = sock->sk;
                struct avc_audit_data ad;
                struct sockaddr_in *addr4 = NULL;
                struct sockaddr_in6 *addr6 = NULL;
                unsigned short snum;
-               u32 sid;
+               u32 sid, perm;
 
                if (sk->sk_family == PF_INET) {
                        addr4 = (struct sockaddr_in *)address;
@@ -3254,11 +3290,13 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
                if (err)
                        goto out;
 
+               perm = (isec->sclass == SECCLASS_TCP_SOCKET) ?
+                      TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
+
                AVC_AUDIT_DATA_INIT(&ad,NET);
                ad.u.net.dport = htons(snum);
                ad.u.net.family = sk->sk_family;
-               err = avc_has_perm(isec->sid, sid, isec->sclass,
-                                  TCP_SOCKET__NAME_CONNECT, &ad);
+               err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad);
                if (err)
                        goto out;
        }
@@ -3446,7 +3484,13 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
                node_perm = NODE__TCP_RECV;
                recv_perm = TCP_SOCKET__RECV_MSG;
                break;
-       
+
+       case SECCLASS_DCCP_SOCKET:
+               netif_perm = NETIF__DCCP_RECV;
+               node_perm = NODE__DCCP_RECV;
+               recv_perm = DCCP_SOCKET__RECV_MSG;
+               break;
+
        default:
                netif_perm = NETIF__RAWIP_RECV;
                node_perm = NODE__RAWIP_RECV;
@@ -3777,7 +3821,13 @@ static int selinux_ip_postroute_last_compat(struct sock *sk, struct net_device *
                node_perm = NODE__TCP_SEND;
                send_perm = TCP_SOCKET__SEND_MSG;
                break;
-       
+
+       case SECCLASS_DCCP_SOCKET:
+               netif_perm = NETIF__DCCP_SEND;
+               node_perm = NODE__DCCP_SEND;
+               send_perm = DCCP_SOCKET__SEND_MSG;
+               break;
+
        default:
                netif_perm = NETIF__RAWIP_SEND;
                node_perm = NODE__RAWIP_SEND;