From: Stephen Smalley This patch adds a name_connect permission check to SELinux to provide control over outbound TCP connections to particular ports distinct from the general controls over sending and receiving packets. Signed-off-by: Stephen Smalley Signed-off-by: James Morris Signed-off-by: Andrew Morton --- 25-akpm/security/selinux/hooks.c | 48 ++++++++++++++++++- 25-akpm/security/selinux/include/av_perm_to_string.h | 1 25-akpm/security/selinux/include/av_permissions.h | 1 3 files changed, 49 insertions(+), 1 deletion(-) diff -puN security/selinux/hooks.c~selinux-add-name_connect-permission-check security/selinux/hooks.c --- 25/security/selinux/hooks.c~selinux-add-name_connect-permission-check 2005-03-23 12:51:47.000000000 -0800 +++ 25-akpm/security/selinux/hooks.c 2005-03-23 12:51:47.000000000 -0800 @@ -3094,7 +3094,53 @@ out: static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen) { - return socket_has_perm(current, sock, SOCKET__CONNECT); + struct inode_security_struct *isec; + int err; + + err = socket_has_perm(current, sock, SOCKET__CONNECT); + if (err) + return err; + + /* + * If a TCP socket, check name_connect permission for the port. + */ + isec = SOCK_INODE(sock)->i_security; + if (isec->sclass == SECCLASS_TCP_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; + + if (sk->sk_family == PF_INET) { + addr4 = (struct sockaddr_in *)address; + if (addrlen != sizeof(struct sockaddr_in)) + return -EINVAL; + snum = ntohs(addr4->sin_port); + } else { + addr6 = (struct sockaddr_in6 *)address; + if (addrlen != sizeof(struct sockaddr_in6)) + return -EINVAL; + snum = ntohs(addr6->sin6_port); + } + + err = security_port_sid(sk->sk_family, sk->sk_type, + sk->sk_protocol, snum, &sid); + if (err) + goto out; + + 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); + if (err) + goto out; + } + +out: + return err; } static int selinux_socket_listen(struct socket *sock, int backlog) diff -puN security/selinux/include/av_permissions.h~selinux-add-name_connect-permission-check security/selinux/include/av_permissions.h --- 25/security/selinux/include/av_permissions.h~selinux-add-name_connect-permission-check 2005-03-23 12:51:47.000000000 -0800 +++ 25-akpm/security/selinux/include/av_permissions.h 2005-03-23 12:51:47.000000000 -0800 @@ -253,6 +253,7 @@ #define TCP_SOCKET__NEWCONN 0x00800000UL #define TCP_SOCKET__ACCEPTFROM 0x01000000UL #define TCP_SOCKET__NODE_BIND 0x02000000UL +#define TCP_SOCKET__NAME_CONNECT 0x04000000UL #define UDP_SOCKET__IOCTL 0x00000001UL #define UDP_SOCKET__READ 0x00000002UL diff -puN security/selinux/include/av_perm_to_string.h~selinux-add-name_connect-permission-check security/selinux/include/av_perm_to_string.h --- 25/security/selinux/include/av_perm_to_string.h~selinux-add-name_connect-permission-check 2005-03-23 12:51:47.000000000 -0800 +++ 25-akpm/security/selinux/include/av_perm_to_string.h 2005-03-23 12:51:47.000000000 -0800 @@ -25,6 +25,7 @@ S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__NEWCONN, "newconn") S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__ACCEPTFROM, "acceptfrom") S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__NODE_BIND, "node_bind") + S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__NAME_CONNECT, "name_connect") S_(SECCLASS_UDP_SOCKET, UDP_SOCKET__NODE_BIND, "node_bind") S_(SECCLASS_RAWIP_SOCKET, RAWIP_SOCKET__NODE_BIND, "node_bind") S_(SECCLASS_NODE, NODE__TCP_RECV, "tcp_recv") _