From: Jens Remus <jremus@linux.ibm.com>
To: Steven Rostedt <rostedt@kernel.org>,
Josh Poimboeuf <jpoimboe@kernel.org>,
Indu Bhagat <ibhagatgnu@gmail.com>
Cc: bpf@vger.kernel.org, sashiko@lists.linux.dev
Subject: Re: [PATCH v14 05/19] unwind_user/sframe: Add support for reading .sframe contents
Date: Wed, 6 May 2026 16:34:34 +0200 [thread overview]
Message-ID: <4e5d51f0-8f4c-4a07-9141-8b26d2c90fc6@linux.ibm.com> (raw)
In-Reply-To: <20260505185932.C708CC2BCB4@smtp.kernel.org>
On 5/5/2026 8:59 PM, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
> - [Critical] Division by zero in `__find_fre` when `fde->rep_size` is 0.
> - [High] `mtree_insert_range` is called with an exclusive end boundary, preventing contiguous SFrame sections.
> - [High] Unbounded linear search over user-controlled memory in `__find_fre` can cause hard lockups in atomic context.
> - [High] Integer overflows in SFrame header parsing allow bypass of bounds checks on 32-bit architectures.
> - [Medium] Generic SFrame unwinding code uses `unsafe_get_user()` for unaligned accesses, breaking strict-alignment architectures.
> --
>
> commit 159c92acf3c961aecc6383f6c3f35a955591abf3
> Author: Josh Poimboeuf <jpoimboe@kernel.org>
>
> unwind_user/sframe: Add support for reading .sframe contents
>
> This commit adds support for reading .sframe section contents to facilitate
> user space stack unwinding. It introduces the sframe_find() interface which
> uses user_read_access_begin() and unsafe_*() accessors for performance.
> Support is included for SFrame V3, internal FDE representations, and
> PC-relative offsets.
>
> 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 fdb2a49085638..c60aa527984a1 100644
>> --- a/kernel/unwind/sframe.c
>> +++ b/kernel/unwind/sframe.c
>> @@ -15,9 +15,338 @@
>> #include <linux/unwind_user_types.h>
>>
>> #include "sframe.h"
>> +#include "sframe_debug.h"
>
> [ ... ]
>
>> +static __always_inline int __read_fre(struct sframe_section *sec,
>> + struct sframe_fde_internal *fde,
>> + unsigned long fre_addr,
>> + struct sframe_fre_internal *fre)
>> +{
> [ ... ]
>> + if (fre_addr + addr_size + 1 > sec->fres_end)
>> + return -EFAULT;
>> +
>> + UNSAFE_GET_USER_INC(ip_off, cur, addr_size, Efault);
>
> Will this cause alignment faults on architectures with strict alignment
> requirements?
>
> The .sframe format uses packed structures and variable-length datawords. The
> cur pointer might be unaligned here, and UNSAFE_GET_USER_INC() performs
> 16-bit or 32-bit reads via unsafe_get_user().
IIUC this should not be an issue for x86-64, s390, and arm64.
> [ ... ]
>
>> +static __always_inline int __find_fre(struct sframe_section *sec,
>> + struct sframe_fde_internal *fde,
>> + unsigned long ip,
>> + struct unwind_user_frame *frame)
>> +{
>> + unsigned char fde_pctype = SFRAME_V3_FDE_PCTYPE(fde->info);
>> + struct sframe_fre_internal *fre, *prev_fre = NULL;
>> + struct sframe_fre_internal fres[2];
>> + unsigned long fre_addr;
>> + bool which = false;
>> + unsigned int i;
>> + u32 ip_off;
>> +
>> + ip_off = ip - fde->func_addr;
>> +
>> + if (fde_pctype == SFRAME_FDE_PCTYPE_MASK)
>> + ip_off %= fde->rep_size;
>
> Can a malicious user provide an SFrame section with a rep_size of 0?
>
> Since fde->rep_size is populated directly from the user-provided
> _fda.rep_size without validation, a 0 value here would trigger a
> divide-by-zero exception and a kernel panic.
Good catch! I would add a check in __read_fde():
diff --git a/kernel/unwind/sframe.c b/kernel/unwind/sframe.c
@@ -67,6 +67,7 @@ static __always_inline int __read_fde(struct sframe_section *sec,
unsigned long fde_addr, fda_addr, func_addr;
struct sframe_fde_v3 _fde;
struct sframe_fda_v3 _fda;
+ unsigned char fde_pctype;
fde_addr = sec->fdes_start + (fde_num * sizeof(struct sframe_fde_v3));
unsafe_copy_from_user(&_fde, (void __user *)fde_addr,
@@ -82,6 +83,10 @@ static __always_inline int __read_fde(struct sframe_section *sec,
unsafe_copy_from_user(&_fda, (void __user *)fda_addr,
sizeof(struct sframe_fda_v3), Efault);
+ fde_pctype = SFRAME_V3_FDE_PCTYPE(_fda.info);
+ if (fde_pctype == SFRAME_FDE_PCTYPE_MASK && !_fda.rep_size)
+ return -EINVAL;
+
fde->func_addr = func_addr;
fde->func_size = _fde.func_size;
fde->fda_off = _fde.fres_off;
>
>> +
>> + fre_addr = sec->fres_start + fde->fres_off;
>> +
>> + for (i = 0; i < fde->fres_num; i++) {
>
> Can this loop cause a hard lockup in atomic context?
>
> fde->fres_num is a 32-bit value copied from user space without validation.
> Since sframe_find() is designed to be called by unwinders in NMI context, an
> attacker could provide a very large number of valid entries. Executing
> billions of iterations and unsafe_get_user() calls could stall the CPU
> and trigger the hard lockup detector.
Please advise.
>
>> + int ret;
>> +
>
> [ ... ]
>
>> @@ -120,8 +449,10 @@ int sframe_add_section(unsigned long sframe_start, unsigned long sframe_end,
>> sec->text_end = text_end;
>>
>> ret = sframe_read_header(sec);
>> - if (ret)
>> + if (ret) {
>> + dbg_print_header(sec);
>> goto err_free;
>> + }
>
> Can shdr.fre_len cause an integer overflow on 32-bit architectures during
> header parsing?
>
> If a malicious user provides a large fre_len in the header, fres_end
> (calculated as fres_start + shdr.fre_len) could wrap around the 32-bit
> address space. This would bypass the bounds check in sframe_read_header(),
> allowing fres_start and fdes_start to point into kernel memory. Later, when
> __read_fde() and __find_fre() use unsafe_get_user(), this could lead to
> arbitrary kernel memory disclosure.
SFrame is currently only supported on 64-bit architectures (i.e. x86-64,
arm64, s390 64-bit). So unsigned long fres_end should always be 64-bit.
Do we need to add the following to the header parsing?
if (fdes_start >= fdes_end || fres_start >= fres_end) {
dbg_sec("inconsistent FDE/FRE start/end address\n");
return -EINVAL;
}
>
>>
>> ret = mtree_insert_range(sframe_mt, sec->text_start, sec->text_end, sec, GFP_KERNEL);
>
> Does passing sec->text_end directly as the last parameter to
> mtree_insert_range() break contiguous mappings?
>
> mtree_insert_range() expects the last boundary to be inclusive, but
> sec->text_end represents the exclusive end address of the executable segment.
> If user space maps seamlessly contiguous text segments, the insertion for the
> second segment might overlap with the claimed end of the first, causing it to
> fail with -EEXIST.
Addressed in previous patch.
>
>> if (ret) {
>> dbg("mtree_insert_range failed: text=%lx-%lx\n",
>
Thanks and regards,
Jens
--
Jens Remus
Linux on Z Development (D3303)
jremus@de.ibm.com / jremus@linux.ibm.com
IBM Deutschland Research & Development GmbH; Vorsitzender des Aufsichtsrats: Wolfgang Wendt; Geschäftsführung: David Faller; Sitz der Gesellschaft: Ehningen; Registergericht: Amtsgericht Stuttgart, HRB 243294
IBM Data Privacy Statement: https://www.ibm.com/privacy/
next prev parent reply other threads:[~2026-05-06 14:34 UTC|newest]
Thread overview: 80+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-05 12:16 [PATCH v14 00/19] unwind_deferred: Implement sframe handling Jens Remus
2026-05-05 12:17 ` [PATCH v14 01/19] unwind_user: Add generic and arch-specific headers to MAINTAINERS Jens Remus
2026-05-05 12:17 ` [PATCH v14 02/19] unwind_user/sframe: Add support for reading .sframe headers Jens Remus
2026-05-05 12:49 ` sashiko-bot
2026-05-06 13:42 ` Jens Remus
2026-05-07 14:55 ` Jens Remus
2026-05-08 23:02 ` Indu Bhagat
2026-05-11 10:05 ` Jens Remus
2026-05-05 12:17 ` [PATCH v14 03/19] unwind_user/sframe: Store .sframe section data in per-mm maple tree Jens Remus
2026-05-05 18:51 ` sashiko-bot
2026-05-06 13:50 ` Jens Remus
2026-05-06 15:21 ` Steven Rostedt
2026-05-12 15:52 ` Jens Remus
2026-05-05 12:17 ` [PATCH v14 04/19] x86/uaccess: Add unsafe_copy_from_user() implementation Jens Remus
2026-05-05 18:22 ` sashiko-bot
2026-05-06 14:13 ` Jens Remus
2026-05-06 15:05 ` Steven Rostedt
2026-05-06 14:09 ` Jens Remus
2026-05-06 15:03 ` Steven Rostedt
2026-05-06 21:13 ` David Laight
2026-05-06 21:17 ` David Laight
2026-05-05 12:17 ` [PATCH v14 05/19] unwind_user/sframe: Add support for reading .sframe contents Jens Remus
2026-05-05 18:59 ` sashiko-bot
2026-05-06 14:34 ` Jens Remus [this message]
2026-05-06 15:01 ` Steven Rostedt
2026-05-06 15:29 ` Jens Remus
2026-05-08 9:49 ` Jens Remus
2026-05-08 23:04 ` Indu Bhagat
2026-05-12 13:35 ` Jens Remus
2026-05-13 12:22 ` Steven Rostedt
2026-05-08 23:03 ` Indu Bhagat
2026-05-08 10:50 ` Jens Remus
2026-05-11 16:16 ` Jens Remus
2026-05-05 12:17 ` [PATCH v14 06/19] unwind_user/sframe: Detect .sframe sections in executables Jens Remus
2026-05-05 12:53 ` sashiko-bot
2026-05-06 14:56 ` Jens Remus
2026-05-06 15:36 ` Steven Rostedt
2026-05-08 23:05 ` Indu Bhagat
2026-05-05 12:17 ` [PATCH v14 07/19] unwind_user/sframe: Wire up unwind_user to sframe Jens Remus
2026-05-05 18:55 ` sashiko-bot
2026-05-07 16:18 ` Jens Remus
2026-05-08 23:07 ` Indu Bhagat
2026-05-11 16:46 ` Steven Rostedt
2026-05-05 12:17 ` [PATCH v14 08/19] unwind_user: Stop when reaching an outermost frame Jens Remus
2026-05-05 12:40 ` sashiko-bot
2026-05-06 15:01 ` Jens Remus
2026-05-06 15:40 ` Steven Rostedt
2026-05-05 12:17 ` [PATCH v14 09/19] unwind_user/sframe: Add support for outermost frame indication Jens Remus
2026-05-05 12:17 ` [PATCH v14 10/19] unwind_user/sframe: Remove .sframe section on detected corruption Jens Remus
2026-05-05 20:39 ` sashiko-bot
2026-05-07 16:23 ` Jens Remus
2026-05-05 12:17 ` [PATCH v14 11/19] unwind_user/sframe: Show file name in debug output Jens Remus
2026-05-05 18:46 ` sashiko-bot
2026-05-12 14:52 ` Jens Remus
2026-05-13 9:20 ` Jens Remus
2026-05-05 12:17 ` [PATCH v14 12/19] unwind_user/sframe: Add .sframe validation option Jens Remus
2026-05-05 18:32 ` sashiko-bot
2026-05-12 14:23 ` Jens Remus
2026-05-13 12:30 ` Steven Rostedt
2026-05-08 10:51 ` Jens Remus
2026-05-05 12:17 ` [PATCH v14 13/19] unwind_user: Enable archs that pass RA in a register Jens Remus
2026-05-05 18:35 ` sashiko-bot
2026-05-05 12:17 ` [PATCH v14 14/19] unwind_user: Flexible FP/RA recovery rules Jens Remus
2026-05-05 18:34 ` sashiko-bot
2026-05-05 12:17 ` [PATCH v14 15/19] unwind_user: Flexible CFA " Jens Remus
2026-05-05 12:17 ` [PATCH v14 16/19] unwind_user/sframe: Add support for SFrame V3 flexible FDEs Jens Remus
2026-05-05 18:55 ` sashiko-bot
2026-05-07 15:30 ` Jens Remus
2026-05-13 6:26 ` Indu Bhagat
2026-05-13 13:50 ` Jens Remus
2026-05-13 15:16 ` Steven Rostedt
2026-05-05 12:17 ` [PATCH v14 17/19] unwind_user/sframe: Separate reading of FRE from reading of FRE data words Jens Remus
2026-05-05 19:05 ` sashiko-bot
2026-05-07 16:01 ` Jens Remus
2026-05-05 12:17 ` [PATCH v14 18/19] unwind_user/sframe/x86: Enable sframe unwinding on x86 Jens Remus
2026-05-05 19:07 ` sashiko-bot
2026-05-05 12:17 ` [PATCH v14 19/19] unwind_user/sframe: Add prctl() interface for registering .sframe sections Jens Remus
2026-05-05 18:45 ` sashiko-bot
2026-05-07 14:14 ` Jens Remus
2026-05-05 12:25 ` [PATCH v14 00/19] unwind_deferred: Implement sframe handling 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=4e5d51f0-8f4c-4a07-9141-8b26d2c90fc6@linux.ibm.com \
--to=jremus@linux.ibm.com \
--cc=bpf@vger.kernel.org \
--cc=ibhagatgnu@gmail.com \
--cc=jpoimboe@kernel.org \
--cc=rostedt@kernel.org \
--cc=sashiko@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 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.