Hello.

I want to use tcp_wrapper-like filtering.
To do so, I need two more hooks.
When I asked for these hooks some months ago,
I got a reply "do it at interface layer".
I want to do it at socket layer so that I can use
interactive judgment (like popup windows
used by anti-virus software's personal firewall feature).



I think security_socket_post_accept() should be able to
return an error so that memory allocation
(or something that may fail) can fail.
But I think you don't want to change type of return value,
my patch doesn't change security_socket_post_accept().
The location of my hook is not too late to block
because this hook is inserted at before fd_install().



The post-recvmsg() hook I introduce can't actually
prevent data from arriving at userspace buffer.
But it is difficult to keep userspace buffer
unmodified until this hook because
if the userland process requests something like

  static char buffer[1048576];
  recv(fd, buffer, sizeof(buffer), 0);

allocating kernel memory likely fails.
Even if allocating kernel memory succeeds,
using temporal buffer every time has performance penalty.



Signed-off-by: Tetsuo Handa <[EMAIL PROTECTED]>
---
 include/linux/security.h |   47 +++++++++++++++++++++++++++++++++++++++++++++++
 net/socket.c             |   16 ++++++++++++++++
 security/dummy.c         |   13 +++++++++++++
 3 files changed, 76 insertions(+)


diff -ur a/include/linux/security.h b/include/linux/security.h
--- a/include/linux/security.h  2007-07-03 10:07:14.000000000 +0900
+++ b/include/linux/security.h  2007-07-03 13:21:20.581744544 +0900
@@ -745,6 +745,16 @@
  *     @sock contains the listening socket structure.
  *     @newsock contains the newly created server socket for connection.
  *     Return 0 if permission is granted.
+ * @socket_pre_accept:
+ *     Check peer's address after accepting a new connection but
+ *     before making that connection visible to userland.
+ *     This hook is intended for filtering connections from unwanted peers.
+ *     The connection will be aborted if this hook returns nonzero.
+ *     @sock contains the listening socket structure.
+ *     @newsock contains the newly created server socket for connection.
+ *     @address contains the address of remote endpoint.
+ *     @addrlen contains the length of address.
+ *     Return 0 if permission is granted.
  * @socket_post_accept:
  *     This hook allows a security module to copy security
  *     information into the newly created socket's inode.
@@ -763,6 +773,14 @@
  *     @size contains the size of message structure.
  *     @flags contains the operational flags.
  *     Return 0 if permission is granted.  
+ * @socket_post_recvmsg:
+ *     Check peer's address after receiving a message from a socket.
+ *     This hook is intended for filtering messages from unwanted peers.
+ *     @sock contains the socket structure.
+ *     @msg contains the message structure.
+ *     @size contains the size of message structure.
+ *     @flags contains the operational flags.
+ *     Return 0 if permission is granted.
  * @socket_getsockname:
  *     Check permission before the local address (name) of the socket object
  *     @sock is retrieved.
@@ -1343,12 +1361,15 @@
                               struct sockaddr * address, int addrlen);
        int (*socket_listen) (struct socket * sock, int backlog);
        int (*socket_accept) (struct socket * sock, struct socket * newsock);
+       int (*socket_pre_accept) (struct socket *sock, struct socket *newsock);
        void (*socket_post_accept) (struct socket * sock,
                                    struct socket * newsock);
        int (*socket_sendmsg) (struct socket * sock,
                               struct msghdr * msg, int size);
        int (*socket_recvmsg) (struct socket * sock,
                               struct msghdr * msg, int size, int flags);
+       int (*socket_post_recvmsg) (struct socket *sock, struct msghdr *msg,
+                                   int size, int flags);
        int (*socket_getsockname) (struct socket * sock);
        int (*socket_getpeername) (struct socket * sock);
        int (*socket_getsockopt) (struct socket * sock, int level, int optname);
@@ -2853,6 +2874,12 @@
        return security_ops->socket_accept(sock, newsock);
 }
 
+static inline int security_socket_pre_accept(struct socket *sock,
+                                            struct socket *newsock)
+{
+       return security_ops->socket_pre_accept(sock, newsock);
+}
+
 static inline void security_socket_post_accept(struct socket * sock, 
                                               struct socket * newsock)
 {
@@ -2872,6 +2899,13 @@
        return security_ops->socket_recvmsg(sock, msg, size, flags);
 }
 
+static inline int security_socket_post_recvmsg(struct socket *sock,
+                                              struct msghdr *msg,
+                                              int size, int flags)
+{
+       return security_ops->socket_post_recvmsg(sock, msg, size, flags);
+}
+
 static inline int security_socket_getsockname(struct socket * sock)
 {
        return security_ops->socket_getsockname(sock);
@@ -3016,6 +3050,12 @@
        return 0;
 }
 
+static inline int security_socket_pre_accept(struct socket *sock,
+                                            struct socket *newsock)
+{
+       return 0;
+}
+
 static inline void security_socket_post_accept(struct socket * sock, 
                                               struct socket * newsock)
 {
@@ -3034,6 +3074,13 @@
        return 0;
 }
 
+static inline int security_socket_post_recvmsg(struct socket *sock,
+                                              struct msghdr *msg,
+                                              int size, int flags)
+{
+       return 0;
+}
+
 static inline int security_socket_getsockname(struct socket * sock)
 {
        return 0;
diff -ur a/net/socket.c b/net/socket.c
--- a/net/socket.c      2007-07-03 10:07:16.000000000 +0900
+++ b/net/socket.c      2007-07-03 13:23:53.055565000 +0900
@@ -651,6 +651,17 @@
        ret = __sock_recvmsg(&iocb, sock, msg, size, flags);
        if (-EIOCBQUEUED == ret)
                ret = wait_on_sync_kiocb(&iocb);
+       /*
+        * Filter messages from unwanted peers.
+        * To be exact, this hook can't filter messages,
+        * this hook just returns an error code.
+        * Do we have to keep userland buffer unchanged until this hook?
+        */
+       if (ret >= 0) {
+               int err = security_socket_post_recvmsg(sock, msg, size, flags);
+               if (err)
+                       ret = err;
+       }
        return ret;
 }
 
@@ -1426,6 +1437,11 @@
        if (err < 0)
                goto out_fd;
 
+       /* Filter connections from unwanted peers like TCP Wrapper. */
+       err = security_socket_pre_accept(sock, newsock);
+       if (err)
+               goto out_fd;
+
        if (upeer_sockaddr) {
                if (newsock->ops->getname(newsock, (struct sockaddr *)address,
                                          &len, 2) < 0) {
diff -ur a/security/dummy.c b/security/dummy.c
--- a/security/dummy.c  2007-04-26 12:08:32.000000000 +0900
+++ b/security/dummy.c  2007-07-03 12:55:08.851683832 +0900
@@ -737,6 +737,11 @@
        return 0;
 }
 
+static int dummy_socket_pre_accept (struct socket *sock, struct socket 
*newsock)
+{
+       return 0;
+}
+
 static void dummy_socket_post_accept (struct socket *sock, 
                                      struct socket *newsock)
 {
@@ -755,6 +760,12 @@
        return 0;
 }
 
+static int dummy_socket_post_recvmsg (struct socket *sock, struct msghdr *msg,
+                                     int size, int flags)
+{
+       return 0;
+}
+
 static int dummy_socket_getsockname (struct socket *sock)
 {
        return 0;
@@ -1089,9 +1100,11 @@
        set_to_dummy_if_null(ops, socket_connect);
        set_to_dummy_if_null(ops, socket_listen);
        set_to_dummy_if_null(ops, socket_accept);
+       set_to_dummy_if_null(ops, socket_pre_accept);
        set_to_dummy_if_null(ops, socket_post_accept);
        set_to_dummy_if_null(ops, socket_sendmsg);
        set_to_dummy_if_null(ops, socket_recvmsg);
+       set_to_dummy_if_null(ops, socket_post_recvmsg);
        set_to_dummy_if_null(ops, socket_getsockname);
        set_to_dummy_if_null(ops, socket_getpeername);
        set_to_dummy_if_null(ops, socket_setsockopt);
-
To unsubscribe from this list: send the line "unsubscribe 
linux-security-module" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to