Linux Security Modules development
 help / color / mirror / Atom feed
From: "Mickaël Salaün" <mic@digikod.net>
To: poppet lovelace <dmcjisalive@gmail.com>
Cc: "Günther Noack" <gnoack@google.com>,
	linux-security-module@vger.kernel.org
Subject: Re: [Bug] landlock: sun_path length underflow to SIZE_MAX in landlock_deny_scope_abstract_unix_socket TP_printk -> unbounded OOB read in trace reader
Date: Fri, 28 Aug 2026 21:12:47 +0200	[thread overview]
Message-ID: <20260828.da0Eik3eeSh8@digikod.net> (raw)
In-Reply-To: <CAL4aGcVcT0VWVFmGi_vLqxxZ9KdOHfGXYZtKjBdvoUyFjbu5=A@mail.gmail.com>

Hi Charles,

This is an impressive report but there is no bug.

There is no underflow because __string_len() reserves one extra byte for
the terminating NUL.  I sent a test patch to prove that:
https://lore.kernel.org/r/20260828190038.71831-1-mic@digikod.net

Dropping the "- 1" would introduce a new bug though.

Bug reports are very welcome but please test the potential issue before.
See https://docs.kernel.org/process/coding-assistants.html#procedure-for-finding-and-fixing-bugs

Regards,
 Mickaël


On Tue, Aug 25, 2026 at 09:00:05PM +0800, poppet lovelace wrote:
> Hi Mickaël,
> 
> While auditing the new landlock tracepoints we found a size_t underflow in
> the TP_printk() of landlock_deny_scope_abstract_unix_socket that turns a
> zero-length abstract AF_UNIX address into an effectively unbounded OOB read
> in the context of whoever consumes the trace (typically root reading
> tracefs). The tracepoints are new in the current merge window, so this can
> still be fixed before 7.3.
> 
> Root cause
> ----------
> 
> The event stores the abstract name correctly:
> 
>   include/trace/events/landlock.h:899-932
> 
>     __string_len(sun_path,
>                  unix_sk(peer)->addr->name->sun_path + 1,
>                  unix_sk(peer)->addr->len -
>                      offsetof(struct sockaddr_un, sun_path) - 1)
> 
> For an abstract address bound with addrlen == sizeof(sa_family_t) + 1 (= 3),
> which net/unix/af_unix.c:335-345 (unix_validate_addr) accepts, addr->len is
> 3, so the stored dynamic-array length is 0.
> 
> The printer then subtracts one more:
> 
>   include/trace/events/landlock.h:954-955
> 
>     __trace_print_untrusted_str(p, __get_str(sun_path),
>                                 __get_dynamic_array_len(sun_path) - 1)
> 
> 0u - 1 wraps to SIZE_MAX. __trace_print_untrusted_str()
> (include/trace/events/landlock.h:36-68) forwards that length to
> string_escape_mem(), whose main loop
> 
>   lib/string_helpers.c:586
> 
>     while (isz--) {
>         unsigned char c = *src++;
> 
> reads every input byte regardless of output exhaustion (the escape_*
> helpers stop writing past `end`, but nothing breaks the input walk). With
> isz == SIZE_MAX the read walks forward from the ring-buffer record through
> the rest of the tracing buffer and the kernel direct map until it faults.
> 
> Impact
> ------
> 
> An unprivileged task inside any landlock domain that scopes abstract unix
> sockets can plant such a record deterministically. The OOB read itself
> executes when the trace buffer is consumed (e.g. cat of
> /sys/kernel/tracing/trace or trace_pipe by a privileged monitor -- exactly
> the deployment these tracepoints target):
> 
> * information disclosure: escaped bytes of adjacent kernel memory
>   (ring-buffer contents and beyond, i.e. direct map) are copied into the
>   visible trace text;
> * availability: the walk ends in a page fault / oops in the reader's
>   syscall context; with panic_on_oops this takes the whole machine down.
> 
> Same-call-site audit: the other __trace_print_untrusted_str() users subtract
> 1 as well (pathname :389/:725, comm :829/:878), but their captured lengths
> cannot be 0 (dentry names are non-empty; comm is fixed-size), so only the
> abstract-socket event is currently reachable. The -1 looks like a leftover
> from string lengths that include a terminator; here the capture side already
> excluded the leading abstract-name NUL.
> 
> Reproducer (hand-written, not executed against a live kernel)
> -------------------------------------------------------------
> 
>   int s = socket(AF_UNIX, SOCK_STREAM, 0);
>   struct sockaddr_un a = { .sun_family = AF_UNIX };
>   a.sun_path[0] = '\0';                       /* abstract, zero length */
>   bind(s, (struct sockaddr *)&a, sizeof(a.sun_family) + 1);   /* ok, len 3 */
> 
>   /* task restricted by a domain scoping abstract unix sockets: */
>   connect(cfd, (struct sockaddr *)&a, 3);     /* denied -> event recorded */
> 
>   # echo 1 > /sys/kernel/tracing/events/landlock/\
> landlock_deny_scope_abstract_unix_socket/enable
>   # cat /sys/kernel/tracing/trace             /* OOB read here */
> 
> Self-assessed severity
> ----------------------
> 
> CVSS:3.1 AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:H = 6.7 (Medium).
> 
> If the cross-boundary read is judged Scope:Changed (kernel-memory bytes are
> surfaced into user-visible trace text, and the walk can traverse the whole
> direct map until it faults): AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:H = 7.3.
> Honest range 5.5-7.3 depending on scope treatment. Preconditions: the
> landlock tracepoints are enabled and consumed by a privileged reader --
> i.e. exactly the monitoring deployment they were added for.
> 
> Suggested fixes (either suffices; both preferred)
> -------------------------------------------------
> 
> 1. Drop the "- 1" at include/trace/events/landlock.h:955 -- the capture-side
>    length already excludes the abstract prefix NUL; the subtraction is a
>    double decrement. Please also re-check :389/:725/:829/:878 against their
>    capture lengths.
> 2. Harden __trace_print_untrusted_str() (or string_escape_mem()) so the
>    input walk cannot exceed the source object: e.g. clamp len, or break the
>    loop when output is exhausted (note this changes string_escape_mem()'s
>    return-size contract for existing callers).
> 
> Found by Charles <dmcjisalive@gmail.com> -- happy to test a fix.
> 
> Thanks,
> Charles
> 
> Reported-by: Charles <dmcjisalive@gmail.com>
> 

      reply	other threads:[~2026-08-28 19:12 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-25 13:00 [Bug] landlock: sun_path length underflow to SIZE_MAX in landlock_deny_scope_abstract_unix_socket TP_printk -> unbounded OOB read in trace reader poppet lovelace
2026-08-28 19:12 ` Mickaël Salaün [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=20260828.da0Eik3eeSh8@digikod.net \
    --to=mic@digikod.net \
    --cc=dmcjisalive@gmail.com \
    --cc=gnoack@google.com \
    --cc=linux-security-module@vger.kernel.org \
    /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