Linux s390 Architecture development
 help / color / mirror / Atom feed
* [PATCH net v2 0/3] net/iucv: fix the recvmsg window update
@ 2026-08-21 11:17 Bryam Vargas via B4 Relay
  2026-08-21 11:17 ` [PATCH net v2 1/3] net/iucv: only send the window update on HiperSockets sockets Bryam Vargas via B4 Relay
                   ` (4 more replies)
  0 siblings, 5 replies; 10+ messages in thread
From: Bryam Vargas via B4 Relay @ 2026-08-21 11:17 UTC (permalink / raw)
  To: Eric Dumazet, Paolo Abeni, Jakub Kicinski, Alexandra Winter,
	Thorsten Winkler, David S. Miller
  Cc: Hidayath Khan, Simon Horman, linux-kernel, netdev, linux-s390,
	Ursula Braun

v2 answers Jakub's reviews of v1 with changes rather than replies.

1/3 keeps its hunk and states the impact properly. SO_MSGLIMIT accepts 1,
which makes msglimit / 2 zero, and msg_recv never leaves zero on a classic
socket, so the NULL read is one recvmsg() away for an unprivileged process
on a socket of its own. With relocate_lowcore it faults.

Its Fixes: tag was wrong as well. The unconditional send does date to
3881ac441f64, but iucv_send_ctrl() sized the skb with a constant ETH_HLEN
until 238965b71b96, so before that it just returned -ENODEV. Backport
window is v5.3, not v3.1.

2/3 is new. v1 admitted it widened the msg_recv race and left it open,
which isn't good enough under Cc: stable. afiucv_hs_send() samples the
counter and settles it after dev_queue_xmit(); sendmsg reaches that under
lock_sock() and recvmsg reaches it under no socket lock, so the two don't
exclude each other and both can subtract the same value. Negative counter,
WARN_ON, and the same credit advertised twice to a peer whose
afiucv_hs_callback_win() subtracts the wire value from msg_sent unchecked.

Taking the socket lock around the deferred send would close it too, since
recvmsg is the only unlocked side. I didn't: recvmsg has never held that
lock, and making it do so changes the receive path for every caller. That
belongs in the locking rework, not in a stable fix.

The claim sits after the last error exit rather than in the header build,
so the counter reads zero only while the transmit is in flight, and a
concurrent sender isn't talked out of its own update.

3/3 is v1's patch, and it must not be applied without 2/3: hoisting the
send out of message_q.lock drops the serialisation that lock gave two
concurrent recvmsg(). Backported alone it recreates what 2/3 fixes. Both
changelogs say so.

Litmus test under LKMM: the counter reaches -2 before 2/3 and cannot after.
No hardware run; I have no IBM Z, and CONFIG_AFIUCV is s390-only.

The unlocked hs_dev and sk_shutdown window, the unbounded backlog_skb_q and
the WARN_ON a flooding peer can reach are pre-existing and wider than this
series. They belong with the locking rework Alexandra has open.

Thanks for the reviews.

---
Bryam Vargas (3):
      net/iucv: only send the window update on HiperSockets sockets
      net/iucv: claim the receive credit atomically
      net/iucv: send the window update outside message_q.lock

 net/iucv/af_iucv.c | 42 +++++++++++++++++++++++++-----------------
 1 file changed, 25 insertions(+), 17 deletions(-)
---
base-commit: 746fc0787f616da418ffc04a110296fe95d53491
change-id: 20260821-b4-disp-3a6e8695-c1f4a6069169

Best regards,
--  
Bryam Vargas <hexlabsecurity@proton.me>



^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH net v2 1/3] net/iucv: only send the window update on HiperSockets sockets
  2026-08-21 11:17 [PATCH net v2 0/3] net/iucv: fix the recvmsg window update Bryam Vargas via B4 Relay
@ 2026-08-21 11:17 ` Bryam Vargas via B4 Relay
  2026-08-22 11:17   ` sashiko-bot
  2026-08-21 11:17 ` [PATCH net v2 2/3] net/iucv: claim the receive credit atomically Bryam Vargas via B4 Relay
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 10+ messages in thread
From: Bryam Vargas via B4 Relay @ 2026-08-21 11:17 UTC (permalink / raw)
  To: Eric Dumazet, Paolo Abeni, Jakub Kicinski, Alexandra Winter,
	Thorsten Winkler, David S. Miller
  Cc: Hidayath Khan, Simon Horman, linux-kernel, netdev, linux-s390,
	Ursula Braun

From: Bryam Vargas <hexlabsecurity@proton.me>

iucv_sock_recvmsg() sends AF_IUCV_FLAG_WIN without testing the transport,
but that flag exists only on HiperSockets. On a classic z/VM socket
iucv->hs_dev is NULL and iucv_send_ctrl() sizes the skb from
LL_RESERVED_SPACE(iucv->hs_dev), so the read goes through NULL. It is one
recvmsg() away for an unprivileged process on a socket of its own:
SO_MSGLIMIT accepts 1, so msglimit / 2 is 0 and msg_recv never leaves 0 on
a classic socket. The read lands in mapped lowcore on a default kernel and
the socket takes a spurious disconnect; with relocate_lowcore it faults.

Test the transport. The unconditional send is older than that, but stayed
harmless while iucv_send_ctrl() used a constant ETH_HLEN.

Fixes: 238965b71b96 ("net/af_iucv: build proper skbs for HiperTransport")
Cc: stable@vger.kernel.org
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
---
 net/iucv/af_iucv.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
index ea047bab65e7..0bc4a15f4b56 100644
--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -1331,7 +1331,8 @@ static int iucv_sock_recvmsg(struct socket *sock, struct msghdr *msg,
 		if (skb_queue_empty(&iucv->backlog_skb_q)) {
 			if (!list_empty(&iucv->message_q.list))
 				iucv_process_message_q(sk);
-			if (atomic_read(&iucv->msg_recv) >=
+			if (iucv->transport == AF_IUCV_TRANS_HIPER &&
+			    atomic_read(&iucv->msg_recv) >=
 							iucv->msglimit / 2) {
 				err = iucv_send_ctrl(sk, AF_IUCV_FLAG_WIN);
 				if (err) {

-- 
2.55.0



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH net v2 2/3] net/iucv: claim the receive credit atomically
  2026-08-21 11:17 [PATCH net v2 0/3] net/iucv: fix the recvmsg window update Bryam Vargas via B4 Relay
  2026-08-21 11:17 ` [PATCH net v2 1/3] net/iucv: only send the window update on HiperSockets sockets Bryam Vargas via B4 Relay
@ 2026-08-21 11:17 ` Bryam Vargas via B4 Relay
  2026-08-22 11:17   ` sashiko-bot
  2026-08-21 11:17 ` [PATCH net v2 3/3] net/iucv: send the window update outside message_q.lock Bryam Vargas via B4 Relay
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 10+ messages in thread
From: Bryam Vargas via B4 Relay @ 2026-08-21 11:17 UTC (permalink / raw)
  To: Eric Dumazet, Paolo Abeni, Jakub Kicinski, Alexandra Winter,
	Thorsten Winkler, David S. Miller
  Cc: Hidayath Khan, Simon Horman, linux-kernel, netdev, linux-s390,
	Ursula Braun

From: Bryam Vargas <hexlabsecurity@proton.me>

afiucv_hs_send() samples msg_recv, advertises it to the peer as the window,
and subtracts it once dev_queue_xmit() has returned. Nothing owns the
counter across the two: iucv_sock_sendmsg() reaches it under lock_sock()
and iucv_sock_recvmsg() reaches it under no socket lock, so an unprivileged
process running both on one socket can have them subtract the same value.
msg_recv goes negative and trips the WARN_ON(); the same interleaving puts
that credit on the wire twice, and the peer's afiucv_hs_callback_win()
subtracts the wire value from msg_sent unchecked.

Claim it with atomic_xchg(), after the last error exit so the counter reads
zero only while the transmit is in flight, and hand it back if that fails.
Nothing subtracts now, so the WARN_ON() goes too.

Fixes: 3881ac441f64 ("af_iucv: add HiperSockets transport")
Cc: stable@vger.kernel.org
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
---
 net/iucv/af_iucv.c | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
index 0bc4a15f4b56..492a45bb2bba 100644
--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -210,12 +210,6 @@ static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock,
 	phs_hdr->flags = flags;
 	if (flags == AF_IUCV_FLAG_SYN)
 		phs_hdr->window = iucv->msglimit;
-	else if ((flags == AF_IUCV_FLAG_WIN) || !flags) {
-		confirm_recv = atomic_read(&iucv->msg_recv);
-		phs_hdr->window = confirm_recv;
-		if (confirm_recv)
-			phs_hdr->flags = phs_hdr->flags | AF_IUCV_FLAG_WIN;
-	}
 	memcpy(phs_hdr->destUserID, iucv->dst_user_id, 8);
 	memcpy(phs_hdr->destAppName, iucv->dst_name, 8);
 	memcpy(phs_hdr->srcUserID, iucv->src_user_id, 8);
@@ -250,13 +244,22 @@ static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock,
 	}
 	skb->protocol = cpu_to_be16(ETH_P_AF_IUCV);
 
+	/* Claim the receive credit here, not while building the header: every
+	 * way this frame can be dropped has now been ruled out, so the window
+	 * is zeroed only for as long as the transmit itself takes.
+	 */
+	if (flags == AF_IUCV_FLAG_WIN || !flags) {
+		confirm_recv = atomic_xchg(&iucv->msg_recv, 0);
+		phs_hdr->window = confirm_recv;
+		if (confirm_recv)
+			phs_hdr->flags = phs_hdr->flags | AF_IUCV_FLAG_WIN;
+	}
+
 	atomic_inc(&iucv->skbs_in_xmit);
 	err = dev_queue_xmit(skb);
 	if (net_xmit_eval(err)) {
 		atomic_dec(&iucv->skbs_in_xmit);
-	} else {
-		atomic_sub(confirm_recv, &iucv->msg_recv);
-		WARN_ON(atomic_read(&iucv->msg_recv) < 0);
+		atomic_add(confirm_recv, &iucv->msg_recv);
 	}
 	return net_xmit_eval(err);
 

-- 
2.55.0



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH net v2 3/3] net/iucv: send the window update outside message_q.lock
  2026-08-21 11:17 [PATCH net v2 0/3] net/iucv: fix the recvmsg window update Bryam Vargas via B4 Relay
  2026-08-21 11:17 ` [PATCH net v2 1/3] net/iucv: only send the window update on HiperSockets sockets Bryam Vargas via B4 Relay
  2026-08-21 11:17 ` [PATCH net v2 2/3] net/iucv: claim the receive credit atomically Bryam Vargas via B4 Relay
@ 2026-08-21 11:17 ` Bryam Vargas via B4 Relay
  2026-08-22 11:17   ` sashiko-bot
  2026-08-24 13:08 ` [PATCH net v2 0/3] net/iucv: fix the recvmsg window update Alexandra Winter
  2026-08-25 13:17 ` Aswin Karuvally
  4 siblings, 1 reply; 10+ messages in thread
From: Bryam Vargas via B4 Relay @ 2026-08-21 11:17 UTC (permalink / raw)
  To: Eric Dumazet, Paolo Abeni, Jakub Kicinski, Alexandra Winter,
	Thorsten Winkler, David S. Miller
  Cc: Hidayath Khan, Simon Horman, linux-kernel, netdev, linux-s390,
	Ursula Braun

From: Bryam Vargas <hexlabsecurity@proton.me>

iucv_sock_recvmsg() calls iucv_send_ctrl() with message_q.lock held, and
iucv_send_ctrl() allocates through sock_alloc_send_skb() with
sk->sk_allocation -- GFP_KERNEL here -- so the allocation may sleep inside
the spin_lock_bh() section; noblock suppresses only the wait for send
buffer space, not the allocation flags. CONFIG_DEBUG_ATOMIC_SLEEP reports
it.

Note that the update is due and send it once the lock is dropped. That
leaves two recvmsg() able to reach afiucv_hs_send() concurrently, which
message_q.lock used to prevent; the preceding patch is what makes that
safe, so do not apply this one without it.

Fixes: 3881ac441f64 ("af_iucv: add HiperSockets transport")
Cc: stable@vger.kernel.org
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
---
 net/iucv/af_iucv.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
index 492a45bb2bba..a7c0f60bb5bf 100644
--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -1244,6 +1244,7 @@ static int iucv_sock_recvmsg(struct socket *sock, struct msghdr *msg,
 	struct iucv_sock *iucv = iucv_sk(sk);
 	unsigned int copied, rlen;
 	struct sk_buff *skb, *rskb, *cskb;
+	bool send_win = false;
 	int err = 0;
 	u32 offset;
 
@@ -1336,15 +1337,18 @@ static int iucv_sock_recvmsg(struct socket *sock, struct msghdr *msg,
 				iucv_process_message_q(sk);
 			if (iucv->transport == AF_IUCV_TRANS_HIPER &&
 			    atomic_read(&iucv->msg_recv) >=
-							iucv->msglimit / 2) {
-				err = iucv_send_ctrl(sk, AF_IUCV_FLAG_WIN);
-				if (err) {
-					sk->sk_state = IUCV_DISCONN;
-					sk->sk_state_change(sk);
-				}
-			}
+							iucv->msglimit / 2)
+				send_win = true;
 		}
 		spin_unlock_bh(&iucv->message_q.lock);
+
+		if (send_win) {
+			err = iucv_send_ctrl(sk, AF_IUCV_FLAG_WIN);
+			if (err) {
+				sk->sk_state = IUCV_DISCONN;
+				sk->sk_state_change(sk);
+			}
+		}
 	}
 
 done:

-- 
2.55.0



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH net v2 3/3] net/iucv: send the window update outside message_q.lock
  2026-08-21 11:17 ` [PATCH net v2 3/3] net/iucv: send the window update outside message_q.lock Bryam Vargas via B4 Relay
@ 2026-08-22 11:17   ` sashiko-bot
  2026-08-24 12:58     ` Alexandra Winter
  0 siblings, 1 reply; 10+ messages in thread
From: sashiko-bot @ 2026-08-22 11:17 UTC (permalink / raw)
  To: Bryam Vargas
  Cc: Vasily Gorbik, Christian Borntraeger, Heiko Carstens,
	Alexander Gordeev, linux-s390

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

New issues:
- [High] Redundant concurrent window updates cause spurious socket disconnections due to transient errors.
- [High] Lockless modification of `sk->sk_state` to `IUCV_DISCONN` in error path corrupts the socket state machine.

Pre-existing issues:
- [Critical] Concurrent execution of `iucv_sock_recvmsg` and `iucv_sock_close` can lead to a NULL pointer dereference of `iucv->hs_dev`.
- [High] Lockless read-modify-write sequence on `sk->sk_shutdown` in `iucv_send_ctrl` permanently loses concurrent state updates.
--

--- Patch [3]: [PATCH net v2 3/3] net/iucv: send the window update outside message_q.lock ---
commit 38dc50c2f4dfcebf699da12476bf1a5fb529484e
Author: Bryam Vargas <hexlabsecurity@proton.me>

net/iucv: send the window update outside message_q.lock

This patch moves the window update control message dispatch outside the
message_q.lock in iucv_sock_recvmsg(). It avoids sleeping in atomic context
since iucv_send_ctrl() performs a GFP_KERNEL allocation. A boolean flag is
used to defer the send until after the lock is released.

> diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
> --- a/net/iucv/af_iucv.c
> +++ b/net/iucv/af_iucv.c
[ ... ]
> @@ -1336,15 +1337,18 @@ static int iucv_sock_recvmsg(struct socket *sock, struct msghdr *msg,
>  				iucv_process_message_q(sk);
>  			if (iucv->transport == AF_IUCV_TRANS_HIPER &&
>  			    atomic_read(&iucv->msg_recv) >=
> -							iucv->msglimit / 2) {
> -				err = iucv_send_ctrl(sk, AF_IUCV_FLAG_WIN);
> -				if (err) {
> -					sk->sk_state = IUCV_DISCONN;
> -					sk->sk_state_change(sk);
> -				}
> -			}
> +							iucv->msglimit / 2)
> +				send_win = true;
>  		}
>  		spin_unlock_bh(&iucv->message_q.lock);
> +
> +		if (send_win) {
> +			err = iucv_send_ctrl(sk, AF_IUCV_FLAG_WIN);

[Severity: High]
Because atomic_read(&iucv->msg_recv) is checked inside the lock, but the
counter is reset later inside afiucv_hs_send() without holding
message_q.lock, can multiple concurrent calls to iucv_sock_recvmsg() set
send_win to true and trigger redundant window updates?

If redundant updates are sent, could transient send buffer exhaustion cause
the socket to unintentionally hit the error path below and disconnect?

[Severity: Critical]
This isn't a bug introduced by this patch, but calling iucv_send_ctrl()
concurrently here exposes a pre-existing race condition.

In iucv_send_ctrl(), LL_RESERVED_SPACE() dereferences iucv->hs_dev:

iucv_send_ctrl()
    blen = sizeof(struct af_iucv_trans_hdr) +
           LL_RESERVED_SPACE(iucv->hs_dev);

If a concurrent thread executes iucv_sock_close() and sets iucv->hs_dev
to NULL, does this cause a NULL pointer dereference?

[Severity: High]
This is a pre-existing issue, but there appears to be a concurrency
regression in iucv_send_ctrl() when it caches sk->sk_shutdown.

iucv_send_ctrl()
    if (sk->sk_shutdown & SEND_SHUTDOWN) {
        shutdown = sk->sk_shutdown;
        sk->sk_shutdown &= RCV_SHUTDOWN;
    }
    skb = sock_alloc_send_skb(sk, blen, 1, &err);
    ...
    if (shutdown)
        sk->sk_shutdown = shutdown;

Since sock_alloc_send_skb() can sleep, if another thread updates
sk->sk_shutdown (for example, via shutdown(fd, SHUT_RD)) during the
allocation, does the unconditional restore of the cached shutdown state
overwrite and permanently lose the concurrent update?

> +			if (err) {
> +				sk->sk_state = IUCV_DISCONN;
> +				sk->sk_state_change(sk);
> +			}
> +		}

[Severity: High]
Does modifying sk->sk_state and calling sk->sk_state_change(sk) locklessly
outside of message_q.lock or lock_sock() corrupt the socket state machine?

If multiple threads hit this error path simultaneously, could it lead to
unordered execution of state change callbacks?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260821-b4-disp-3a6e8695-v2-0-37597ff723a8@proton.me?part=3

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH net v2 2/3] net/iucv: claim the receive credit atomically
  2026-08-21 11:17 ` [PATCH net v2 2/3] net/iucv: claim the receive credit atomically Bryam Vargas via B4 Relay
@ 2026-08-22 11:17   ` sashiko-bot
  0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-08-22 11:17 UTC (permalink / raw)
  To: Bryam Vargas
  Cc: linux-s390, Christian Borntraeger, Heiko Carstens,
	Alexander Gordeev, Vasily Gorbik

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

Pre-existing issues:
- [High] Positive network drop errors leak to userspace as partial success
- [High] Silent data loss for SOCK_STREAM when packet length exceeds MTU
--

--- Patch [2]: [PATCH net v2 2/3] net/iucv: claim the receive credit atomically ---
commit 20117da9fdf439cdc2d9a9928d88d8e19d4f0e83
Author: Bryam Vargas <hexlabsecurity@proton.me>

net/iucv: claim the receive credit atomically

This commit addresses a race condition in the af_iucv HiperSockets
transport where the receive credit counter could be subtracted multiple times.
It modifies the code to claim the window using atomic_xchg() right before
queueing the packet to ensure the counter reads zero while the transmit
is in flight.

> diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
> index 0bc4a15f4b565..492a45bb2bba6 100644
> --- a/net/iucv/af_iucv.c
> +++ b/net/iucv/af_iucv.c

[ ... ]

> @@ -250,13 +244,22 @@ static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock,
>  	}
>  	skb->protocol = cpu_to_be16(ETH_P_AF_IUCV);

[Severity: High]
This isn't a bug introduced by this patch, but I noticed a potential issue with
the MTU check just above this line in afiucv_hs_send():

	if (skb->len > skb->dev->mtu) {
		if (sock->sk_type == SOCK_SEQPACKET) {
			err = -EMSGSIZE;
			goto err_free;
		}
		err = pskb_trim(skb, skb->dev->mtu);
		if (err)
			goto err_free;
	}

For SOCK_STREAM sockets, if the packet is larger than the MTU, the skb is
silently truncated via pskb_trim().

However, iucv_sock_sendmsg() isn't aware of this truncation and returns the full
original length to userspace on success:

	err = afiucv_hs_send(&txmsg, sk, skb, 0);
	...
	release_sock(sk);
	return len;

Does this result in silent data loss, since userspace believes the entire buffer
was successfully sent?

>  
> +	/* Claim the receive credit here, not while building the header: every
> +	 * way this frame can be dropped has now been ruled out, so the window
> +	 * is zeroed only for as long as the transmit itself takes.
> +	 */
> +	if (flags == AF_IUCV_FLAG_WIN || !flags) {
> +		confirm_recv = atomic_xchg(&iucv->msg_recv, 0);
> +		phs_hdr->window = confirm_recv;
> +		if (confirm_recv)
> +			phs_hdr->flags = phs_hdr->flags | AF_IUCV_FLAG_WIN;
> +	}
> +
>  	atomic_inc(&iucv->skbs_in_xmit);
>  	err = dev_queue_xmit(skb);
>  	if (net_xmit_eval(err)) {
>  		atomic_dec(&iucv->skbs_in_xmit);
> -	} else {
> -		atomic_sub(confirm_recv, &iucv->msg_recv);
> -		WARN_ON(atomic_read(&iucv->msg_recv) < 0);
> +		atomic_add(confirm_recv, &iucv->msg_recv);
>  	}
>  	return net_xmit_eval(err);

[Severity: High]
This is a pre-existing issue, but I wanted to ask about the return value here.

When dev_queue_xmit() drops a packet, it returns NET_XMIT_DROP (0x01).
net_xmit_eval() translates NET_XMIT_DROP to 1, and returning this positive value
propagates to iucv_sock_sendmsg().

Since iucv_sock_sendmsg() passes positive error codes back to the socket layer:

	err = afiucv_hs_send(&txmsg, sk, skb, 0);
	if (err) {
		atomic_dec(&iucv->msg_sent);
		goto out;
	}

Could sys_sendmsg interpret the return value of 1 as 1 byte successfully sent,
causing userspace to incorrectly assume partial success and potentially enter
an infinite loop retrying the remaining data?

Should this be returning net_xmit_errno(err) instead of net_xmit_eval(err)?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260821-b4-disp-3a6e8695-v2-0-37597ff723a8@proton.me?part=2

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH net v2 1/3] net/iucv: only send the window update on HiperSockets sockets
  2026-08-21 11:17 ` [PATCH net v2 1/3] net/iucv: only send the window update on HiperSockets sockets Bryam Vargas via B4 Relay
@ 2026-08-22 11:17   ` sashiko-bot
  0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-08-22 11:17 UTC (permalink / raw)
  To: Bryam Vargas
  Cc: Heiko Carstens, Christian Borntraeger, linux-s390,
	Alexander Gordeev, Vasily Gorbik

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:

Pre-existing issues:
- [High] `iucv_sock_recvmsg` and `iucv_send_ctrl` perform unprotected read-modify-restore operations on `sk->sk_shutdown`, clobbering concurrent state changes from `shutdown()`.
- [High] Concurrent execution within `iucv_sock_recvmsg()` can cause a data race leading to a NULL pointer dereference of `iucv->hs_dev`.
- [High] Iterating over `iucv_sk_list.head` without acquiring the associated lock leads to race conditions and potential use-after-free or list corruption.
--

--- Patch [1]: [PATCH net v2 1/3] net/iucv: only send the window update on HiperSockets sockets ---
commit 50e666866fa1b6d2153e6efa369820e5171cf305
Author: Bryam Vargas <hexlabsecurity@proton.me>

net/iucv: only send the window update on HiperSockets sockets

This commit fixes an issue where an unconditional window update on classic
z/VM sockets can result in a spurious disconnect or a fault. It adds a check
to only send the window update if the transport is HiperSockets.

Cc: stable@vger.kernel.org

> diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
> index ea047bab65e7c..0bc4a15f4b565 100644
> --- a/net/iucv/af_iucv.c
> +++ b/net/iucv/af_iucv.c
> @@ -1331,7 +1331,8 @@ static int iucv_sock_recvmsg(struct socket *sock, struct msghdr *msg,
>  		if (skb_queue_empty(&iucv->backlog_skb_q)) {
>  			if (!list_empty(&iucv->message_q.list))
>  				iucv_process_message_q(sk);
> -			if (atomic_read(&iucv->msg_recv) >=
> +			if (iucv->transport == AF_IUCV_TRANS_HIPER &&
> +			    atomic_read(&iucv->msg_recv) >=
>  							iucv->msglimit / 2) {
>  				err = iucv_send_ctrl(sk, AF_IUCV_FLAG_WIN);

[Severity: High]
This is a pre-existing issue, but could concurrent execution within
iucv_sock_recvmsg() cause a data race leading to a NULL pointer dereference
of iucv->hs_dev?

If multiple threads execute recvmsg() concurrently on the same socket, they
can dequeue packets and increment iucv->msg_recv without mutual exclusion
earlier in the function:

    if (atomic_read(&iucv->msg_recv) > iucv->msglimit) {
        WARN_ON(1);
        iucv_sock_close(sk);
        return -EFAULT;
    }

Calling iucv_sock_close() acquires the socket lock, drops the device
reference, and sets iucv->hs_dev = NULL.

Another concurrent thread executing recvmsg() might evaluate the send_win
condition as true and subsequently call iucv_send_ctrl(sk, AF_IUCV_FLAG_WIN).

Since iucv_send_ctrl() accesses iucv->hs_dev via LL_RESERVED_SPACE() without
holding the socket lock:

    blen = sizeof(struct af_iucv_trans_hdr) +
           LL_RESERVED_SPACE(iucv->hs_dev);

wouldn't this dereference NULL if the first thread nullified the device
pointer?

[Severity: High]
This is a pre-existing issue, but is it possible for concurrent updates to
sk_shutdown to be lost?

Looking at iucv_sock_recvmsg(), we modify sk_shutdown directly without
holding the socket lock:

    if (!rlen)
        sk->sk_shutdown = sk->sk_shutdown | RCV_SHUTDOWN;

Additionally, in iucv_send_ctrl(), the stale state is saved, modified, and
blindly restored without locking:

    shutdown = sk->sk_shutdown;
    sk->sk_shutdown &= RCV_SHUTDOWN;
    ...
    if (shutdown)
        sk->sk_shutdown = shutdown;

If Thread A executes recvmsg() while Thread B concurrently executes shutdown(),
could Thread A overwrite and erase the flags (e.g., SEND_SHUTDOWN) set by
Thread B?

[Severity: High]
This is a pre-existing issue, but does iterating over iucv_sk_list.head
without acquiring the associated lock in afiucv_netdev_event() lead to
race conditions?

net/iucv/af_iucv.c:afiucv_netdev_event() {
    ...
    case NETDEV_GOING_DOWN:
        sk_for_each(sk, &iucv_sk_list.head) {
            iucv = iucv_sk(sk);
            if ((iucv->hs_dev == event_dev) &&
    ...
}

Concurrently, if a socket is created (iucv_sock_bind) or destroyed
(iucv_sock_kill), the list is mutated under write_lock_bh(&iucv_sk_list.lock).

Could this lockless traversal dereference invalid pointers or freed socket
structures during a NETDEV_GOING_DOWN or NETDEV_REBOOT event?

>  				if (err) {
>  					sk->sk_state = IUCV_DISCONN;
>  					sk->sk_state_change(sk);
>  				}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260821-b4-disp-3a6e8695-v2-0-37597ff723a8@proton.me?part=1

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH net v2 3/3] net/iucv: send the window update outside message_q.lock
  2026-08-22 11:17   ` sashiko-bot
@ 2026-08-24 12:58     ` Alexandra Winter
  0 siblings, 0 replies; 10+ messages in thread
From: Alexandra Winter @ 2026-08-24 12:58 UTC (permalink / raw)
  To: sashiko-reviews, Bryam Vargas
  Cc: Vasily Gorbik, Christian Borntraeger, Heiko Carstens,
	Alexander Gordeev, linux-s390



On 22.08.26 13:17, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
> 
> New issues:
> - [High] Redundant concurrent window updates cause spurious socket disconnections due to transient errors.
> - [High] Lockless modification of `sk->sk_state` to `IUCV_DISCONN` in error path corrupts the socket state machine.
> 
> Pre-existing issues:
> - [Critical] Concurrent execution of `iucv_sock_recvmsg` and `iucv_sock_close` can lead to a NULL pointer dereference of `iucv->hs_dev`.
> - [High] Lockless read-modify-write sequence on `sk->sk_shutdown` in `iucv_send_ctrl` permanently loses concurrent state updates.
> --
> 
> --- Patch [3]: [PATCH net v2 3/3] net/iucv: send the window update outside message_q.lock ---
> commit 38dc50c2f4dfcebf699da12476bf1a5fb529484e
> Author: Bryam Vargas <hexlabsecurity@proton.me>
> 
> net/iucv: send the window update outside message_q.lock
> 
> This patch moves the window update control message dispatch outside the
> message_q.lock in iucv_sock_recvmsg(). It avoids sleeping in atomic context
> since iucv_send_ctrl() performs a GFP_KERNEL allocation. A boolean flag is
> used to defer the send until after the lock is released.
> 
>> diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
>> --- a/net/iucv/af_iucv.c
>> +++ b/net/iucv/af_iucv.c
> [ ... ]
>> @@ -1336,15 +1337,18 @@ static int iucv_sock_recvmsg(struct socket *sock, struct msghdr *msg,
>>  				iucv_process_message_q(sk);
>>  			if (iucv->transport == AF_IUCV_TRANS_HIPER &&
>>  			    atomic_read(&iucv->msg_recv) >=
>> -							iucv->msglimit / 2) {
>> -				err = iucv_send_ctrl(sk, AF_IUCV_FLAG_WIN);
>> -				if (err) {
>> -					sk->sk_state = IUCV_DISCONN;
>> -					sk->sk_state_change(sk);
>> -				}
>> -			}
>> +							iucv->msglimit / 2)
>> +				send_win = true;
>>  		}
>>  		spin_unlock_bh(&iucv->message_q.lock);
>> +
>> +		if (send_win) {
>> +			err = iucv_send_ctrl(sk, AF_IUCV_FLAG_WIN);
> 
> [Severity: High]
> Because atomic_read(&iucv->msg_recv) is checked inside the lock, but the
> counter is reset later inside afiucv_hs_send() without holding
> message_q.lock, can multiple concurrent calls to iucv_sock_recvmsg() set
> send_win to true and trigger redundant window updates?
> 

No, because of the previous patch that is mentioned as a precondition.


> If redundant updates are sent, could transient send buffer exhaustion cause
> the socket to unintentionally hit the error path below and disconnect?

I'm not sure I understand the question. But I think this works as designed.




^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH net v2 0/3] net/iucv: fix the recvmsg window update
  2026-08-21 11:17 [PATCH net v2 0/3] net/iucv: fix the recvmsg window update Bryam Vargas via B4 Relay
                   ` (2 preceding siblings ...)
  2026-08-21 11:17 ` [PATCH net v2 3/3] net/iucv: send the window update outside message_q.lock Bryam Vargas via B4 Relay
@ 2026-08-24 13:08 ` Alexandra Winter
  2026-08-25 13:17 ` Aswin Karuvally
  4 siblings, 0 replies; 10+ messages in thread
From: Alexandra Winter @ 2026-08-24 13:08 UTC (permalink / raw)
  To: hexlabsecurity, Eric Dumazet, Paolo Abeni, Jakub Kicinski,
	Thorsten Winkler, David S. Miller
  Cc: Hidayath Khan, Simon Horman, linux-kernel, netdev, linux-s390,
	Ursula Braun



On 21.08.26 13:17, Bryam Vargas via B4 Relay wrote:
> v2 answers Jakub's reviews of v1 with changes rather than replies.
> 
> 1/3 keeps its hunk and states the impact properly. SO_MSGLIMIT accepts 1,
> which makes msglimit / 2 zero, and msg_recv never leaves zero on a classic
> socket, so the NULL read is one recvmsg() away for an unprivileged process
> on a socket of its own. With relocate_lowcore it faults.
> 
> Its Fixes: tag was wrong as well. The unconditional send does date to
> 3881ac441f64, but iucv_send_ctrl() sized the skb with a constant ETH_HLEN
> until 238965b71b96, so before that it just returned -ENODEV. Backport
> window is v5.3, not v3.1.
> 
> 2/3 is new. v1 admitted it widened the msg_recv race and left it open,
> which isn't good enough under Cc: stable. afiucv_hs_send() samples the
> counter and settles it after dev_queue_xmit(); sendmsg reaches that under
> lock_sock() and recvmsg reaches it under no socket lock, so the two don't
> exclude each other and both can subtract the same value. Negative counter,
> WARN_ON, and the same credit advertised twice to a peer whose
> afiucv_hs_callback_win() subtracts the wire value from msg_sent unchecked.
> 
> Taking the socket lock around the deferred send would close it too, since
> recvmsg is the only unlocked side. I didn't: recvmsg has never held that
> lock, and making it do so changes the receive path for every caller. That
> belongs in the locking rework, not in a stable fix.
> 
> The claim sits after the last error exit rather than in the header build,
> so the counter reads zero only while the transmit is in flight, and a
> concurrent sender isn't talked out of its own update.
> 
> 3/3 is v1's patch, and it must not be applied without 2/3: hoisting the
> send out of message_q.lock drops the serialisation that lock gave two
> concurrent recvmsg(). Backported alone it recreates what 2/3 fixes. Both
> changelogs say so.
> 
> Litmus test under LKMM: the counter reaches -2 before 2/3 and cannot after.
> No hardware run; I have no IBM Z, and CONFIG_AFIUCV is s390-only.
> 
> The unlocked hs_dev and sk_shutdown window, the unbounded backlog_skb_q and
> the WARN_ON a flooding peer can reach are pre-existing and wider than this
> series. They belong with the locking rework Alexandra has open.
> 
> Thanks for the reviews.
> 
> ---
> Bryam Vargas (3):
>       net/iucv: only send the window update on HiperSockets sockets
>       net/iucv: claim the receive credit atomically
>       net/iucv: send the window update outside message_q.lock
> 
>  net/iucv/af_iucv.c | 42 +++++++++++++++++++++++++-----------------
>  1 file changed, 25 insertions(+), 17 deletions(-)
> ---
> base-commit: 746fc0787f616da418ffc04a110296fe95d53491
> change-id: 20260821-b4-disp-3a6e8695-c1f4a6069169
> 
> Best regards,
> --  
> Bryam Vargas <hexlabsecurity@proton.me>
> 
> 
> 

Thank you for the fixes Bryam.
I have reviewed them and would technically give an R-b to all three.

However I propose to send them again as one single patch. They are
really about the same subject: iucv->msg_recv handling and even have
a dependency, as you rightfully noted.
It will be much easier to proceed and to backport them, if it is only
one patch.

I know it's a tradeoff, but I think we will do ourselves and the
upstream maintainers a favor, if we send not too small fragments
of fixes.






^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH net v2 0/3] net/iucv: fix the recvmsg window update
  2026-08-21 11:17 [PATCH net v2 0/3] net/iucv: fix the recvmsg window update Bryam Vargas via B4 Relay
                   ` (3 preceding siblings ...)
  2026-08-24 13:08 ` [PATCH net v2 0/3] net/iucv: fix the recvmsg window update Alexandra Winter
@ 2026-08-25 13:17 ` Aswin Karuvally
  4 siblings, 0 replies; 10+ messages in thread
From: Aswin Karuvally @ 2026-08-25 13:17 UTC (permalink / raw)
  To: hexlabsecurity, Eric Dumazet, Paolo Abeni, Jakub Kicinski,
	Alexandra Winter, Thorsten Winkler, David S. Miller
  Cc: Hidayath Khan, Simon Horman, linux-kernel, netdev, linux-s390,
	Ursula Braun

On 21/08/26 16:47, Bryam Vargas via B4 Relay wrote:
> v2 answers Jakub's reviews of v1 with changes rather than replies.
> 
> 1/3 keeps its hunk and states the impact properly. SO_MSGLIMIT accepts 1,
> which makes msglimit / 2 zero, and msg_recv never leaves zero on a classic
> socket, so the NULL read is one recvmsg() away for an unprivileged process
> on a socket of its own. With relocate_lowcore it faults.
> 
> Its Fixes: tag was wrong as well. The unconditional send does date to
> 3881ac441f64, but iucv_send_ctrl() sized the skb with a constant ETH_HLEN
> until 238965b71b96, so before that it just returned -ENODEV. Backport
> window is v5.3, not v3.1.
> 
> 2/3 is new. v1 admitted it widened the msg_recv race and left it open,
> which isn't good enough under Cc: stable. afiucv_hs_send() samples the
> counter and settles it after dev_queue_xmit(); sendmsg reaches that under
> lock_sock() and recvmsg reaches it under no socket lock, so the two don't
> exclude each other and both can subtract the same value. Negative counter,
> WARN_ON, and the same credit advertised twice to a peer whose
> afiucv_hs_callback_win() subtracts the wire value from msg_sent unchecked.
> 
> Taking the socket lock around the deferred send would close it too, since
> recvmsg is the only unlocked side. I didn't: recvmsg has never held that
> lock, and making it do so changes the receive path for every caller. That
> belongs in the locking rework, not in a stable fix.
> 
> The claim sits after the last error exit rather than in the header build,
> so the counter reads zero only while the transmit is in flight, and a
> concurrent sender isn't talked out of its own update.
> 
> 3/3 is v1's patch, and it must not be applied without 2/3: hoisting the
> send out of message_q.lock drops the serialisation that lock gave two
> concurrent recvmsg(). Backported alone it recreates what 2/3 fixes. Both
> changelogs say so.
> 
> Litmus test under LKMM: the counter reaches -2 before 2/3 and cannot after.
> No hardware run; I have no IBM Z, and CONFIG_AFIUCV is s390-only.
> 
> The unlocked hs_dev and sk_shutdown window, the unbounded backlog_skb_q and
> the WARN_ON a flooding peer can reach are pre-existing and wider than this
> series. They belong with the locking rework Alexandra has open.
> 
> Thanks for the reviews.
> 
> ---
> Bryam Vargas (3):
>       net/iucv: only send the window update on HiperSockets sockets
>       net/iucv: claim the receive credit atomically
>       net/iucv: send the window update outside message_q.lock
> 
>  net/iucv/af_iucv.c | 42 +++++++++++++++++++++++++-----------------
>  1 file changed, 25 insertions(+), 17 deletions(-)
> ---
> base-commit: 746fc0787f616da418ffc04a110296fe95d53491
> change-id: 20260821-b4-disp-3a6e8695-c1f4a6069169
> 
> Best regards,
> --  
> Bryam Vargas <hexlabsecurity@proton.me>

Thank you for the fixes Bryam!

Tested-by: Aswin Karuvally <aswin@linux.ibm.com>

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2026-08-25 13:18 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-21 11:17 [PATCH net v2 0/3] net/iucv: fix the recvmsg window update Bryam Vargas via B4 Relay
2026-08-21 11:17 ` [PATCH net v2 1/3] net/iucv: only send the window update on HiperSockets sockets Bryam Vargas via B4 Relay
2026-08-22 11:17   ` sashiko-bot
2026-08-21 11:17 ` [PATCH net v2 2/3] net/iucv: claim the receive credit atomically Bryam Vargas via B4 Relay
2026-08-22 11:17   ` sashiko-bot
2026-08-21 11:17 ` [PATCH net v2 3/3] net/iucv: send the window update outside message_q.lock Bryam Vargas via B4 Relay
2026-08-22 11:17   ` sashiko-bot
2026-08-24 12:58     ` Alexandra Winter
2026-08-24 13:08 ` [PATCH net v2 0/3] net/iucv: fix the recvmsg window update Alexandra Winter
2026-08-25 13:17 ` Aswin Karuvally

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox