Netdev List
 help / color / mirror / Atom feed
From: Hidayath Khan <hidayath@linux.ibm.com>
To: hexlabsecurity@proton.me, Paolo Abeni <pabeni@redhat.com>,
	Jakub Kicinski <kuba@kernel.org>,
	Thorsten Winkler <twinkler@linux.ibm.com>,
	Eric Dumazet <edumazet@kernel.org>,
	Alexandra Winter <wintera@linux.ibm.com>,
	"David S. Miller" <davem@davemloft.net>
Cc: Nagamani PV <nagamani@linux.ibm.com>,
	netdev@vger.kernel.org, Simon Horman <horms@kernel.org>,
	linux-s390@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH net-next] net/iucv: serialize HiperSockets receive with the socket lock
Date: Sun, 18 Oct 2026 00:08:20 +0530	[thread overview]
Message-ID: <b3fea2ca-25ff-42c0-812c-f8cc6bb6667e@linux.ibm.com> (raw)
In-Reply-To: <82691101-92d7-4838-b16e-2e41a83f65d0@linux.ibm.com>


On 14/10/26 4:42 am, Hidayath Khan wrote:
> Hi Bryam,
>
> Below are the test results for this stage 1 patch on z/VM.
>
> Setup: one z/VM guest, two HiperSockets hsuids, two CPUs, af_iucv as a
> module, and an AF_IUCV socket-locking reproducer. Both kernels have 
> the same
> config - CONFIG_KASAN=y, CONFIG_PROVE_LOCKING=y and
> CONFIG_DEBUG_ATOMIC_SLEEP=y - so the only variable is the patch.
>
>   scenario     net-next,               patch
>   sk_shutdown  fail, 271-299 misses    pass, 0 in 9058 cycles
>   shut_rd      fail, fail, pass        pass, 0 in 29 cycles
>   recvrecv     fail, 3658-4139 back.   pass, 0 out-of-order in 4194304 
> words
>   backlog      pass                    pass
>   rxclose      fail, 16-17 of 35-38    fail, 14 of 57
>   spin         fail, 2020-2190 ms CPU  fail, 2070 ms CPU
>
> No KASAN, lockdep or DEBUG_ATOMIC_SLEEP report on either kernel, in 
> dmesg or
> the journal - so nothing reports here either way, and the patch 
> introduces
> nothing. Since this patch adds local_bh_disable() around the backlog 
> replay,
> moves __iucv_sock_close() into recvmsg() under lock_sock() and holds 
> the socket
> lock across copy_to_user(), that was the result I was most interested in.
>
> backlog passed on both - it is a guard rather than a reproducer, and 0
> frames lost over roughly 1.1 million ownership windows on net-next 
> confirms
> it has no discriminating power here, so it says nothing either way.
>
> shut_rd is too flaky to lean on: on net-next it failed with 2 misses 
> in 43
> cycles and 3 in 35, then passed with 0 in 45. So its single pass with the
> patch is not evidence. Its window is now narrow enough that 30 s under 
> KASAN
> is not enough cycles; I will re-run it much longer.
>
> sk_shutdown and recvrecv are the solid ones. recvrecv is what I would 
> point
> at: two readers interleaving inside an unlocked iucv_sock_recvmsg() went
> backwards 3658, 3896 and 4139 times across the three net-next runs and 
> not
> once with your patch.
>
> rxclose fails on both, on the -ENOTCONN that Sashiko flags as Low: 17 
> of 37,
> 17 of 38 and 16 of 35 on net-next against 14 of 57 with your patch. Lower
> with the patch, but that is one patched run against three, so I would not
> read much into the difference. 0 lost tails in every run - though the
> lost-tail check only runs on cycles that reached EOF, so the failing 
> cycles
> are not data-checked. The test counts any errno other than EINTR and 
> EAGAIN
> as a wrong termination, which is why -ENOTCONN shows as a failure.
>
> The asymmetry is that recvmsg()'s shortcut gives EOF on IUCV_DISCONN with
> the queues empty, while iucv_sock_recv_skb() gives -ENOTCONN on
> sk_state != IUCV_CONNECTED. Either the loop returns EOF for IUCV_DISCONN
> with nothing queued, or afiucv_hs_callback_fin() sets RCV_SHUTDOWN as 
> well -
> that one is a single line but also changes what callback_rx() drops 
> and what
> iucv_sock_poll() reports. I have tried neither. Which behaviour do you 
> want?
>
> spin fails on both, and by the same margin: 2020, 2150 and 2190 ms of CPU
> while blocked about 3000 ms on net-next, 2070 ms with your patch.
> __iucv_sock_wait() still calls prepare_to_wait() once, outside its 
> loop, so
> after the first schedule_timeout() the task is TASK_RUNNING. Outside your
> diff, and a different bug from the missed wakeup you fix at the same call
> site. One-liner; I will send it separately.
>
> On KASAN specifically, so an empty result is not read as a gap: there 
> will
> be no KASAN report from these scenarios even on a KASAN kernel. The
> reproducer does scan /dev/kmsg for KASAN and KCSAN reports and fails a
> scenario on any hit, but stage 1's defects are missing locks - they 
> surface
> as lost data, a lost sk_shutdown bit, a wrong errno or a leaked 
> socket, none
> of which touch freed or out-of-bounds memory. KASAN is a clean-run 
> control
> here. KCSAN is what can witness the accesses still left unlocked; note 
> that
> it generally does not flag volatile accesses, so it may not show sk_state
> races either. A KCSAN run is next.
>
> Sashiko's three budget findings look to me like instances of one 
> thing, and
> it says so itself on the SO_MSGLIMIT case: stream data is "lost 
> without any
> error". A frame that does not fit is dropped with nothing but
> sk_drops_inc() and kfree_skb_reason(). Resizing a budget per instance 
> leaves
> the next one open.
>
> Sashiko's three budget findings look like one thing: a frame that does 
> not fit
> is dropped with only sk_drops_inc() and kfree_skb_reason(), so resizing a
> budget per instance leaves the next one open. Would you take a patch 
> on top
> that makes the loss visible instead - the softirq sets a bit in 
> iucv_sock, and
> iucv_sock_release_cb() turns it into sk_err = ECONNRESET plus 
> IUCV_DISCONN once
> the owner lets go? Separately: would it be simpler not to defer
> a pure WIN at all? afiucv_hs_callback_win() is only an atomic_sub() and
> iucv_sock_wake_msglim().
>
> Thanks,
> Hidayath
>

Hi Bryam,

Follow-up to the earlier KASAN + PROVE_LOCKING + DEBUG_ATOMIC_SLEEP results.

I ran the same reproducer on the same z/VM guest with a KCSAN build of your
patch, interrupt watcher on. KCSAN found two af_iucv data races. Both
appeared during the sk_shutdown scenario. The second also appeared once in
rxclose scenario. I have the full KCSAN reports from /dev/kmsg now, so
the fields below are from them rather than from reading the code.

1) sk->sk_shutdown, 1 byte, same address on both sides.

A marked read in afiucv_hs_callback_rx(), inlined into afiucv_hs_dispatch():

     if (READ_ONCE(sk->sk_shutdown) & RCV_SHUTDOWN)

by interrupt on one CPU, against the plain read-modify-write in
iucv_sock_shutdown():

     sk->sk_shutdown |= how;

by task on the other CPU. The report gives the contexts as interrupt and 
task;
that the writer holds lock_sock() is from the source - iucv_sock_shutdown()
takes it on entry and that line is on every path to it.

The receive side must have come through the !afiucv_hs_defer() bypass rather
than the !sock_owned_by_user() arm. The writer holds lock_sock(), so
sk_lock.owned is set and slock is free; the reader runs inside 
bh_lock_sock(),
which is slock. For the two to overlap, the task must have finished
lock_sock() before the softirq took slock - so sock_owned_by_user() was 
true
when the softirq checked it. On the other arm the softirq holds slock while
nobody owns the socket, and a task entering lock_sock() blocks on slock 
until
the callback returns, so it cannot reach the write.

That is the window I asked you about in the previous comment, where a frame
can also be queued after shutdown(SHUT_RD)'s skb_queue_purge(), and which I
could not get to fire functionally. It has a KCSAN report behind it now.

Making the write a WRITE_ONCE() would silence KCSAN and fix nothing. The
frame-after-purge behaviour looks like an ordering problem.

2) iucv->hs_dev, 8 bytes, same address on both sides.

A plain read in afiucv_hs_rcv()'s socket-lookup loop:

     if (iucv_sk(sk)->hs_dev != dev)

by interrupt, with only read_lock(&iucv_sk_list.lock) held, against the 
plain
write in __iucv_sock_close():

     iucv->hs_dev = NULL;

by task, from an ordinary close() - the stack is iucv_sock_release ->
sock_close -> __fput -> sys_close, so the socket lock is held there.

The read is the ingress check added by Alexandra's 80230a18c164 and the
write was already there, so neither line is from your patches.
I do not think it needs locking: the lookup is inherently racy with close,
since the socket can be closed between the match and the dispatch however
well hs_dev is synchronised. I think both outcomes are harmless - observing
NULL early drops a frame that was about to be dropped anyway, and 
observing a
stale pointer gets the frame as far as the callbacks, which drop it on
sk_state. So I think the right treatment is READ_ONCE()/WRITE_ONCE() on the
two accesses with a comment saying the lookup read is deliberately
unsynchronised, rather than anything structural. Tell me if you see it
differently.

One more thing in the same function. __iucv_sock_close() does

     dev_put(iucv->hs_dev);
     iucv->hs_dev = NULL;

so between those two statements hs_dev names a device this socket no longer
holds a reference to, and the lookup loop can match on it. Clearing before
the put removes that window - via a local, since swapping the lines as they
stand would dev_put(NULL) and leak the reference:

     struct net_device *dev = iucv->hs_dev;

     if (dev) {
         iucv->hs_dev = NULL;
         sk->sk_bound_dev_if = 0;
         dev_put(dev);
     }

The test run also has 500+ KCSAN reports with skb_copy_bits / 
__might_fault.
All of them have
afiucv_hs_rcv() -> pskb_may_pull() -> __pskb_pull_tail() in the stack.
The conflict is on current->pagefault_disabled not skb data, so I don't 
think
either of your patches is involved.

Functionally the KCSAN kernel showed nothing new - the same rxclose and spin
failures as previous comment, everything else is clean.

Thanks,
Hidayath

      reply	other threads:[~2026-10-17 18:38 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-11 19:08 [PATCH net-next] net/iucv: serialize HiperSockets receive with the socket lock Bryam Vargas via B4 Relay
2026-10-12 19:45 ` netdev-bot+sashiko
2026-10-13 23:12 ` Hidayath Khan
2026-10-17 18:38   ` Hidayath Khan [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=b3fea2ca-25ff-42c0-812c-f8cc6bb6667e@linux.ibm.com \
    --to=hidayath@linux.ibm.com \
    --cc=davem@davemloft.net \
    --cc=edumazet@kernel.org \
    --cc=hexlabsecurity@proton.me \
    --cc=horms@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-s390@vger.kernel.org \
    --cc=nagamani@linux.ibm.com \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=twinkler@linux.ibm.com \
    --cc=wintera@linux.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox