From: Bryam Vargas <hexlabsecurity@proton.me>
To: "Mickaël Salaün" <mic@digikod.net>, "Günther Noack" <gnoack@google.com>
Cc: Justin Suess <utilityemal77@gmail.com>,
Christian Brauner <brauner@kernel.org>,
Paul Moore <paul@paul-moore.com>,
James Morris <jmorris@namei.org>,
"Serge E . Hallyn" <serge@hallyn.com>,
linux-security-module@vger.kernel.org, stable@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [PATCH v5 0/2] landlock: fix SCOPE_SIGNAL bypass on the SIGIO/fowner path
Date: Thu, 04 Jun 2026 23:16:47 +0000 [thread overview]
Message-ID: <cover.1780614610.git.hexlabsecurity@proton.me> (raw)
This series fixes a LANDLOCK_SCOPE_SIGNAL bypass on the asynchronous SIGIO
(fcntl(F_SETOWN)) delivery path, and adds regression tests.
A sandboxed process that owns a file or socket can request a signal
(F_SETSIG, e.g. SIGKILL) to be delivered to a whole process group on I/O
readiness (F_SETOWN(-pgid) + O_ASYNC). When it is the head of its own
process group -- the default after fork() -- that group still contains the
non-sandboxed process that launched it (a supervisor, a security monitor),
so the sandbox can signal processes that SCOPE_SIGNAL is meant to protect
from it.
Patch 1 has two parts:
- Narrow the same-thread-group exemption in control_current_fowner() so a
process-group fowner always records the caller's Landlock domain; the
delivery-time check in hook_file_send_sigiotask() then runs against
every group member. This closes the bypass.
- Recording the domain alone over-blocks one corner: the kernel signals a
process group through its members' thread-group leaders, and the leader
of the registrant's own process can carry a different Landlock domain
than the sibling thread that armed F_SETOWN. domain_is_scoped() would
then deny that leader, even though commit 18eb75f3af40 requires
same-process delivery to be allowed. hook_task_kill() avoids this by
checking same_thread_group() live, per recipient; the SIGIO path
delegated the whole decision to a single registration-time check that a
fan-out cannot honor. So patch 1 also records the registrant's thread
group next to its domain and exempts it at delivery, restoring the
same-process guarantee while keeping out-of-domain group members
blocked.
The direct kill() path (hook_task_kill) is unaffected.
Patch 2 adds two regression tests in scoped_signal_test.c:
sigio_to_pgid_members (out-of-domain member must not be signaled) and
sigio_to_pgid_self (the registrant's own process, reached through its
thread-group leader, must still be signaled).
The defect was introduced by commit 18eb75f3af40 ("landlock: Always allow
signals between threads of the same process") in v6.15, and is present in the
stable branches that backported it (6.12.y, 6.13.y, 6.14.y).
control_current_fowner() is identical across those branches.
Verified on 7.1.0-rc5 + CONFIG_SECURITY_LANDLOCK=y (same .config, only the
landlock change differs across arms):
- unpatched: sigio_to_pgid_members fails (out-of-domain member signaled,
bypass), sigio_to_pgid_self passes;
- patch-1-record-only (the v4 hunk): sigio_to_pgid_members passes,
sigio_to_pgid_self fails (the registrant's own leader is over-blocked);
- this series: both pass, and the landlock signal-scoping suite is 21/21.
A standalone reproducer of both invariants was also built -m32 and -m64 and
run on each arm: the fix behaves identically through the i386-compat and the
x86-64 native syscall paths.
v4 -> v5 (review feedback from Günther Noack):
- patch 1: also fix the same-process over-block introduced by recording the
domain for a process-group fowner -- record the registrant's thread group
(struct pid) in landlock_file_security and exempt it in
hook_file_send_sigiotask() (task_tgid(tsk) == fown_tg), restoring the
18eb75f3af40 guarantee for the registrant's own process;
- patch 2: add sigio_to_pgid_self covering the non-leader-registrant /
pgid-includes-self case;
- drop Tested-by: Justin Suess -- patch 1 gained the delivery-time exemption
he did not test (re-test welcome);
- posted as a fresh top-level thread (no In-Reply-To to the v4 review).
v4: https://lore.kernel.org/all/20260602172741.18760-1-hexlabsecurity@proton.me/
(v1/v2 were sent to security@kernel.org while embargoed; not in a public
archive.)
Bryam Vargas (2):
landlock: fix LANDLOCK_SCOPE_SIGNAL bypass on the SIGIO path
selftests/landlock: test SCOPE_SIGNAL on the SIGIO/fowner pgid path
security/landlock/fs.c | 15 ++
security/landlock/fs.h | 10 +
security/landlock/task.c | 11 ++
.../selftests/landlock/scoped_signal_test.c | 183 ++++++++++++++++++
4 files changed, 219 insertions(+)
base-commit: 6f3ed7fec72fc8979b2a8c7219c0a9fcfc8d07b5
--
2.43.0
next reply other threads:[~2026-06-04 23:17 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-04 23:16 Bryam Vargas [this message]
2026-06-04 23:16 ` [PATCH v5 1/2] landlock: fix LANDLOCK_SCOPE_SIGNAL bypass on the SIGIO path Bryam Vargas
2026-06-05 11:11 ` Günther Noack
2026-06-04 23:17 ` [PATCH v5 2/2] selftests/landlock: test SCOPE_SIGNAL on the SIGIO/fowner pgid path Bryam Vargas
2026-06-05 11:50 ` Günther Noack
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=cover.1780614610.git.hexlabsecurity@proton.me \
--to=hexlabsecurity@proton.me \
--cc=brauner@kernel.org \
--cc=gnoack@google.com \
--cc=jmorris@namei.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=mic@digikod.net \
--cc=paul@paul-moore.com \
--cc=serge@hallyn.com \
--cc=stable@vger.kernel.org \
--cc=utilityemal77@gmail.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.