All of lore.kernel.org
 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 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.