BPF List
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Jens Remus" <jremus@linux.ibm.com>
Cc: bpf@vger.kernel.org
Subject: Re: [PATCH v15 05/20] unwind_user/sframe: Add support for reading .sframe contents
Date: Wed, 20 May 2026 16:33:47 +0000	[thread overview]
Message-ID: <20260520163348.11FD21F00893@smtp.kernel.org> (raw)
In-Reply-To: <20260520154004.3845823-6-jremus@linux.ibm.com>

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] Incorrect FRE size calculation due to using a mutated `dataword_count`.
- [High] Binary search incorrectly reads 64 bits for a 32-bit PC-relative offset, corrupting the function address calculation.
- [High] Unbounded linear scan of user-controlled SFrame FREs can cause a kernel hard lockup.
- [High] Usage of `guard(srcu)` invokes `srcu_read_lock()`, which is not NMI-safe and can corrupt the SRCU lock counter.
- [Medium] Mixing goto-based error handling with scope-based `guard()` cleanup.
--

commit 12c453957aeaea0a5733d7ed09d97cf7dfd380a5
Author: Josh Poimboeuf <jpoimboe@kernel.org>

unwind_user/sframe: Add support for reading .sframe contents

In preparation for using sframe to unwind user space stacks, add an
sframe_find() interface for finding the sframe information associated
with a given text address.

Link: https://lore.kernel.org/all/77c0d1ec143bf2a53d66c4ecb190e7e0a576fbfd.1737511963.git.jpoimboe@kernel.org/
Link: https://lore.kernel.org/all/b35ca3a3-8de5-4d32-8d30-d4e562f6b0de@linux.ibm.com/

> diff --git a/kernel/unwind/sframe.c b/kernel/unwind/sframe.c
> index 6b3ce3f8966d0..a38f50a363633 100644
> --- a/kernel/unwind/sframe.c
> +++ b/kernel/unwind/sframe.c

[ ... ]

> @@ -15,9 +15,350 @@
[ ... ]
> +static __always_inline int __find_fde(struct sframe_section *sec,
> +				      unsigned long ip,
> +				      struct sframe_fde_internal *fde)
> +{
[ ... ]
> +	while (low <= high) {
> +		struct sframe_fde_v3 __user *mid;
> +		s64 func_off;
> +		unsigned long func_addr;
> +
> +		mid = low + ((high - low) / 2);
> +
> +		unsafe_get_user(func_off, (s64 __user *)mid, Efault);

[Severity: High]
Does this read 64 bits for a 32-bit PC-relative offset? Since SFrame V3
specifies a 32-bit signed integer for the PC-relative offset followed by
a 32-bit function size, won't reading 8 bytes merge both fields into
func_off and corrupt the function address calculation?

> +		func_addr = (unsigned long)mid + func_off;

[ ... ]

> +static __always_inline int __read_fre(struct sframe_section *sec,
> +				      struct sframe_fde_internal *fde,
> +				      unsigned long fre_addr,
> +				      struct sframe_fre_internal *fre)
> +{
[ ... ]
> +	UNSAFE_GET_USER_INC(cfa_off, cur, dataword_size, Efault);
> +	dataword_count--;
> +
> +	ra_off = sec->ra_off;
> +	if (!ra_off) {
> +		if (!dataword_count--)
> +			return -EINVAL;
> +
> +		UNSAFE_GET_USER_INC(ra_off, cur, dataword_size, Efault);
> +	}
> +
> +	fp_off = sec->fp_off;
> +	if (!fp_off && dataword_count) {
> +		dataword_count--;
> +		UNSAFE_GET_USER_INC(fp_off, cur, dataword_size, Efault);
> +	}
> +
> +	if (dataword_count)
> +		return -EINVAL;
> +
> +	fre->size	= addr_size + 1 + (dataword_count * dataword_size);

[Severity: High]
Is the FRE size calculation correct here? Since dataword_count is decremented
as datawords are read, and the previous line ensures it is exactly 0, doesn't
this entirely omit the size of the read datawords from the total FRE size?
When __find_fre() advances to the next FRE, this might cause it to point to
the middle of the current FRE's datawords and read garbage.

> +	fre->ip_off	= ip_off;

[ ... ]

> +static __always_inline int __find_fre(struct sframe_section *sec,
> +				      struct sframe_fde_internal *fde,
> +				      unsigned long ip,
> +				      struct unwind_user_frame *frame)
> +{
[ ... ]
> +	fre_addr = sec->fres_start + fde->fres_off;
> +
> +	for (i = 0; i < fde->fres_num; i++) {
> +		int ret;

[Severity: High]
Could this loop cause a kernel hard lockup? fde->fres_num is read from user
space and can be large. Since this performs a linear scan reading each FRE
sequentially from user memory, and unwinding often runs in NMI context (like
perf PMU interrupts), could a maliciously large SFrame section force the
kernel to loop without yielding and trigger the NMI watchdog?

> +
> +		/*
> +		 * Alternate between the two fre_addr[] entries for 'fre' and
> +		 * 'prev_fre'.
> +		 */

[ ... ]

> +int sframe_find(unsigned long ip, struct unwind_user_frame *frame)
> +{
> +	struct mm_struct *mm = current->mm;
> +	struct sframe_section *sec;
> +	struct sframe_fde_internal fde;
> +	int ret;
> +
> +	if (!mm)
> +		return -EINVAL;
> +
> +	guard(srcu)(&sframe_srcu);

[Severity: High]
Is this safe to use from NMI context? Stack unwinding is frequently invoked
from NMIs (like perf PMU interrupts), but srcu_read_lock() is not NMI-safe
on all architectures (like arm64, where the non-atomic read-modify-write
could corrupt the SRCU lock counter). Should this use srcu_read_lock_nmisafe()
or standard RCU instead?

[Severity: Medium]
Does this mix goto-based error handling with scope-based cleanup? The
function declares a scope-based guard here, but uses a goto-based cleanup
label (end:) below. This goes against the cleanup subsystem guidelines
which recommend either converting all resources to scope-based cleanup or
none at all, to avoid confusing ownership semantics.

> +
> +	sec = mtree_load(&mm->sframe_mt, ip);
> +	if (!sec)
> +		return -ENOENT;
> +
> +	if (!user_read_access_begin((void __user *)sec->sframe_start,
> +				    sec->sframe_end - sec->sframe_start))
> +		return -EFAULT;
> +
> +	ret = __find_fde(sec, ip, &fde);
> +	if (ret)
> +		goto end;
> +
> +	ret = __find_fre(sec, &fde, ip, frame);
> +end:
> +	user_read_access_end();
> +	return ret;
> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260520154004.3845823-1-jremus@linux.ibm.com?part=5

  reply	other threads:[~2026-05-20 16:33 UTC|newest]

Thread overview: 52+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-20 15:39 [PATCH v15 00/20] unwind_deferred: Implement sframe handling Jens Remus
2026-05-20 15:39 ` [PATCH v15 01/20] unwind_user: Add generic and arch-specific headers to MAINTAINERS Jens Remus
2026-05-20 15:39 ` [PATCH v15 02/20] unwind_user/sframe: Add support for reading .sframe headers Jens Remus
2026-05-20 16:02   ` sashiko-bot
2026-05-21  7:58     ` Jens Remus
2026-05-20 15:39 ` [PATCH v15 03/20] unwind_user/sframe: Store .sframe section data in per-mm maple tree Jens Remus
2026-05-20 16:29   ` sashiko-bot
2026-05-21  9:39     ` Jens Remus
2026-05-21 16:08       ` Steven Rostedt
2026-05-20 15:39 ` [PATCH v15 04/20] x86/uaccess: Add unsafe_copy_from_user() implementation Jens Remus
2026-05-20 16:13   ` sashiko-bot
2026-05-20 15:39 ` [PATCH v15 05/20] unwind_user/sframe: Add support for reading .sframe contents Jens Remus
2026-05-20 16:33   ` sashiko-bot [this message]
2026-05-21  9:40     ` Jens Remus
2026-05-20 15:39 ` [PATCH v15 06/20] unwind_user/sframe: Detect .sframe sections in executables Jens Remus
2026-05-20 15:39 ` [PATCH v15 07/20] unwind_user/sframe: Wire up unwind_user to sframe Jens Remus
2026-05-20 16:23   ` sashiko-bot
2026-05-21 10:44     ` Jens Remus
2026-05-20 15:39 ` [PATCH v15 08/20] unwind_user: Stop when reaching an outermost frame Jens Remus
2026-05-20 16:01   ` sashiko-bot
2026-05-21 10:45     ` Jens Remus
2026-05-20 15:39 ` [PATCH v15 09/20] unwind_user/sframe: Add support for outermost frame indication Jens Remus
2026-05-20 16:01   ` sashiko-bot
2026-05-21 10:46     ` Jens Remus
2026-05-20 15:39 ` [PATCH v15 10/20] unwind_user/sframe: Remove .sframe section on detected corruption Jens Remus
2026-05-20 16:26   ` sashiko-bot
2026-05-20 15:39 ` [PATCH v15 11/20] unwind_user/sframe: Show file name in debug output Jens Remus
2026-05-20 16:14   ` sashiko-bot
2026-05-21 10:55     ` Jens Remus
2026-05-21 16:20       ` Steven Rostedt
2026-05-20 15:39 ` [PATCH v15 12/20] unwind_user/sframe: Add .sframe validation option Jens Remus
2026-05-20 16:15   ` sashiko-bot
2026-05-21 12:51     ` Jens Remus
2026-05-20 15:39 ` [PATCH v15 13/20] unwind_user: Enable archs that pass RA in a register Jens Remus
2026-05-20 16:21   ` sashiko-bot
2026-05-21 13:00     ` Jens Remus
2026-05-20 15:39 ` [PATCH v15 14/20] unwind_user: Flexible FP/RA recovery rules Jens Remus
2026-05-20 15:39 ` [PATCH v15 15/20] unwind_user: Flexible CFA " Jens Remus
2026-05-20 16:22   ` sashiko-bot
2026-05-21 11:33     ` Jens Remus
2026-05-20 15:40 ` [PATCH v15 16/20] unwind_user/sframe: Add support for SFrame V3 flexible FDEs Jens Remus
2026-05-20 17:04   ` sashiko-bot
2026-05-21 11:58     ` Jens Remus
2026-05-20 15:40 ` [PATCH v15 17/20] unwind_user/sframe: Separate reading of FRE from reading of FRE data words Jens Remus
2026-05-20 16:48   ` sashiko-bot
2026-05-20 15:40 ` [PATCH v15 18/20] unwind_user/sframe: Duplicate registered .sframe section data on clone/fork Jens Remus
2026-05-20 17:01   ` sashiko-bot
2026-05-21 12:05     ` Jens Remus
2026-05-20 15:40 ` [PATCH v15 19/20] unwind_user/sframe/x86: Enable sframe unwinding on x86 Jens Remus
2026-05-20 15:40 ` [PATCH v15 20/20] unwind_user/sframe: Add prctl() interface for registering .sframe sections Jens Remus
2026-05-20 16:52   ` sashiko-bot
2026-05-21 12:08     ` Jens Remus

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=20260520163348.11FD21F00893@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=jremus@linux.ibm.com \
    --cc=sashiko-reviews@lists.linux.dev \
    /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