diff options
author | James Morris <jmorris@namei.org> | 2006-11-13 19:09:01 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-12-03 00:22:24 -0500 |
commit | 2ee92d46c6cabedd50edf6f273fa8cf84f707618 (patch) | |
tree | bdf7c64514a5063ba4ef41915f9efb6f803fc38a /security/selinux/hooks.c | |
parent | 90833aa4f496d69ca374af6acef7d1614c8693ff (diff) |
[SELinux]: Add support for DCCP
This patch implements SELinux kernel support for DCCP
(http://linux-net.osdl.org/index.php/DCCP), which is similar in
operation to TCP in terms of connected state between peers.
The SELinux support for DCCP is thus modeled on existing handling of
TCP.
A new DCCP socket class is introduced, to allow protocol
differentation. The permissions for this class inherit all of the
socket permissions, as well as the current TCP permissions (node_bind,
name_bind etc). IPv4 and IPv6 are supported, although labeled
networking is not, at this stage.
Patches for SELinux userspace are at:
http://people.redhat.com/jmorris/selinux/dccp/user/
I've performed some basic testing, and it seems to be working as
expected. Adding policy support is similar to TCP, the only real
difference being that it's a different protocol.
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r-- | security/selinux/hooks.c | 66 |
1 files changed, 58 insertions, 8 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 956137baf3e7..0cf98740ddc6 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -58,6 +58,7 @@ | |||
58 | #include <linux/netlink.h> | 58 | #include <linux/netlink.h> |
59 | #include <linux/tcp.h> | 59 | #include <linux/tcp.h> |
60 | #include <linux/udp.h> | 60 | #include <linux/udp.h> |
61 | #include <linux/dccp.h> | ||
61 | #include <linux/quota.h> | 62 | #include <linux/quota.h> |
62 | #include <linux/un.h> /* for Unix socket types */ | 63 | #include <linux/un.h> /* for Unix socket types */ |
63 | #include <net/af_unix.h> /* for Unix socket types */ | 64 | #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 | |||
751 | return SECCLASS_UDP_SOCKET; | 752 | return SECCLASS_UDP_SOCKET; |
752 | else | 753 | else |
753 | return SECCLASS_RAWIP_SOCKET; | 754 | return SECCLASS_RAWIP_SOCKET; |
755 | case SOCK_DCCP: | ||
756 | return SECCLASS_DCCP_SOCKET; | ||
754 | default: | 757 | default: |
755 | return SECCLASS_RAWIP_SOCKET; | 758 | return SECCLASS_RAWIP_SOCKET; |
756 | } | 759 | } |
@@ -2944,6 +2947,22 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb, | |||
2944 | break; | 2947 | break; |
2945 | } | 2948 | } |
2946 | 2949 | ||
2950 | case IPPROTO_DCCP: { | ||
2951 | struct dccp_hdr _dccph, *dh; | ||
2952 | |||
2953 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
2954 | break; | ||
2955 | |||
2956 | offset += ihlen; | ||
2957 | dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph); | ||
2958 | if (dh == NULL) | ||
2959 | break; | ||
2960 | |||
2961 | ad->u.net.sport = dh->dccph_sport; | ||
2962 | ad->u.net.dport = dh->dccph_dport; | ||
2963 | break; | ||
2964 | } | ||
2965 | |||
2947 | default: | 2966 | default: |
2948 | break; | 2967 | break; |
2949 | } | 2968 | } |
@@ -3004,6 +3023,18 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb, | |||
3004 | break; | 3023 | break; |
3005 | } | 3024 | } |
3006 | 3025 | ||
3026 | case IPPROTO_DCCP: { | ||
3027 | struct dccp_hdr _dccph, *dh; | ||
3028 | |||
3029 | dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph); | ||
3030 | if (dh == NULL) | ||
3031 | break; | ||
3032 | |||
3033 | ad->u.net.sport = dh->dccph_sport; | ||
3034 | ad->u.net.dport = dh->dccph_dport; | ||
3035 | break; | ||
3036 | } | ||
3037 | |||
3007 | /* includes fragments */ | 3038 | /* includes fragments */ |
3008 | default: | 3039 | default: |
3009 | break; | 3040 | break; |
@@ -3188,7 +3219,11 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
3188 | case SECCLASS_UDP_SOCKET: | 3219 | case SECCLASS_UDP_SOCKET: |
3189 | node_perm = UDP_SOCKET__NODE_BIND; | 3220 | node_perm = UDP_SOCKET__NODE_BIND; |
3190 | break; | 3221 | break; |
3191 | 3222 | ||
3223 | case SECCLASS_DCCP_SOCKET: | ||
3224 | node_perm = DCCP_SOCKET__NODE_BIND; | ||
3225 | break; | ||
3226 | |||
3192 | default: | 3227 | default: |
3193 | node_perm = RAWIP_SOCKET__NODE_BIND; | 3228 | node_perm = RAWIP_SOCKET__NODE_BIND; |
3194 | break; | 3229 | break; |
@@ -3226,16 +3261,17 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, | |||
3226 | return err; | 3261 | return err; |
3227 | 3262 | ||
3228 | /* | 3263 | /* |
3229 | * If a TCP socket, check name_connect permission for the port. | 3264 | * If a TCP or DCCP socket, check name_connect permission for the port. |
3230 | */ | 3265 | */ |
3231 | isec = SOCK_INODE(sock)->i_security; | 3266 | isec = SOCK_INODE(sock)->i_security; |
3232 | if (isec->sclass == SECCLASS_TCP_SOCKET) { | 3267 | if (isec->sclass == SECCLASS_TCP_SOCKET || |
3268 | isec->sclass == SECCLASS_DCCP_SOCKET) { | ||
3233 | struct sock *sk = sock->sk; | 3269 | struct sock *sk = sock->sk; |
3234 | struct avc_audit_data ad; | 3270 | struct avc_audit_data ad; |
3235 | struct sockaddr_in *addr4 = NULL; | 3271 | struct sockaddr_in *addr4 = NULL; |
3236 | struct sockaddr_in6 *addr6 = NULL; | 3272 | struct sockaddr_in6 *addr6 = NULL; |
3237 | unsigned short snum; | 3273 | unsigned short snum; |
3238 | u32 sid; | 3274 | u32 sid, perm; |
3239 | 3275 | ||
3240 | if (sk->sk_family == PF_INET) { | 3276 | if (sk->sk_family == PF_INET) { |
3241 | addr4 = (struct sockaddr_in *)address; | 3277 | addr4 = (struct sockaddr_in *)address; |
@@ -3254,11 +3290,13 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, | |||
3254 | if (err) | 3290 | if (err) |
3255 | goto out; | 3291 | goto out; |
3256 | 3292 | ||
3293 | perm = (isec->sclass == SECCLASS_TCP_SOCKET) ? | ||
3294 | TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT; | ||
3295 | |||
3257 | AVC_AUDIT_DATA_INIT(&ad,NET); | 3296 | AVC_AUDIT_DATA_INIT(&ad,NET); |
3258 | ad.u.net.dport = htons(snum); | 3297 | ad.u.net.dport = htons(snum); |
3259 | ad.u.net.family = sk->sk_family; | 3298 | ad.u.net.family = sk->sk_family; |
3260 | err = avc_has_perm(isec->sid, sid, isec->sclass, | 3299 | err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad); |
3261 | TCP_SOCKET__NAME_CONNECT, &ad); | ||
3262 | if (err) | 3300 | if (err) |
3263 | goto out; | 3301 | goto out; |
3264 | } | 3302 | } |
@@ -3446,7 +3484,13 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | |||
3446 | node_perm = NODE__TCP_RECV; | 3484 | node_perm = NODE__TCP_RECV; |
3447 | recv_perm = TCP_SOCKET__RECV_MSG; | 3485 | recv_perm = TCP_SOCKET__RECV_MSG; |
3448 | break; | 3486 | break; |
3449 | 3487 | ||
3488 | case SECCLASS_DCCP_SOCKET: | ||
3489 | netif_perm = NETIF__DCCP_RECV; | ||
3490 | node_perm = NODE__DCCP_RECV; | ||
3491 | recv_perm = DCCP_SOCKET__RECV_MSG; | ||
3492 | break; | ||
3493 | |||
3450 | default: | 3494 | default: |
3451 | netif_perm = NETIF__RAWIP_RECV; | 3495 | netif_perm = NETIF__RAWIP_RECV; |
3452 | node_perm = NODE__RAWIP_RECV; | 3496 | node_perm = NODE__RAWIP_RECV; |
@@ -3777,7 +3821,13 @@ static int selinux_ip_postroute_last_compat(struct sock *sk, struct net_device * | |||
3777 | node_perm = NODE__TCP_SEND; | 3821 | node_perm = NODE__TCP_SEND; |
3778 | send_perm = TCP_SOCKET__SEND_MSG; | 3822 | send_perm = TCP_SOCKET__SEND_MSG; |
3779 | break; | 3823 | break; |
3780 | 3824 | ||
3825 | case SECCLASS_DCCP_SOCKET: | ||
3826 | netif_perm = NETIF__DCCP_SEND; | ||
3827 | node_perm = NODE__DCCP_SEND; | ||
3828 | send_perm = DCCP_SOCKET__SEND_MSG; | ||
3829 | break; | ||
3830 | |||
3781 | default: | 3831 | default: |
3782 | netif_perm = NETIF__RAWIP_SEND; | 3832 | netif_perm = NETIF__RAWIP_SEND; |
3783 | node_perm = NODE__RAWIP_SEND; | 3833 | node_perm = NODE__RAWIP_SEND; |