]> git.hungrycats.org Git - linux/commitdiff
[NET]: Add sock_create_kern()
authorJames Morris <jmorris@redhat.com>
Sat, 8 May 2004 08:00:33 +0000 (01:00 -0700)
committerDavid S. Miller <davem@nuts.davemloft.net>
Sat, 8 May 2004 08:00:33 +0000 (01:00 -0700)
Under SELinux, and potentially other LSMs, we need to be able to
distinguish between user sockets and kernel sockets.  For SELinux
specifically, kernel sockets need to be specially labeled during creation,
then bypass access control checks (they are controlled by the kernel
itself and not subject to SELinux mediation).

This addresses a class of potential issues in SELinux where, for example,
a TCP NFS session times out, then the kernel re-establishes an RPC
connection upon further user activity.  We do not want such kernel
created sockets to be labeled with user security contexts.

sock_create() and sock_create_kern() are wrapper functions, which seems
semantically clearer to me than e.g. adding a flag to sock_create().  If
you prefer the latter, then let me know.

The patch also adds an argument to the LSM socket creation functions
indicating whether the socket being created is a kernel socket or not.

19 files changed:
fs/cifs/connect.c
include/linux/net.h
include/linux/security.h
net/bluetooth/rfcomm/core.c
net/econet/af_econet.c
net/ipv4/icmp.c
net/ipv4/ipvs/ip_vs_sync.c
net/ipv4/tcp_ipv4.c
net/ipv6/icmp.c
net/ipv6/mcast.c
net/ipv6/ndisc.c
net/netlink/netlink_dev.c
net/rxrpc/transport.c
net/sctp/protocol.c
net/socket.c
net/sunrpc/svcsock.c
net/sunrpc/xprt.c
security/dummy.c
security/selinux/hooks.c

index f3634a91c93c73c350b42407c71caf2bfaf05a5f..b36e95ab46ae749ee2d7ff32aa83092cc35c9134 100644 (file)
@@ -900,7 +900,7 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
        unsigned short int orig_port = 0;
 
        if(*csocket == NULL) {
-               rc = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
+               rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
                if (rc < 0) {
                        cERROR(1, ("Error %d creating socket",rc));
                        *csocket = NULL;
@@ -1007,7 +1007,7 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
        int connected = 0;
 
        if(*csocket == NULL) {
-               rc = sock_create(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
+               rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
                if (rc < 0) {
                        cERROR(1, ("Error %d creating ipv6 socket",rc));
                        *csocket = NULL;
index 859c519eda8d10803d83d6d4b16fa597a3f43c5e..6f7846c15e08e01a5d9b360e0c1df7afb72efc27 100644 (file)
@@ -149,6 +149,8 @@ extern int       sock_unregister(int family);
 extern struct socket *sock_alloc(void);
 extern int          sock_create(int family, int type, int proto,
                                 struct socket **res);
+extern int          sock_create_kern(int family, int type, int proto,
+                                     struct socket **res);
 extern void         sock_release(struct socket *sock);
 extern int          sock_sendmsg(struct socket *sock, struct msghdr *msg,
                                  size_t len);
index 5bc1ac328495e9935300c8573f44665ca82ffc19..df0089af8ad6f8c027e946533470ca0ebe682275 100644 (file)
@@ -680,6 +680,7 @@ struct swap_info_struct;
  *     @family contains the requested protocol family.
  *     @type contains the requested communications type.
  *     @protocol contains the requested protocol.
+ *     @kern set to 1 if a kernel socket.
  *     Return 0 if permission is granted.
  * @socket_post_create:
  *     This hook allows a module to update or allocate a per-socket security
@@ -694,6 +695,7 @@ struct swap_info_struct;
  *     @family contains the requested protocol family.
  *     @type contains the requested communications type.
  *     @protocol contains the requested protocol.
+ *     @kern set to 1 if a kernel socket.
  * @socket_bind:
  *     Check permission before socket protocol layer bind operation is
  *     performed and the socket @sock is bound to the address specified in the
@@ -1198,9 +1200,9 @@ struct security_operations {
                                    struct socket * other, struct sock * newsk);
        int (*unix_may_send) (struct socket * sock, struct socket * other);
 
-       int (*socket_create) (int family, int type, int protocol);
+       int (*socket_create) (int family, int type, int protocol, int kern);
        void (*socket_post_create) (struct socket * sock, int family,
-                                   int type, int protocol);
+                                   int type, int protocol, int kern);
        int (*socket_bind) (struct socket * sock,
                            struct sockaddr * address, int addrlen);
        int (*socket_connect) (struct socket * sock,
@@ -2526,17 +2528,19 @@ static inline int security_unix_may_send(struct socket * sock,
        return security_ops->unix_may_send(sock, other);
 }
 
-static inline int security_socket_create (int family, int type, int protocol)
+static inline int security_socket_create (int family, int type,
+                                         int protocol, int kern)
 {
-       return security_ops->socket_create(family, type, protocol);
+       return security_ops->socket_create(family, type, protocol, kern);
 }
 
 static inline void security_socket_post_create(struct socket * sock, 
                                               int family,
                                               int type, 
-                                              int protocol)
+                                              int protocol, int kern)
 {
-       security_ops->socket_post_create(sock, family, type, protocol);
+       security_ops->socket_post_create(sock, family, type,
+                                        protocol, kern);
 }
 
 static inline int security_socket_bind(struct socket * sock, 
@@ -2645,7 +2649,8 @@ static inline int security_unix_may_send(struct socket * sock,
        return 0;
 }
 
-static inline int security_socket_create (int family, int type, int protocol)
+static inline int security_socket_create (int family, int type,
+                                         int protocol, int kern)
 {
        return 0;
 }
@@ -2653,7 +2658,7 @@ static inline int security_socket_create (int family, int type, int protocol)
 static inline void security_socket_post_create(struct socket * sock, 
                                               int family,
                                               int type, 
-                                              int protocol)
+                                              int protocol, int kern)
 {
 }
 
index 8ac33f3b0ebe523664948ab5bba17f28232e7c17..665564beee21bd29b19f63aaeb46756a43a607cf 100644 (file)
@@ -158,7 +158,8 @@ static int rfcomm_l2sock_create(struct socket **sock)
 
        BT_DBG("");
 
-       err = sock_create(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP, sock);
+       err = sock_create_kern(PF_BLUETOOTH, SOCK_SEQPACKET,
+                              BTPROTO_L2CAP, sock);
        if (!err) {
                struct sock *sk = (*sock)->sk;
                sk->sk_data_ready   = rfcomm_l2data_ready;
index ddd470edb9c915426593731ab6a0ba5fff4485ac..b503ae3b40e8066cb546994da989c74edc11c409 100644 (file)
@@ -976,7 +976,7 @@ static int __init aun_udp_initialise(void)
 
        /* We can count ourselves lucky Acorn machines are too dim to
           speak IPv6. :-) */
-       if ((error = sock_create(PF_INET, SOCK_DGRAM, 0, &udpsock)) < 0)
+       if ((error = sock_create_kern(PF_INET, SOCK_DGRAM, 0, &udpsock)) < 0)
        {
                printk("AUN: socket error %d\n", -error);
                return error;
index 530cfcd6ccf4160cfda606a065510ef6530bbe95..f3b54930368c38eefaf01364b6e9c4ae6503edea 100644 (file)
@@ -1108,8 +1108,8 @@ void __init icmp_init(struct net_proto_family *ops)
                if (!cpu_possible(i))
                        continue;
 
-               err = sock_create(PF_INET, SOCK_RAW, IPPROTO_ICMP,
-                                 &per_cpu(__icmp_socket, i));
+               err = sock_create_kern(PF_INET, SOCK_RAW, IPPROTO_ICMP,
+                                      &per_cpu(__icmp_socket, i));
 
                if (err < 0)
                        panic("Failed to create the ICMP control socket.\n");
index 8178b22cf307d52b310040e81774ff9714d362f0..7b727a92b9d7866d7526594294d139fe1941b335 100644 (file)
@@ -480,7 +480,7 @@ static struct socket * make_send_sock(void)
        struct socket *sock;
 
        /* First create a socket */
-       if (sock_create(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock) < 0) {
+       if (sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock) < 0) {
                IP_VS_ERR("Error during creation of socket; terminating\n");
                return NULL;
        }
@@ -521,7 +521,7 @@ static struct socket * make_receive_sock(void)
        struct socket *sock;
 
        /* First create a socket */
-       if (sock_create(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock) < 0) {
+       if (sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock) < 0) {
                IP_VS_ERR("Error during creation of socket; terminating\n");
                return NULL;
        }
index 0bcfdea3f50313ddda83785cf2c725cf312b5e18..ac92115041faaf7c1fede03c2f9594137872a13f 100644 (file)
@@ -2609,7 +2609,7 @@ struct proto tcp_prot = {
 
 void __init tcp_v4_init(struct net_proto_family *ops)
 {
-       int err = sock_create(PF_INET, SOCK_RAW, IPPROTO_TCP, &tcp_socket);
+       int err = sock_create_kern(PF_INET, SOCK_RAW, IPPROTO_TCP, &tcp_socket);
        if (err < 0)
                panic("Failed to create the TCP control socket.\n");
        tcp_socket->sk->sk_allocation   = GFP_ATOMIC;
index cc153c21fbafe3ea136dfb25ba41f88cf00d0b42..24e3def47237022b3fec75a03f19e2bc81e0c65a 100644 (file)
@@ -682,8 +682,8 @@ int __init icmpv6_init(struct net_proto_family *ops)
                if (!cpu_possible(i))
                        continue;
 
-               err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6,
-                                 &per_cpu(__icmpv6_socket, i));
+               err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6,
+                                      &per_cpu(__icmpv6_socket, i));
                if (err < 0) {
                        printk(KERN_ERR
                               "Failed to initialize the ICMP6 control socket "
index c7ad98b4218243bd8b878fa4d116740cfc243e23..a94f3c0affe05310f8cbc349b204adf67145420d 100644 (file)
@@ -2452,7 +2452,7 @@ int __init igmp6_init(struct net_proto_family *ops)
        struct sock *sk;
        int err;
 
-       err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &igmp6_socket);
+       err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &igmp6_socket);
        if (err < 0) {
                printk(KERN_ERR
                       "Failed to initialize the IGMP6 control socket (err %d).\n",
index 6b34ed27fca47284ba10dd7f00bfe883fdd73196..3de845af29df1c0d760a23b68ae2b2b851621e23 100644 (file)
@@ -1443,7 +1443,7 @@ int __init ndisc_init(struct net_proto_family *ops)
        struct sock *sk;
         int err;
 
-       err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &ndisc_socket);
+       err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &ndisc_socket);
        if (err < 0) {
                ND_PRINTK0(KERN_ERR
                           "ICMPv6 NDISC: Failed to initialize the control socket (err %d).\n", 
index c4edc886876d1556cc7da9c329a85b0c99967544..bf5d86a27a3272fa32c2aa5d6f4900ccb33bb91b 100644 (file)
@@ -112,7 +112,7 @@ static int netlink_open(struct inode * inode, struct file * file)
        if (test_and_set_bit(minor, &open_map))
                return -EBUSY;
 
-       err = sock_create(PF_NETLINK, SOCK_RAW, minor, &sock);
+       err = sock_create_kern(PF_NETLINK, SOCK_RAW, minor, &sock);
        if (err < 0)
                goto out;
 
index f53284d8fdc4d3879599ce1ebaee57aa32517703..4454c5938014b803c7da0b9fd6d65f2c2c143332 100644 (file)
@@ -86,7 +86,7 @@ int rxrpc_create_transport(unsigned short port,
        trans->port = port;
 
        /* create a UDP socket to be my actual transport endpoint */
-       ret = sock_create(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &trans->socket);
+       ret = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &trans->socket);
        if (ret < 0)
                goto error;
 
index ffd064dd99251cd3c1328695020c072fd2e5fe5e..fbc958a75ea4a7ae066b1138f69de99cca6d2478 100644 (file)
@@ -653,8 +653,8 @@ int sctp_ctl_sock_init(void)
        else
                family = PF_INET;
 
-       err = sock_create(family, SOCK_SEQPACKET, IPPROTO_SCTP,
-                         &sctp_ctl_socket);
+       err = sock_create_kern(family, SOCK_SEQPACKET, IPPROTO_SCTP,
+                              &sctp_ctl_socket);
        if (err < 0) {
                printk(KERN_ERR
                       "SCTP: Failed to create the SCTP control socket.\n");
index 312de3b6b45c4acb48cc6271576333db82469779..f4ef38250280815af1370f8e1f2bf29350c3144e 100644 (file)
@@ -983,8 +983,7 @@ int sock_wake_async(struct socket *sock, int how, int band)
        return 0;
 }
 
-
-int sock_create(int family, int type, int protocol, struct socket **res)
+static int __sock_create(int family, int type, int protocol, struct socket **res, int kern)
 {
        int i;
        int err;
@@ -1012,7 +1011,7 @@ int sock_create(int family, int type, int protocol, struct socket **res)
                family = PF_PACKET;
        }
 
-       err = security_socket_create(family, type, protocol);
+       err = security_socket_create(family, type, protocol, kern);
        if (err)
                return err;
                
@@ -1075,7 +1074,7 @@ int sock_create(int family, int type, int protocol, struct socket **res)
         */
        module_put(net_families[family]->owner);
        *res = sock;
-       security_socket_post_create(sock, family, type, protocol);
+       security_socket_post_create(sock, family, type, protocol, kern);
 
 out:
        net_family_read_unlock();
@@ -1087,6 +1086,16 @@ out_release:
        goto out;
 }
 
+int sock_create(int family, int type, int protocol, struct socket **res)
+{
+       return __sock_create(family, type, protocol, res, 0);
+}
+
+int sock_create_kern(int family, int type, int protocol, struct socket **res)
+{
+       return __sock_create(family, type, protocol, res, 1);
+}
+
 asmlinkage long sys_socket(int family, int type, int protocol)
 {
        int retval;
@@ -1991,6 +2000,7 @@ EXPORT_SYMBOL(move_addr_to_user);
 EXPORT_SYMBOL(sock_alloc);
 EXPORT_SYMBOL(sock_alloc_inode);
 EXPORT_SYMBOL(sock_create);
+EXPORT_SYMBOL(sock_create_kern);
 EXPORT_SYMBOL(sock_map_fd);
 EXPORT_SYMBOL(sock_recvmsg);
 EXPORT_SYMBOL(sock_register);
index 3152928c756e752ec5190025925779a566b51130..dd199ccbb78a25e5a06b9dfda344cc1a389dbe47 100644 (file)
@@ -1413,7 +1413,7 @@ svc_create_socket(struct svc_serv *serv, int protocol, struct sockaddr_in *sin)
        }
        type = (protocol == IPPROTO_UDP)? SOCK_DGRAM : SOCK_STREAM;
 
-       if ((error = sock_create(PF_INET, type, protocol, &sock)) < 0)
+       if ((error = sock_create_kern(PF_INET, type, protocol, &sock)) < 0)
                return error;
 
        if (sin != NULL) {
index 757f39cf1f364582bc7ac8f6f67f54e349a33b33..f02f9e259a903fd313de487d95e93084d1469662 100644 (file)
@@ -1567,7 +1567,7 @@ static struct socket * xprt_create_socket(struct rpc_xprt *xprt, int proto, int
 
        type = (proto == IPPROTO_UDP)? SOCK_DGRAM : SOCK_STREAM;
 
-       if ((err = sock_create(PF_INET, type, proto, &sock)) < 0) {
+       if ((err = sock_create_kern(PF_INET, type, proto, &sock)) < 0) {
                printk("RPC: can't create socket (%d).\n", -err);
                return NULL;
        }
index 4e12451e8a744fee4578d0c76f4b46d6a578e0ab..2a3ca3c7677a143b11d693ae81243da4315ff8d6 100644 (file)
@@ -750,13 +750,14 @@ static int dummy_unix_may_send (struct socket *sock,
        return 0;
 }
 
-static int dummy_socket_create (int family, int type, int protocol)
+static int dummy_socket_create (int family, int type,
+                               int protocol, int kern)
 {
        return 0;
 }
 
 static void dummy_socket_post_create (struct socket *sock, int family, int type,
-                                     int protocol)
+                                     int protocol, int kern)
 {
        return;
 }
index 2b52cb6537beb535055b6fd1f59e7ffe3babcc2c..8880f37ddf9448dde7bb0c7431289159967f8352 100644 (file)
@@ -2810,34 +2810,43 @@ static int socket_has_perm(struct task_struct *task, struct socket *sock,
        struct inode_security_struct *isec;
        struct task_security_struct *tsec;
        struct avc_audit_data ad;
-       int err;
+       int err = 0;
 
        tsec = task->security;
        isec = SOCK_INODE(sock)->i_security;
 
+       if (isec->sid == SECINITSID_KERNEL)
+               goto out;
+
        AVC_AUDIT_DATA_INIT(&ad,NET);
        ad.u.net.sk = sock->sk;
        err = avc_has_perm(tsec->sid, isec->sid, isec->sclass,
                           perms, &isec->avcr, &ad);
 
+out:
        return err;
 }
 
-static int selinux_socket_create(int family, int type, int protocol)
+static int selinux_socket_create(int family, int type,
+                                int protocol, int kern)
 {
-       int err;
+       int err = 0;
        struct task_security_struct *tsec;
 
-       tsec = current->security;
+       if (kern)
+               goto out;
 
+       tsec = current->security;
        err = avc_has_perm(tsec->sid, tsec->sid,
                           socket_type_to_security_class(family, type),
                           SOCKET__CREATE, NULL, NULL);
 
+out:
        return err;
 }
 
-static void selinux_socket_post_create(struct socket *sock, int family, int type, int protocol)
+static void selinux_socket_post_create(struct socket *sock, int family,
+                                      int type, int protocol, int kern)
 {
        int err;
        struct inode_security_struct *isec;
@@ -2850,7 +2859,7 @@ static void selinux_socket_post_create(struct socket *sock, int family, int type
 
        tsec = current->security;
        isec->sclass = socket_type_to_security_class(family, type);
-       isec->sid = tsec->sid;
+       isec->sid = kern ? SECINITSID_KERNEL : tsec->sid;
 
        return;
 }