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
next prev parent reply other threads:[~2026-10-17 18:38 UTC|newest]
Thread overview: 9+ 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-11 19:08 ` Bryam Vargas
2026-10-12 19:08 ` sashiko-bot
2026-10-12 19:45 ` netdev-bot+sashiko
2026-10-13 23:12 ` Hidayath Khan
2026-10-17 18:38 ` Hidayath Khan [this message]
2026-10-19 18:01 ` Hidayath Khan
2026-10-23 3:14 ` Bryam Vargas
2026-10-20 1:32 ` Jakub Kicinski
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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.