Hello. > > Isn't it better to hook into existing netfilter infrastructure somehow? > Yes, it has been suggested several times. I want to use a process's context who issued accept()/recv()/recvfrom()/recvmsg()/read() requests.
But Stephen Smalley said at http://marc.info/?l=linux-security-module&m=118459899017487&w=2 that > The socket can be inherited by a child task or passed via local IPC to > an unrelated task, and then used by those other tasks. It isn't tied to > the original allocating task's lifecycle in any way, nor is it > guaranteed to only be used by that original allocating task. It can > exist in zero, one or many tasks' file tables and still be receiving > data, and can go from completely disassociated (i.e. not present in any > tasks' file tables) to being associated. I can't use netfilter infrastructure because it is too early to know who the recipant process of the packet is. The only chance to perform ip/port based filtering using ACLs associated with the recipant process of the packet is post-accept() and post-recvmsg(). Therefore, I re-post my patch again. Regards. Signed-off-by: Tetsuo Handa <[EMAIL PROTECTED]> --- include/linux/security.h | 44 +++++++++++++++++++++++++++++++++++++------- net/socket.c | 42 ++++++++++++++++++++++++++++++++++++------ security/dummy.c | 13 ++++++++++--- 3 files changed, 83 insertions(+), 16 deletions(-) diff -upr a/include/linux/security.h b/include/linux/security.h --- a/include/linux/security.h 2007-07-20 22:55:38.000000000 +0900 +++ b/include/linux/security.h 2007-07-20 23:15:58.000000000 +0900 @@ -749,8 +749,12 @@ struct request_sock; * @socket_post_accept: * This hook allows a security module to copy security * information into the newly created socket's inode. + * This hook also allows a security module to filter 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. + * Return 0 if permission is granted. * @socket_sendmsg: * Check permission before transmitting a message to another socket. * @sock contains the socket structure. @@ -764,6 +768,15 @@ struct request_sock; * @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 allows a security module to filter 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. @@ -1345,12 +1358,14 @@ struct security_operations { struct sockaddr * address, int addrlen); int (*socket_listen) (struct socket * sock, int backlog); int (*socket_accept) (struct socket * sock, struct socket * newsock); - void (*socket_post_accept) (struct socket * sock, - struct socket * newsock); + int (*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); @@ -2860,10 +2875,10 @@ static inline int security_socket_accept return security_ops->socket_accept(sock, newsock); } -static inline void security_socket_post_accept(struct socket * sock, - struct socket * newsock) +static inline int security_socket_post_accept(struct socket *sock, + struct socket *newsock) { - security_ops->socket_post_accept(sock, newsock); + return security_ops->socket_post_accept(sock, newsock); } static inline int security_socket_sendmsg(struct socket * sock, @@ -2879,6 +2894,13 @@ static inline int security_socket_recvms 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); @@ -3023,9 +3045,10 @@ static inline int security_socket_accept return 0; } -static inline void security_socket_post_accept(struct socket * sock, - struct socket * newsock) +static inline int security_socket_post_accept(struct socket *sock, + struct socket *newsock) { + return 0; } static inline int security_socket_sendmsg(struct socket * sock, @@ -3041,6 +3064,13 @@ static inline int security_socket_recvms 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 -upr a/net/socket.c b/net/socket.c --- a/net/socket.c 2007-07-20 22:55:53.000000000 +0900 +++ b/net/socket.c 2007-07-21 00:05:18.000000000 +0900 @@ -635,7 +635,19 @@ static inline int __sock_recvmsg(struct if (err) return err; - return sock->ops->recvmsg(iocb, sock, msg, size, flags); + err = sock->ops->recvmsg(iocb, sock, msg, size, flags); + /* + * Filter messages from unwanted peers. + * To be exact, this hook can't filter messages, + * this hook just returns an error code. + */ + if (err >= 0) { + int ret; + ret = security_socket_post_recvmsg(sock, msg, size, flags); + if (ret) + err = ret; + } + return err; } int sock_recvmsg(struct socket *sock, struct msghdr *msg, @@ -648,8 +660,17 @@ int sock_recvmsg(struct socket *sock, st init_sync_kiocb(&iocb, NULL); iocb.private = &siocb; ret = __sock_recvmsg(&iocb, sock, msg, size, flags); - if (-EIOCBQUEUED == ret) + if (-EIOCBQUEUED == ret) { ret = wait_on_sync_kiocb(&iocb); + /* I can now check security_socket_post_recvmsg(). */ + if (ret >= 0) { + int err; + err = security_socket_post_recvmsg(sock, msg, size, + flags); + if (err) + ret = err; + } + } return ret; } @@ -712,12 +733,14 @@ static ssize_t do_sock_read(struct msghd struct socket *sock = file->private_data; size_t size = 0; int i; + /* only for security_socket_post_recvmsg() */ + char address[MAX_SOCK_ADDR]; for (i = 0; i < nr_segs; i++) size += iov[i].iov_len; - msg->msg_name = NULL; - msg->msg_namelen = 0; + msg->msg_name = address; + msg->msg_namelen = sizeof(address); msg->msg_control = NULL; msg->msg_controllen = 0; msg->msg_iov = (struct iovec *)iov; @@ -1437,13 +1460,16 @@ asmlinkage long sys_accept(int fd, struc goto out_fd; } + /* Filter connections from unwanted peers like TCP Wrapper. */ + err = security_socket_post_accept(sock, newsock); + if (err) + goto out_fd; + /* File flags are not inherited via accept() unlike another OSes. */ fd_install(newfd, newfile); err = newfd; - security_socket_post_accept(sock, newsock); - out_put: fput_light(sock->file, fput_needed); out: @@ -1937,6 +1963,10 @@ asmlinkage long sys_recvmsg(int fd, stru goto out_freeiov; total_len = err; + /* only for security_socket_post_recvmsg() */ + msg_sys.msg_name = addr; + msg_sys.msg_namelen = sizeof(addr); + cmsg_ptr = (unsigned long)msg_sys.msg_control; msg_sys.msg_flags = flags & (MSG_CMSG_CLOEXEC|MSG_CMSG_COMPAT); diff -upr a/security/dummy.c b/security/dummy.c --- a/security/dummy.c 2007-07-20 22:55:54.000000000 +0900 +++ b/security/dummy.c 2007-07-20 23:15:22.000000000 +0900 @@ -741,10 +741,10 @@ static int dummy_socket_accept (struct s return 0; } -static void dummy_socket_post_accept (struct socket *sock, - struct socket *newsock) +static int dummy_socket_post_accept(struct socket *sock, + struct socket *newsock) { - return; + return 0; } static int dummy_socket_sendmsg (struct socket *sock, struct msghdr *msg, @@ -759,6 +759,12 @@ static int dummy_socket_recvmsg (struct 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; @@ -1096,6 +1102,7 @@ void security_fixup_ops (struct security 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