Commit e81fdf70 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'af_unix-set-skb-drop-reason-in-every-kfree_skb-path'

Kuniyuki Iwashima says:

====================
af_unix: Set skb drop reason in every kfree_skb() path.

There is a potential user for skb drop reason for AF_UNIX.

This series replaces some kfree_skb() in connect() and
sendmsg() paths and sets skb drop reason for the rest of
kfree_skb() in AF_UNIX.

Link: https://lore.kernel.org/netdev/CAAf2ycmZHti95WaBR3s+L5Epm1q7sXmvZ-EqCK=-oZj=45tOwQ@mail.gmail.com/

v2: https://lore.kernel.org/20250112040810.14145-1-kuniyu@amazon.com/
v1: https://lore.kernel.org/20250110092641.85905-1-kuniyu@amazon.com/
====================

Link: https://patch.msgid.link/20250116053441.5758-1-kuniyu@amazon.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 3a0b7fa0 085e6cba
Loading
Loading
Loading
Loading
+22 −6
Original line number Diff line number Diff line
@@ -6,9 +6,13 @@
#define DEFINE_DROP_REASON(FN, FNe)	\
	FN(NOT_SPECIFIED)		\
	FN(NO_SOCKET)			\
	FN(SOCKET_CLOSE)		\
	FN(SOCKET_FILTER)		\
	FN(SOCKET_RCVBUFF)		\
	FN(UNIX_DISCONNECT)		\
	FN(UNIX_SKIP_OOB)		\
	FN(PKT_TOO_SMALL)		\
	FN(TCP_CSUM)			\
	FN(SOCKET_FILTER)		\
	FN(UDP_CSUM)			\
	FN(NETFILTER_DROP)		\
	FN(OTHERHOST)			\
@@ -18,7 +22,6 @@
	FN(UNICAST_IN_L2_MULTICAST)	\
	FN(XFRM_POLICY)			\
	FN(IP_NOPROTO)			\
	FN(SOCKET_RCVBUFF)		\
	FN(PROTO_MEM)			\
	FN(TCP_AUTH_HDR)		\
	FN(TCP_MD5NOTFOUND)		\
@@ -138,12 +141,27 @@ enum skb_drop_reason {
	 * 3) no valid child socket during 3WHS process
	 */
	SKB_DROP_REASON_NO_SOCKET,
	/** @SKB_DROP_REASON_SOCKET_CLOSE: socket is close()d */
	SKB_DROP_REASON_SOCKET_CLOSE,
	/** @SKB_DROP_REASON_SOCKET_FILTER: dropped by socket filter */
	SKB_DROP_REASON_SOCKET_FILTER,
	/** @SKB_DROP_REASON_SOCKET_RCVBUFF: socket receive buff is full */
	SKB_DROP_REASON_SOCKET_RCVBUFF,
	/**
	 * @SKB_DROP_REASON_UNIX_DISCONNECT: recv queue is purged when SOCK_DGRAM
	 * or SOCK_SEQPACKET socket re-connect()s to another socket or notices
	 * during send() that the peer has been close()d.
	 */
	SKB_DROP_REASON_UNIX_DISCONNECT,
	/**
	 * @SKB_DROP_REASON_UNIX_SKIP_OOB: Out-Of-Band data is skipped by
	 * recv() without MSG_OOB so dropped.
	 */
	SKB_DROP_REASON_UNIX_SKIP_OOB,
	/** @SKB_DROP_REASON_PKT_TOO_SMALL: packet size is too small */
	SKB_DROP_REASON_PKT_TOO_SMALL,
	/** @SKB_DROP_REASON_TCP_CSUM: TCP checksum error */
	SKB_DROP_REASON_TCP_CSUM,
	/** @SKB_DROP_REASON_SOCKET_FILTER: dropped by socket filter */
	SKB_DROP_REASON_SOCKET_FILTER,
	/** @SKB_DROP_REASON_UDP_CSUM: UDP checksum error */
	SKB_DROP_REASON_UDP_CSUM,
	/** @SKB_DROP_REASON_NETFILTER_DROP: dropped by netfilter */
@@ -174,8 +192,6 @@ enum skb_drop_reason {
	SKB_DROP_REASON_XFRM_POLICY,
	/** @SKB_DROP_REASON_IP_NOPROTO: no support for IP protocol */
	SKB_DROP_REASON_IP_NOPROTO,
	/** @SKB_DROP_REASON_SOCKET_RCVBUFF: socket receive buff is full */
	SKB_DROP_REASON_SOCKET_RCVBUFF,
	/**
	 * @SKB_DROP_REASON_PROTO_MEM: proto memory limitation, such as
	 * udp packet drop out of udp_memory_allocated.
+32 −35
Original line number Diff line number Diff line
@@ -622,7 +622,9 @@ static void unix_write_space(struct sock *sk)
static void unix_dgram_disconnected(struct sock *sk, struct sock *other)
{
	if (!skb_queue_empty(&sk->sk_receive_queue)) {
		skb_queue_purge(&sk->sk_receive_queue);
		skb_queue_purge_reason(&sk->sk_receive_queue,
				       SKB_DROP_REASON_UNIX_DISCONNECT);

		wake_up_interruptible_all(&unix_sk(sk)->peer_wait);

		/* If one link of bidirectional dgram pipe is disconnected,
@@ -640,7 +642,7 @@ static void unix_sock_destructor(struct sock *sk)
{
	struct unix_sock *u = unix_sk(sk);

	skb_queue_purge(&sk->sk_receive_queue);
	skb_queue_purge_reason(&sk->sk_receive_queue, SKB_DROP_REASON_SOCKET_CLOSE);

	DEBUG_NET_WARN_ON_ONCE(refcount_read(&sk->sk_wmem_alloc));
	DEBUG_NET_WARN_ON_ONCE(!sk_unhashed(sk));
@@ -716,7 +718,7 @@ static void unix_release_sock(struct sock *sk, int embrion)
			unix_release_sock(skb->sk, 1);

		/* passed fds are erased in the kfree_skb hook */
		kfree_skb(skb);
		kfree_skb_reason(skb, SKB_DROP_REASON_SOCKET_CLOSE);
	}

	if (path.dentry)
@@ -1699,7 +1701,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
	unix_state_unlock(other);
	sock_put(other);
out_free_skb:
	kfree_skb(skb);
	consume_skb(skb);
out_free_sk:
	unix_release_sock(newsk, 0);
out:
@@ -2170,7 +2172,7 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg,
out_sock_put:
	sock_put(other);
out_free:
	kfree_skb(skb);
	consume_skb(skb);
out:
	scm_destroy(&scm);
	return err;
@@ -2187,7 +2189,7 @@ static int queue_oob(struct socket *sock, struct msghdr *msg, struct sock *other
{
	struct unix_sock *ousk = unix_sk(other);
	struct sk_buff *skb;
	int err = 0;
	int err;

	skb = sock_alloc_send_skb(sock->sk, 1, msg->msg_flags & MSG_DONTWAIT, &err);

@@ -2195,25 +2197,22 @@ static int queue_oob(struct socket *sock, struct msghdr *msg, struct sock *other
		return err;

	err = unix_scm_to_skb(scm, skb, !fds_sent);
	if (err < 0) {
		kfree_skb(skb);
		return err;
	}
	if (err < 0)
		goto out;

	skb_put(skb, 1);
	err = skb_copy_datagram_from_iter(skb, 0, &msg->msg_iter, 1);

	if (err) {
		kfree_skb(skb);
		return err;
	}
	if (err)
		goto out;

	unix_state_lock(other);

	if (sock_flag(other, SOCK_DEAD) ||
	    (other->sk_shutdown & RCV_SHUTDOWN)) {
		unix_state_unlock(other);
		kfree_skb(skb);
		return -EPIPE;
		err = -EPIPE;
		goto out;
	}

	maybe_add_creds(skb, sock, other);
@@ -2228,6 +2227,9 @@ static int queue_oob(struct socket *sock, struct msghdr *msg, struct sock *other
	unix_state_unlock(other);
	other->sk_data_ready(other);

	return 0;
out:
	consume_skb(skb);
	return err;
}
#endif
@@ -2236,13 +2238,11 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg,
			       size_t len)
{
	struct sock *sk = sock->sk;
	struct sk_buff *skb = NULL;
	struct sock *other = NULL;
	int err, size;
	struct sk_buff *skb;
	int sent = 0;
	struct scm_cookie scm;
	bool fds_sent = false;
	int data_len;
	int err, sent = 0;

	err = scm_send(sock, msg, &scm, false);
	if (err < 0)
@@ -2271,16 +2271,12 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg,
		}
	}

	if (READ_ONCE(sk->sk_shutdown) & SEND_SHUTDOWN) {
		if (!(msg->msg_flags & MSG_NOSIGNAL))
			send_sig(SIGPIPE, current, 0);

		err = -EPIPE;
		goto out_err;
	}
	if (READ_ONCE(sk->sk_shutdown) & SEND_SHUTDOWN)
		goto out_pipe;

	while (sent < len) {
		size = len - sent;
		int size = len - sent;
		int data_len;

		if (unlikely(msg->msg_flags & MSG_SPLICE_PAGES)) {
			skb = sock_alloc_send_pskb(sk, 0, 0,
@@ -2333,7 +2329,7 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg,

		if (sock_flag(other, SOCK_DEAD) ||
		    (other->sk_shutdown & RCV_SHUTDOWN))
			goto out_pipe;
			goto out_pipe_unlock;

		maybe_add_creds(skb, sock, other);
		scm_stat_add(other, skb);
@@ -2356,13 +2352,14 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg,

	return sent;

out_pipe:
out_pipe_unlock:
	unix_state_unlock(other);
out_pipe:
	if (!sent && !(msg->msg_flags & MSG_NOSIGNAL))
		send_sig(SIGPIPE, current, 0);
	err = -EPIPE;
out_free:
	kfree_skb(skb);
	consume_skb(skb);
out_err:
	scm_destroy(&scm);
	return sent ? : err;
@@ -2695,7 +2692,7 @@ static struct sk_buff *manage_oob(struct sk_buff *skb, struct sock *sk,
	spin_unlock(&sk->sk_receive_queue.lock);

	consume_skb(read_skb);
	kfree_skb(unread_skb);
	kfree_skb_reason(unread_skb, SKB_DROP_REASON_UNIX_SKIP_OOB);

	return skb;
}
@@ -2724,7 +2721,7 @@ static int unix_stream_read_skb(struct sock *sk, skb_read_actor_t recv_actor)

		if (sock_flag(sk, SOCK_DEAD)) {
			unix_state_unlock(sk);
			kfree_skb(skb);
			kfree_skb_reason(skb, SKB_DROP_REASON_SOCKET_CLOSE);
			return -ECONNRESET;
		}

@@ -2738,7 +2735,7 @@ static int unix_stream_read_skb(struct sock *sk, skb_read_actor_t recv_actor)
		unix_state_unlock(sk);

		if (drop) {
			kfree_skb(skb);
			kfree_skb_reason(skb, SKB_DROP_REASON_UNIX_SKIP_OOB);
			return -EAGAIN;
		}
	}
+1 −1
Original line number Diff line number Diff line
@@ -573,7 +573,7 @@ static void __unix_gc(struct work_struct *work)
			UNIXCB(skb).fp->dead = true;
	}

	__skb_queue_purge(&hitlist);
	__skb_queue_purge_reason(&hitlist, SKB_DROP_REASON_SOCKET_CLOSE);
skip_gc:
	WRITE_ONCE(gc_in_progress, false);
}