All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] af_unix: Fix priority inversion issue
@ 2026-07-01 16:35 Nam Cao
  2026-07-01 16:35 ` [PATCH 1/2] af_unix: Do not wait for garbage collector in sendmsg() Nam Cao
  2026-07-01 16:35 ` [PATCH 2/2] af_unix: Clean up unix_schedule_gc() Nam Cao
  0 siblings, 2 replies; 11+ messages in thread
From: Nam Cao @ 2026-07-01 16:35 UTC (permalink / raw)
  To: Kuniyuki Iwashima, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, netdev, linux-kernel, linux-rt-devel
  Cc: Nam Cao

Hi,

While auditing AF_UNIX sockets, I noticed that the sendmsg() code paths may
block on the garbage collector running as workqueue. This can cause
priority inversion and latency for real-time users.

The implementation does kindly avoid blocking "sane users". However, it is
impossible to tell whether the kernel's definition of "sane users"
accurately describes all users out there.

Digging into history and figuring out the reasons why sendmsg() needs to
wait for garbage collector, it is determined that those reasons no longer
apply.

The first patch remove that block, and the second patch is a simple
post cleanup.

Nam Cao (2):
  af_unix: Do not wait for garbage collector in sendmsg()
  af_unix: Clean up unix_schedule_gc()

 net/unix/af_unix.c |  2 +-
 net/unix/af_unix.h |  2 +-
 net/unix/garbage.c | 16 +---------------
 3 files changed, 3 insertions(+), 17 deletions(-)

-- 
2.47.3


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

* [PATCH 1/2] af_unix: Do not wait for garbage collector in sendmsg()
  2026-07-01 16:35 [PATCH 0/2] af_unix: Fix priority inversion issue Nam Cao
@ 2026-07-01 16:35 ` Nam Cao
  2026-07-02  3:27   ` Kuniyuki Iwashima
  2026-07-02 16:36   ` sashiko-bot
  2026-07-01 16:35 ` [PATCH 2/2] af_unix: Clean up unix_schedule_gc() Nam Cao
  1 sibling, 2 replies; 11+ messages in thread
From: Nam Cao @ 2026-07-01 16:35 UTC (permalink / raw)
  To: Kuniyuki Iwashima, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, netdev, linux-kernel, linux-rt-devel
  Cc: Nam Cao

AF_UNIX sockets' sendmsg() schedules and blocks on the garbage collector if
user has too many inflight unix sockets. This causes real-time issues, as
high priority processes who do need to send lots of unix sockets get
blocked by the garbage collector which runs as workqueue, causing a
priority inversion scenario.

The reason for blocking on garbage collector goes back to 2008, when
it was reported that "Local/unprivileged users can cause soft lockups
and take out system processes by triggering the OOM killer":
https://bugzilla.redhat.com/show_bug.cgi?id=470201

The soft lockup was because a process can keep queueing AF_UNIX sockets to
another process that is exiting. Back in 2008, the garbage collector was
run synchronously by the exiting process, therefore keep queueing AF_UNIX
sockets blocks that process from exiting.

The solution to that issue was forcing sendmsg() to wait for ongoing
garbage collector.

The OOM killer issue was brought up again in 2010:
https://lore.kernel.org/lkml/AANLkTi=Q967xpX0KLMwX-=_4_1AKO5wjHEuJ1TrNjCj9@mail.gmail.com/

To resolve that report, beside blocking on the garbage collector, sendmsg()
also schedules the garbage collector if the number of inflight AF_UNIX
sockets in the system is too high.

Then in 2015, once again, the OOM killer problem was brought up:
https://lore.kernel.org/lkml/20151228141435.GA13351@1wt.eu/

That time, the issue was resolved by disallowing a user from having more
inflight AF_UNIX sockets than their RLIMIT_NOFILE. That was done by commit
712f4aad406b ("unix: properly account for FDs passed over unix sockets")
and commit 415e3d3e90ce ("unix: correctly track in-flight fds in sending
process user_struct").

Now, sendmsg() does not have to block on the garbage collector anymore,
because:

  - The OOM killer issue has already been addressed by checking
    RLIMIT_NOFILE.

  - The soft lockup issue is no longer relevant, because the garbage
    collector now runs asynchronously since commit d9f21b361333 ("af_unix:
    Try to run GC async.")

Therefore, remove that to prevent priority inversion. Running all the
reproducers from the mentioned bug reports after this patch, no problem is
observed.

Signed-off-by: Nam Cao <namcao@linutronix.de>
---
 net/unix/garbage.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/net/unix/garbage.c b/net/unix/garbage.c
index 0783555e2526..f180c59b3da9 100644
--- a/net/unix/garbage.c
+++ b/net/unix/garbage.c
@@ -300,8 +300,6 @@ int unix_prepare_fpl(struct scm_fp_list *fpl)
 	if (!fpl->edges)
 		goto err;
 
-	unix_schedule_gc(fpl->user);
-
 	return 0;
 
 err:
-- 
2.47.3


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

* [PATCH 2/2] af_unix: Clean up unix_schedule_gc()
  2026-07-01 16:35 [PATCH 0/2] af_unix: Fix priority inversion issue Nam Cao
  2026-07-01 16:35 ` [PATCH 1/2] af_unix: Do not wait for garbage collector in sendmsg() Nam Cao
@ 2026-07-01 16:35 ` Nam Cao
  1 sibling, 0 replies; 11+ messages in thread
From: Nam Cao @ 2026-07-01 16:35 UTC (permalink / raw)
  To: Kuniyuki Iwashima, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, netdev, linux-kernel, linux-rt-devel
  Cc: Nam Cao

The only caller of unix_schedule_gc() passes NULL as an argument. Therefore
simplify by deleting the parameter.

Signed-off-by: Nam Cao <namcao@linutronix.de>
---
 net/unix/af_unix.c |  2 +-
 net/unix/af_unix.h |  2 +-
 net/unix/garbage.c | 14 +-------------
 3 files changed, 3 insertions(+), 15 deletions(-)

diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index f7a9d55eee8a..759db734a866 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -733,7 +733,7 @@ static void unix_release_sock(struct sock *sk, int embrion)
 
 	/* ---- Socket is dead now and most probably destroyed ---- */
 
-	unix_schedule_gc(NULL);
+	unix_schedule_gc();
 }
 
 struct unix_peercred {
diff --git a/net/unix/af_unix.h b/net/unix/af_unix.h
index 8119dbeef3a3..600d56fdcde4 100644
--- a/net/unix/af_unix.h
+++ b/net/unix/af_unix.h
@@ -30,7 +30,7 @@ void unix_update_edges(struct unix_sock *receiver);
 int unix_prepare_fpl(struct scm_fp_list *fpl);
 void unix_destroy_fpl(struct scm_fp_list *fpl);
 void unix_peek_fpl(struct scm_fp_list *fpl);
-void unix_schedule_gc(struct user_struct *user);
+void unix_schedule_gc(void);
 
 /* SOCK_DIAG */
 long unix_inq_len(struct sock *sk);
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
index f180c59b3da9..d46aeb9d2051 100644
--- a/net/unix/garbage.c
+++ b/net/unix/garbage.c
@@ -635,23 +635,11 @@ static void unix_gc(struct work_struct *work)
 
 static DECLARE_WORK(unix_gc_work, unix_gc);
 
-#define UNIX_INFLIGHT_SANE_USER		(SCM_MAX_FD * 8)
-
-void unix_schedule_gc(struct user_struct *user)
+void unix_schedule_gc(void)
 {
 	if (READ_ONCE(unix_graph_state) == UNIX_GRAPH_NOT_CYCLIC)
 		return;
 
-	/* Penalise users who want to send AF_UNIX sockets
-	 * but whose sockets have not been received yet.
-	 */
-	if (user &&
-	    READ_ONCE(user->unix_inflight) < UNIX_INFLIGHT_SANE_USER)
-		return;
-
 	if (!READ_ONCE(gc_in_progress))
 		queue_work(system_dfl_wq, &unix_gc_work);
-
-	if (user && READ_ONCE(unix_graph_cyclic_sccs))
-		flush_work(&unix_gc_work);
 }
-- 
2.47.3


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

* Re: [PATCH 1/2] af_unix: Do not wait for garbage collector in sendmsg()
  2026-07-01 16:35 ` [PATCH 1/2] af_unix: Do not wait for garbage collector in sendmsg() Nam Cao
@ 2026-07-02  3:27   ` Kuniyuki Iwashima
  2026-07-02  3:56     ` Nam Cao
  2026-07-02 16:36   ` sashiko-bot
  1 sibling, 1 reply; 11+ messages in thread
From: Kuniyuki Iwashima @ 2026-07-02  3:27 UTC (permalink / raw)
  To: Nam Cao
  Cc: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, netdev, linux-kernel, linux-rt-devel

On Wed, Jul 1, 2026 at 9:36 AM Nam Cao <namcao@linutronix.de> wrote:
>
> AF_UNIX sockets' sendmsg() schedules and blocks on the garbage collector if
> user has too many inflight unix sockets

AND there is a cyclic reference

>. This causes real-time issues, as
> high priority processes who do need to send lots of unix sockets get
> blocked by the garbage collector which runs as workqueue, causing a
> priority inversion scenario.

So the real problem is the process creating cyclic references.

>
> The reason for blocking on garbage collector goes back to 2008, when
> it was reported that "Local/unprivileged users can cause soft lockups
> and take out system processes by triggering the OOM killer":
> https://bugzilla.redhat.com/show_bug.cgi?id=470201
>
> The soft lockup was because a process can keep queueing AF_UNIX sockets to
> another process that is exiting. Back in 2008, the garbage collector was
> run synchronously by the exiting process, therefore keep queueing AF_UNIX
> sockets blocks that process from exiting.
>
> The solution to that issue was forcing sendmsg() to wait for ongoing
> garbage collector.
>
> The OOM killer issue was brought up again in 2010:
> https://lore.kernel.org/lkml/AANLkTi=Q967xpX0KLMwX-=_4_1AKO5wjHEuJ1TrNjCj9@mail.gmail.com/
>
> To resolve that report, beside blocking on the garbage collector, sendmsg()
> also schedules the garbage collector if the number of inflight AF_UNIX
> sockets in the system is too high.
>
> Then in 2015, once again, the OOM killer problem was brought up:
> https://lore.kernel.org/lkml/20151228141435.GA13351@1wt.eu/
>
> That time, the issue was resolved by disallowing a user from having more
> inflight AF_UNIX sockets than their RLIMIT_NOFILE. That was done by commit
> 712f4aad406b ("unix: properly account for FDs passed over unix sockets")
> and commit 415e3d3e90ce ("unix: correctly track in-flight fds in sending
> process user_struct").
>
> Now, sendmsg() does not have to block on the garbage collector anymore,
> because:
>
>   - The OOM killer issue has already been addressed by checking
>     RLIMIT_NOFILE.
>
>   - The soft lockup issue is no longer relevant, because the garbage
>     collector now runs asynchronously since commit d9f21b361333 ("af_unix:
>     Try to run GC async.")

I don't think the latter is resolved.  Without blocking insane
users, they can keep pushing sockets to the kernel work,
which could be soft-lockup'd.


>
> Therefore, remove that to prevent priority inversion. Running all the
> reproducers from the mentioned bug reports after this patch, no problem is
> observed.
>
> Signed-off-by: Nam Cao <namcao@linutronix.de>
> ---
>  net/unix/garbage.c | 2 --
>  1 file changed, 2 deletions(-)
>
> diff --git a/net/unix/garbage.c b/net/unix/garbage.c
> index 0783555e2526..f180c59b3da9 100644
> --- a/net/unix/garbage.c
> +++ b/net/unix/garbage.c
> @@ -300,8 +300,6 @@ int unix_prepare_fpl(struct scm_fp_list *fpl)
>         if (!fpl->edges)
>                 goto err;
>
> -       unix_schedule_gc(fpl->user);
> -
>         return 0;
>
>  err:
> --
> 2.47.3
>

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

* Re: [PATCH 1/2] af_unix: Do not wait for garbage collector in sendmsg()
  2026-07-02  3:27   ` Kuniyuki Iwashima
@ 2026-07-02  3:56     ` Nam Cao
  0 siblings, 0 replies; 11+ messages in thread
From: Nam Cao @ 2026-07-02  3:56 UTC (permalink / raw)
  To: Kuniyuki Iwashima
  Cc: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, netdev, linux-kernel, linux-rt-devel

Kuniyuki Iwashima <kuniyu@google.com> writes:
> On Wed, Jul 1, 2026 at 9:36 AM Nam Cao <namcao@linutronix.de> wrote:
>> Now, sendmsg() does not have to block on the garbage collector anymore,
>> because:
>>
>>   - The OOM killer issue has already been addressed by checking
>>     RLIMIT_NOFILE.
>>
>>   - The soft lockup issue is no longer relevant, because the garbage
>>     collector now runs asynchronously since commit d9f21b361333 ("af_unix:
>>     Try to run GC async.")
>
> I don't think the latter is resolved.  Without blocking insane
> users, they can keep pushing sockets to the kernel work,
> which could be soft-lockup'd.

User cannot push more than RLIMIT_NOFILE before GC runs. And the GC
grabs the spin lock, clean up the present stuffs, and exit.

So user could make the GC runs again and again, but there wouldn't be
soft lockup, as the GC yields after short intervals.

Nam

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

* Re: [PATCH 1/2] af_unix: Do not wait for garbage collector in sendmsg()
  2026-07-01 16:35 ` [PATCH 1/2] af_unix: Do not wait for garbage collector in sendmsg() Nam Cao
  2026-07-02  3:27   ` Kuniyuki Iwashima
@ 2026-07-02 16:36   ` sashiko-bot
  2026-07-03  5:53     ` Nam Cao
  1 sibling, 1 reply; 11+ messages in thread
From: sashiko-bot @ 2026-07-02 16:36 UTC (permalink / raw)
  To: Nam Cao; +Cc: linux-rt-devel, linux-kernel

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Garbage collector is no longer scheduled when creating new inflight FDs, leading to permanent cycle accumulation and -ETOOMANYREFS failures in isolated environments.
--

commit 506189bd29f8ad56f5d9e51f3e0216203ebad5ec
Author: Nam Cao <namcao@linutronix.de>

af_unix: Do not wait for garbage collector in sendmsg()

This patch removes the garbage collector scheduling and waiting from the
sendmsg() path for AF_UNIX sockets. It aims to prevent priority inversion
by relying on RLIMIT_NOFILE limits and asynchronous garbage collection.

> diff --git a/net/unix/garbage.c b/net/unix/garbage.c
> index 0783555e25266..f180c59b3da9d 100644
> --- a/net/unix/garbage.c
> +++ b/net/unix/garbage.c
> @@ -300,8 +300,6 @@ int unix_prepare_fpl(struct scm_fp_list *fpl)
>  	if (!fpl->edges)
>  		goto err;
>  
> -	unix_schedule_gc(fpl->user);
> -

[Severity: High]
Does this removal prevent the garbage collector from running when a process
creates isolated socket cycles?

If a process continuously creates socket cycles (e.g., passing FDs to each
other) and closes its local FDs, the sockets reference each other in their
receive queues, so their file reference counts will not reach zero.

Because the refcounts do not drop to zero, unix_release_sock() is never
triggered. By removing unix_schedule_gc() from unix_prepare_fpl() here,
unix_release_sock() is left as the only trigger for garbage collection.

This could allow the inflight count to accumulate indefinitely until it
hits RLIMIT_NOFILE, causing subsequent sendmsg() calls to fail with
-ETOOMANYREFS and permanently leaking the network namespace unless an
unrelated AF_UNIX socket is closed system-wide.

>  	return 0;
>  
>  err:

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1782922354.git.namcao@linutronix.de?part=1

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

* Re: [PATCH 1/2] af_unix: Do not wait for garbage collector in sendmsg()
  2026-07-02 16:36   ` sashiko-bot
@ 2026-07-03  5:53     ` Nam Cao
  2026-07-03  6:25       ` Kuniyuki Iwashima
  0 siblings, 1 reply; 11+ messages in thread
From: Nam Cao @ 2026-07-03  5:53 UTC (permalink / raw)
  To: sashiko-reviews, Kuniyuki Iwashima, David S . Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman, netdev,
	linux-kernel, linux-rt-devel
  Cc: linux-rt-devel, linux-kernel

sashiko-bot@kernel.org writes:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [High] Garbage collector is no longer scheduled when creating new inflight FDs, leading to permanent cycle accumulation and -ETOOMANYREFS failures in isolated environments.
> --
>
> commit 506189bd29f8ad56f5d9e51f3e0216203ebad5ec
> Author: Nam Cao <namcao@linutronix.de>
>
> af_unix: Do not wait for garbage collector in sendmsg()
>
> This patch removes the garbage collector scheduling and waiting from the
> sendmsg() path for AF_UNIX sockets. It aims to prevent priority inversion
> by relying on RLIMIT_NOFILE limits and asynchronous garbage collection.
>
>> diff --git a/net/unix/garbage.c b/net/unix/garbage.c
>> index 0783555e25266..f180c59b3da9d 100644
>> --- a/net/unix/garbage.c
>> +++ b/net/unix/garbage.c
>> @@ -300,8 +300,6 @@ int unix_prepare_fpl(struct scm_fp_list *fpl)
>>  	if (!fpl->edges)
>>  		goto err;
>>  
>> -	unix_schedule_gc(fpl->user);
>> -
>
> [Severity: High]
> Does this removal prevent the garbage collector from running when a process
> creates isolated socket cycles?
>
> If a process continuously creates socket cycles (e.g., passing FDs to each
> other) and closes its local FDs, the sockets reference each other in their
> receive queues, so their file reference counts will not reach zero.
>
> Because the refcounts do not drop to zero, unix_release_sock() is never
> triggered. By removing unix_schedule_gc() from unix_prepare_fpl() here,
> unix_release_sock() is left as the only trigger for garbage collection.
>
> This could allow the inflight count to accumulate indefinitely until it
> hits RLIMIT_NOFILE, causing subsequent sendmsg() calls to fail with
> -ETOOMANYREFS and permanently leaking the network namespace unless an
> unrelated AF_UNIX socket is closed system-wide.

Sashiko found a valid issue here. But this is a pre-existing issue. It
is not introduced in this patch.

unix_schedule_gc() does not actually schedule the garbage collector
unless user's inflight unix socket count exceeds UNIX_INFLIGHT_SANE_USER
(2024). So user can already accumulate up to 2023 inflight socket counts
without the garbage collector running until unix_release_sock() is called.

Nam

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

* Re: [PATCH 1/2] af_unix: Do not wait for garbage collector in sendmsg()
  2026-07-03  5:53     ` Nam Cao
@ 2026-07-03  6:25       ` Kuniyuki Iwashima
  2026-07-04  6:03         ` Nam Cao
  0 siblings, 1 reply; 11+ messages in thread
From: Kuniyuki Iwashima @ 2026-07-03  6:25 UTC (permalink / raw)
  To: Nam Cao
  Cc: sashiko-reviews, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, netdev, linux-kernel, linux-rt-devel

On Thu, Jul 2, 2026 at 10:53 PM Nam Cao <namcao@linutronix.de> wrote:
>
> sashiko-bot@kernel.org writes:
> > Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> > - [High] Garbage collector is no longer scheduled when creating new inflight FDs, leading to permanent cycle accumulation and -ETOOMANYREFS failures in isolated environments.
> > --
> >
> > commit 506189bd29f8ad56f5d9e51f3e0216203ebad5ec
> > Author: Nam Cao <namcao@linutronix.de>
> >
> > af_unix: Do not wait for garbage collector in sendmsg()
> >
> > This patch removes the garbage collector scheduling and waiting from the
> > sendmsg() path for AF_UNIX sockets. It aims to prevent priority inversion
> > by relying on RLIMIT_NOFILE limits and asynchronous garbage collection.
> >
> >> diff --git a/net/unix/garbage.c b/net/unix/garbage.c
> >> index 0783555e25266..f180c59b3da9d 100644
> >> --- a/net/unix/garbage.c
> >> +++ b/net/unix/garbage.c
> >> @@ -300,8 +300,6 @@ int unix_prepare_fpl(struct scm_fp_list *fpl)
> >>      if (!fpl->edges)
> >>              goto err;
> >>
> >> -    unix_schedule_gc(fpl->user);
> >> -
> >
> > [Severity: High]
> > Does this removal prevent the garbage collector from running when a process
> > creates isolated socket cycles?
> >
> > If a process continuously creates socket cycles (e.g., passing FDs to each
> > other) and closes its local FDs, the sockets reference each other in their
> > receive queues, so their file reference counts will not reach zero.
> >
> > Because the refcounts do not drop to zero, unix_release_sock() is never
> > triggered. By removing unix_schedule_gc() from unix_prepare_fpl() here,
> > unix_release_sock() is left as the only trigger for garbage collection.
> >
> > This could allow the inflight count to accumulate indefinitely until it
> > hits RLIMIT_NOFILE, causing subsequent sendmsg() calls to fail with
> > -ETOOMANYREFS and permanently leaking the network namespace unless an
> > unrelated AF_UNIX socket is closed system-wide.
>
> Sashiko found a valid issue here.

This is same with my point, and

> But this is a pre-existing issue. It
> is not introduced in this patch.

your patch makes it much easier to abuse.
UNIX_INFLIGHT_SANE_USER is usually much smaller than
RLIMIT_NOFILE.

unix_schedule_gc() in sendmsg() is to self-regulate malicious users,
otherwise GC relies on unrelated AF_UNIX socket's close() and could
be triggered too late since GC is system-wide.

Previously every sendmsg() had to wait for GC, and now it's only when
there is a circular reference AND user has too many inflight sockets.

Please fix the root cause; the former condition on your system.
--
pw-bot: cr

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

* Re: [PATCH 1/2] af_unix: Do not wait for garbage collector in sendmsg()
  2026-07-03  6:25       ` Kuniyuki Iwashima
@ 2026-07-04  6:03         ` Nam Cao
  2026-07-07 11:42           ` Sebastian Andrzej Siewior
  0 siblings, 1 reply; 11+ messages in thread
From: Nam Cao @ 2026-07-04  6:03 UTC (permalink / raw)
  To: Kuniyuki Iwashima
  Cc: sashiko-reviews, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, netdev, linux-kernel, linux-rt-devel

Kuniyuki Iwashima <kuniyu@google.com> writes:
> your patch makes it much easier to abuse.
> UNIX_INFLIGHT_SANE_USER is usually much smaller than
> RLIMIT_NOFILE.
>
> unix_schedule_gc() in sendmsg() is to self-regulate malicious users,
> otherwise GC relies on unrelated AF_UNIX socket's close() and could
> be triggered too late since GC is system-wide.

About the abuse, the scenario where inflight sockets bypass
UNIX_INFLIGHT_SANE_USER and delay GC until an unrelated AF_UNIX socket
closes actually exists today.

For example, the following program creates far more than
UNIX_INFLIGHT_SANE_USER inflight sockets, which persists indefinitely
until another unrelated AF_UNIX close().

#include <sys/mount.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/wait.h>

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

static int send_fd(int unix_fd, int fd)
{
        struct msghdr msgh;
        struct cmsghdr *cmsg;
        char buf[CMSG_SPACE(sizeof(fd))];

        memset(&msgh, 0, sizeof(msgh));

        memset(buf, 0, sizeof(buf));
        msgh.msg_control = buf;
        msgh.msg_controllen = sizeof(buf);

        cmsg = CMSG_FIRSTHDR(&msgh);
        cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
        cmsg->cmsg_level = SOL_SOCKET;
        cmsg->cmsg_type = SCM_RIGHTS;

        msgh.msg_controllen = cmsg->cmsg_len;

        memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
        return sendmsg(unix_fd, &msgh, 0);
}

int main(int argc, char *argv[])
{
	int fd[2];
	int i;

	for (int n = 0; n < 100; ++n) {
		if (socketpair(PF_UNIX, SOCK_SEQPACKET, 0, fd) == -1)
			goto out_error;

		for (i = 0; i < 100; ++i) {
			if (send_fd(fd[0], fd[0]) == -1)
				goto out_error;

			if (send_fd(fd[1], fd[1]) == -1)
				goto out_error;
		}
	}

	return 0;

out_error:
	fprintf(stderr, "error: %s\n", strerror(errno));
}

To address this properly, we can schedule the GC at task exit. I can
include that patch in my series, if that sounds good to you.

> Previously every sendmsg() had to wait for GC, and now it's only when
> there is a circular reference AND user has too many inflight sockets.
>
> Please fix the root cause; the former condition on your system.

Can you clarify what you mean by fixing the former condition on my
system. Do you mean ensuring that no application creates a circular
reference?

I am afraid we cannot rely on all users and applications to behave. We
do not want a buggy program or a malicious program to harm another
time-critical task.

Nam

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

* Re: [PATCH 1/2] af_unix: Do not wait for garbage collector in sendmsg()
  2026-07-04  6:03         ` Nam Cao
@ 2026-07-07 11:42           ` Sebastian Andrzej Siewior
  2026-07-07 13:49             ` Nam Cao
  0 siblings, 1 reply; 11+ messages in thread
From: Sebastian Andrzej Siewior @ 2026-07-07 11:42 UTC (permalink / raw)
  To: Nam Cao
  Cc: Kuniyuki Iwashima, sashiko-reviews, David S . Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman, netdev,
	linux-kernel, linux-rt-devel

On 2026-07-04 08:03:56 [+0200], Nam Cao wrote:
> Kuniyuki Iwashima <kuniyu@google.com> writes:
> > your patch makes it much easier to abuse.
> > UNIX_INFLIGHT_SANE_USER is usually much smaller than
> > RLIMIT_NOFILE.
> >
> > unix_schedule_gc() in sendmsg() is to self-regulate malicious users,
> > otherwise GC relies on unrelated AF_UNIX socket's close() and could
> > be triggered too late since GC is system-wide.
> 
> About the abuse, the scenario where inflight sockets bypass
> UNIX_INFLIGHT_SANE_USER and delay GC until an unrelated AF_UNIX socket
> closes actually exists today.

We don't bypass the limit for an ordinary user. That one gets blocked in
too_many_unix_fds(). But for the CAP_SYS_RESOURCE + CAP_SYS_ADMIN it is
a different story.
In that case we cross the UNIX_INFLIGHT_SANE_USER and schedule the GC,
it is not delayed. The worker is triggered regularity and the thread
waits for its completion it is just the GC worker does not clean up
anything so it continues to increase. The only thing that actually
limits the sender is if it runs out of socket memory and needs to wait.
So it kind of works for a single thread.

…
> To address this properly, we can schedule the GC at task exit. I can
> include that patch in my series, if that sounds good to you.

task exit or closing the socket?
Either way, in your PoC it hardly makes any sense to schedule the worker
over and over and wait for it since it does not do anything. Sure it is
the system as a whole so triggering might make sense but I'm not sure
about waiting for its completion.

Side note: gc_in_progress is redundant since you can't schedule a worker
twice and work_pending(&unix_gc_work) would provide the same
information. The only difference is that you avoid scheduling the worker
while it is running but I don't think this is a problem.

> Nam

Sebastian

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

* Re: [PATCH 1/2] af_unix: Do not wait for garbage collector in sendmsg()
  2026-07-07 11:42           ` Sebastian Andrzej Siewior
@ 2026-07-07 13:49             ` Nam Cao
  0 siblings, 0 replies; 11+ messages in thread
From: Nam Cao @ 2026-07-07 13:49 UTC (permalink / raw)
  To: Sebastian Andrzej Siewior
  Cc: Kuniyuki Iwashima, sashiko-reviews, David S . Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman, netdev,
	linux-kernel, linux-rt-devel

Sebastian Andrzej Siewior <bigeasy@linutronix.de> writes:
> On 2026-07-04 08:03:56 [+0200], Nam Cao wrote:
>> Kuniyuki Iwashima <kuniyu@google.com> writes:
>> > your patch makes it much easier to abuse.
>> > UNIX_INFLIGHT_SANE_USER is usually much smaller than
>> > RLIMIT_NOFILE.
>> >
>> > unix_schedule_gc() in sendmsg() is to self-regulate malicious users,
>> > otherwise GC relies on unrelated AF_UNIX socket's close() and could
>> > be triggered too late since GC is system-wide.
>> 
>> About the abuse, the scenario where inflight sockets bypass
>> UNIX_INFLIGHT_SANE_USER and delay GC until an unrelated AF_UNIX socket
>> closes actually exists today.
>
> We don't bypass the limit for an ordinary user. That one gets blocked in
> too_many_unix_fds(). But for the CAP_SYS_RESOURCE + CAP_SYS_ADMIN it is
> a different story.
> In that case we cross the UNIX_INFLIGHT_SANE_USER and schedule the GC,
> it is not delayed. The worker is triggered regularity and the thread
> waits for its completion it is just the GC worker does not clean up
> anything so it continues to increase. The only thing that actually
> limits the sender is if it runs out of socket memory and needs to wait.

That's also my understanding. But tasks that have
CAP_SYS_RESOURCE|CAP_SYS_ADMIN should be trustworthy to not burn
system's resources.

> So it kind of works for a single thread.
>
> …
>> To address this properly, we can schedule the GC at task exit. I can
>> include that patch in my series, if that sounds good to you.
>
> task exit or closing the socket?

I meant task exit, but closing the socket also makes sense because that
is when dead cyclic reference can appear. However, unless the file
descriptor's refcount reaches 0, the fs layer will not call us. We could
change fs/, but I am not sure if we should invade into fs/ just for this
one.

For the "resource is still consumed indefinitely after task exit" issue,
then scheduling GC at task exit is good enough.

If the task does not exit, those dead cyclic references can sit there
indefinitely. But this is not really critical as it is capped by
RLIMIT_NOFILE. Additionally it is impossible to prevent a "malicious"
task from creating RLIMIT_NOFILE inflight sockets and just leave them
there.

> Either way, in your PoC it hardly makes any sense to schedule the worker
> over and over and wait for it since it does not do anything. Sure it is
> the system as a whole so triggering might make sense but I'm not sure
> about waiting for its completion.

Agree. For the GC triggering thingy, it is a trade-off between CPU
consumption and how early garbage gets cleared, so that can arguably
stay. But the waiting part has to go.

> Side note: gc_in_progress is redundant since you can't schedule a worker
> twice and work_pending(&unix_gc_work) would provide the same
> information. The only difference is that you avoid scheduling the worker
> while it is running but I don't think this is a problem.

Yep. Additionally gc_in_progress is not read/write under any lock, so
it is possible to read a stale gc_in_progress and the GC gets delayed
indefinitely. That is already on my todo list, among a few other
things. But let's get this most important piece done first.

Nam

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

end of thread, other threads:[~2026-07-07 13:50 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-01 16:35 [PATCH 0/2] af_unix: Fix priority inversion issue Nam Cao
2026-07-01 16:35 ` [PATCH 1/2] af_unix: Do not wait for garbage collector in sendmsg() Nam Cao
2026-07-02  3:27   ` Kuniyuki Iwashima
2026-07-02  3:56     ` Nam Cao
2026-07-02 16:36   ` sashiko-bot
2026-07-03  5:53     ` Nam Cao
2026-07-03  6:25       ` Kuniyuki Iwashima
2026-07-04  6:03         ` Nam Cao
2026-07-07 11:42           ` Sebastian Andrzej Siewior
2026-07-07 13:49             ` Nam Cao
2026-07-01 16:35 ` [PATCH 2/2] af_unix: Clean up unix_schedule_gc() Nam Cao

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.