@@ -880,6 +880,17 @@ static inline void security_free_mnt_opt
* @sock contains the listening socket structure.
* @newsock contains the newly created server socket for connection.
* Return 0 if permission is granted.
+ * @socket_post_accept:
+ * This hook allows a security module to filter connections from unwanted
+ * peers based on the process accepting this connection.
+ * The connection will be aborted if this hook returns nonzero.
+ * This hook is not designed for updating security attributes of
+ * an accept()ed socket, for the accept()ed socket has already sent
+ * several packets (e.g. TCP's SYN/ACK packet and some ACK packets for
+ * incoming data) before this hook is called.
+ * @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.
@@ -893,6 +904,15 @@ static inline void security_free_mnt_opt
* @size contains the size of message structure.
* @flags contains the operational flags.
* Return 0 if permission is granted.
+ * @socket_post_recv_datagram:
+ * Check permission after receiving a datagram.
+ * This hook allows a security module to filter packets
+ * from unwanted peers based on the process receiving this datagram.
+ * The packet will be discarded if this hook returns nonzero.
+ * @sk contains the socket.
+ * @skb contains the socket buffer.
+ * @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.
@@ -1549,10 +1569,13 @@ 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);
+ 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_recv_datagram) (struct sock *sk, struct sk_buff *skb,
+ unsigned int flags);
int (*socket_getsockname) (struct socket *sock);
int (*socket_getpeername) (struct socket *sock);
int (*socket_getsockopt) (struct socket *sock, int level, int optname);
@@ -2530,9 +2553,12 @@ int security_socket_bind(struct socket *
int security_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen);
int security_socket_listen(struct socket *sock, int backlog);
int security_socket_accept(struct socket *sock, struct socket *newsock);
+int security_socket_post_accept(struct socket *sock, struct socket *newsock);
int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size);
int security_socket_recvmsg(struct socket *sock, struct msghdr *msg,
int size, int flags);
+int security_socket_post_recv_datagram(struct sock *sk, struct sk_buff *skb,
+ unsigned int flags);
int security_socket_getsockname(struct socket *sock);
int security_socket_getpeername(struct socket *sock);
int security_socket_getsockopt(struct socket *sock, int level, int optname);
@@ -2608,6 +2634,12 @@ static inline int security_socket_accept
return 0;
}
+static inline int security_socket_post_accept(struct socket *sock,
+ struct socket *newsock)
+{
+ return 0;
+}
+
static inline int security_socket_sendmsg(struct socket *sock,
struct msghdr *msg, int size)
{
@@ -2621,6 +2653,13 @@ static inline int security_socket_recvms
return 0;
}
+static inline int security_socket_post_recv_datagram(struct sock *sk,
+ struct sk_buff *skb,
+ unsigned int flags)
+{
+ return 0;
+}
+
static inline int security_socket_getsockname(struct socket *sock)
{
return 0;
@@ -55,6 +55,7 @@
#include <net/checksum.h>
#include <net/sock.h>
#include <net/tcp_states.h>
+#include <linux/security.h>
/*
* Is a socket 'connection oriented' ?
@@ -148,6 +149,7 @@ struct sk_buff *__skb_recv_datagram(stru
{
struct sk_buff *skb;
long timeo;
+ unsigned long cpu_flags;
/*
* Caller is allowed not to check sk->sk_err before skb_recv_datagram()
*/
@@ -165,7 +167,6 @@ struct sk_buff *__skb_recv_datagram(stru
* Look at current nfs client by the way...
* However, this function was corrent in any case. 8)
*/
- unsigned long cpu_flags;
spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags);
skb = skb_peek(&sk->sk_receive_queue);
@@ -179,8 +180,13 @@ struct sk_buff *__skb_recv_datagram(stru
}
spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags);
- if (skb)
+ if (skb) {
+ error = security_socket_post_recv_datagram(sk, skb,
+ flags);
+ if (error)
+ goto force_dequeue;
return skb;
+ }
/* User doesn't want to wait */
error = -EAGAIN;
@@ -191,6 +197,17 @@ struct sk_buff *__skb_recv_datagram(stru
return NULL;
+force_dequeue:
+ if (!(flags & MSG_PEEK))
+ goto no_peek;
+ spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags);
+ if (skb == skb_peek(&sk->sk_receive_queue)) {
+ __skb_unlink(skb, &sk->sk_receive_queue);
+ atomic_dec(&skb->users);
+ }
+ spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags);
+no_peek:
+ kfree_skb(skb);
no_packet:
*err = error;
return NULL;
@@ -1519,6 +1519,11 @@ SYSCALL_DEFINE4(accept4, int, fd, struct
if (err < 0)
goto out_fd;
+ /* Filter connections from unwanted peers. */
+ err = security_socket_post_accept(sock, newsock);
+ if (err)
+ goto out_fd;
+
if (upeer_sockaddr) {
if (newsock->ops->getname(newsock, (struct sockaddr *)&address,
&len, 2) < 0) {
@@ -620,6 +620,11 @@ static int cap_socket_accept(struct sock
return 0;
}
+static int cap_socket_post_accept(struct socket *sock, struct socket *newsock)
+{
+ return 0;
+}
+
static int cap_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size)
{
return 0;
@@ -631,6 +636,12 @@ static int cap_socket_recvmsg(struct soc
return 0;
}
+static int cap_socket_post_recv_datagram(struct sock *sk, struct sk_buff *skb,
+ unsigned int flags)
+{
+ return 0;
+}
+
static int cap_socket_getsockname(struct socket *sock)
{
return 0;
@@ -1010,8 +1021,10 @@ void security_fixup_ops(struct security_
set_to_cap_if_null(ops, socket_connect);
set_to_cap_if_null(ops, socket_listen);
set_to_cap_if_null(ops, socket_accept);
+ set_to_cap_if_null(ops, socket_post_accept);
set_to_cap_if_null(ops, socket_sendmsg);
set_to_cap_if_null(ops, socket_recvmsg);
+ set_to_cap_if_null(ops, socket_post_recv_datagram);
set_to_cap_if_null(ops, socket_getsockname);
set_to_cap_if_null(ops, socket_getpeername);
set_to_cap_if_null(ops, socket_setsockopt);
@@ -1007,6 +1007,11 @@ int security_socket_accept(struct socket
return security_ops->socket_accept(sock, newsock);
}
+int security_socket_post_accept(struct socket *sock, struct socket *newsock)
+{
+ return security_ops->socket_post_accept(sock, newsock);
+}
+
int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size)
{
return security_ops->socket_sendmsg(sock, msg, size);
@@ -1018,6 +1023,12 @@ int security_socket_recvmsg(struct socke
return security_ops->socket_recvmsg(sock, msg, size, flags);
}
+int security_socket_post_recv_datagram(struct sock *sk, struct sk_buff *skb,
+ unsigned int flags)
+{
+ return security_ops->socket_post_recv_datagram(sk, skb, flags);
+}
+
int security_socket_getsockname(struct socket *sock)
{
return security_ops->socket_getsockname(sock);