]> git.neil.brown.name Git - history.git/commitdiff
[LSM]: Networking AF_UNIX hooks.
authorJames Morris <jmorris@intercode.com.au>
Thu, 6 Feb 2003 17:50:47 +0000 (09:50 -0800)
committerJames Morris <jmorris@intercode.com.au>
Thu, 6 Feb 2003 17:50:47 +0000 (09:50 -0800)
include/linux/security.h
net/unix/af_unix.c
security/dummy.c

index 95962488a08978f0c0383f4afbe93f45f236743b..c04fc8ceec06e417f2641ba92a4fe4208e1097b7 100644 (file)
@@ -588,6 +588,31 @@ struct swap_info_struct;
  *     is being reparented to the init task.
  *     @p contains the task_struct for the kernel thread.
  *
+ * Security hooks for Unix domain networking.
+ *
+ * @unix_stream_connect:
+ *     Check permissions before establishing a Unix domain stream connection
+ *     between @sock and @other.
+ *     @sock contains the socket structure.
+ *     @other contains the peer socket structure.
+ *     Return 0 if permission is granted.
+ * @unix_may_send:
+ *     Check permissions before connecting or sending datagrams from @sock to
+ *     @other.
+ *     @sock contains the socket structure.
+ *     @sock contains the peer socket structure.
+ *     Return 0 if permission is granted.
+ *
+ * The @unix_stream_connect and @unix_may_send hooks were necessary because
+ * Linux provides an alternative to the conventional file name space for Unix
+ * domain sockets.  Whereas binding and connecting to sockets in the file name
+ * space is mediated by the typical file permissions (and caught by the mknod
+ * and permission hooks in inode_security_ops), binding and connecting to
+ * sockets in the abstract name space is completely unmediated.  Sufficient
+ * control of Unix domain sockets in the abstract name space isn't possible
+ * using only the socket layer hooks, since we need to know the actual target
+ * socket, which is not looked up until we are inside the af_unix code.
+ *
  * Security hooks for socket operations.
  *
  * @socket_create:
@@ -1059,6 +1084,10 @@ struct security_operations {
                                    struct security_operations *ops);
 
 #ifdef CONFIG_SECURITY_NETWORK
+       int (*unix_stream_connect) (struct socket * sock,
+                                   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);
        void (*socket_post_create) (struct socket * sock, int family,
                                    int type, int protocol);
@@ -2236,6 +2265,20 @@ static inline int security_sem_semop (struct sem_array * sma,
 #endif /* CONFIG_SECURITY */
 
 #ifdef CONFIG_SECURITY_NETWORK
+static inline int security_unix_stream_connect(struct socket * sock,
+                                              struct socket * other, 
+                                              struct sock * newsk)
+{
+       return security_ops->unix_stream_connect(sock, other, newsk);
+}
+
+
+static inline int security_unix_may_send(struct socket * sock, 
+                                        struct socket * other)
+{
+       return security_ops->unix_may_send(sock, other);
+}
+
 static inline int security_socket_create (int family, int type, int protocol)
 {
        return security_ops->socket_create(family, type, protocol);
@@ -2326,6 +2369,19 @@ static inline int security_sock_rcv_skb (struct sock * sk,
        return security_ops->socket_sock_rcv_skb (sk, skb);
 }
 #else  /* CONFIG_SECURITY_NETWORK */
+static inline int security_unix_stream_connect(struct socket * sock,
+                                              struct socket * other, 
+                                              struct sock * newsk)
+{
+       return 0;
+}
+
+static inline int security_unix_may_send(struct socket * sock, 
+                                        struct socket * other)
+{
+       return 0;
+}
+
 static inline int security_socket_create (int family, int type, int protocol)
 {
        return 0;
index 42e341e9bb2dda615656d3ec6fbe48714a64ffd5..c84795fd80a2f743e33bcfd46b989e643a02dc50 100644 (file)
 #include <linux/rtnetlink.h>
 #include <linux/mount.h>
 #include <net/checksum.h>
+#include <linux/security.h>
 
 int sysctl_unix_max_dgram_qlen = 10;
 
@@ -816,6 +817,11 @@ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr,
                err = -EPERM;
                if (!unix_may_send(sk, other))
                        goto out_unlock;
+
+               err = security_unix_may_send(sk->socket, other->socket);
+               if (err)
+                       goto out_unlock;
+
        } else {
                /*
                 *      1003.1g breaking connected state with AF_UNSPEC
@@ -981,6 +987,12 @@ restart:
                goto restart;
        }
 
+       err = security_unix_stream_connect(sock, other->socket, newsk);
+       if (err) {
+               unix_state_wunlock(sk);
+               goto out_unlock;
+       }
+
        /* The way is open! Fastly set all the necessary fields... */
 
        sock_hold(sk);
@@ -1280,6 +1292,10 @@ restart:
        if (other->shutdown&RCV_SHUTDOWN)
                goto out_unlock;
 
+       err = security_unix_may_send(sk->socket, other->socket);
+       if (err)
+               goto out_unlock;
+
        if (unix_peer(other) != sk &&
            skb_queue_len(&other->receive_queue) > other->max_ack_backlog) {
                if (!timeo) {
index e2dfbadaee1f64755526196f7d31edd426ec81d5..46cfb0d00aa6888d86c5ff84181d75f56fb8a16b 100644 (file)
@@ -598,6 +598,19 @@ static int dummy_sem_semop (struct sem_array *sma,
 }
 
 #ifdef CONFIG_SECURITY_NETWORK
+static int dummy_unix_stream_connect (struct socket *sock,
+                                     struct socket *other,
+                                     struct sock *newsk)
+{
+       return 0;
+}
+
+static int dummy_unix_may_send (struct socket *sock,
+                               struct socket *other)
+{
+       return 0;
+}
+
 static int dummy_socket_create (int family, int type, int protocol)
 {
        return 0;
@@ -809,6 +822,8 @@ void security_fixup_ops (struct security_operations *ops)
        set_to_dummy_if_null(ops, register_security);
        set_to_dummy_if_null(ops, unregister_security);
 #ifdef CONFIG_SECURITY_NETWORK
+       set_to_dummy_if_null(ops, unix_stream_connect);
+       set_to_dummy_if_null(ops, unix_may_send);
        set_to_dummy_if_null(ops, socket_create);
        set_to_dummy_if_null(ops, socket_post_create);
        set_to_dummy_if_null(ops, socket_bind);