Commit 73880d9f authored by James Morris's avatar James Morris

[LSM]: Networking AF_UNIX hooks.

parent 5234b9f7
......@@ -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;
......
......@@ -115,6 +115,7 @@
#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 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
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 @@ static int unix_dgram_sendmsg(struct kiocb *iocb, struct socket *sock,
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) {
......
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment