* [PATCH v2 0/2] tracing/user_events: validate dynamic field bounds
@ 2026-11-03 2:45 Yifan Zhang
2026-11-03 2:45 ` [PATCH v2 1/2] tracing/user_events: validate dynamic cpumask size Yifan Zhang
2026-11-03 2:45 ` [PATCH v2 2/2] tracing/user_events: reject overflowing field offsets Yifan Zhang
0 siblings, 2 replies; 4+ messages in thread
From: Yifan Zhang @ 2026-11-03 2:45 UTC (permalink / raw)
To: Steven Rostedt, Masami Hiramatsu, linux-trace-kernel
Cc: Mathieu Desnoyers, Beau Belgrave, linux-kernel
These patches validate the size assumptions used by dynamic cpumask fields
and prevent explicit structure sizes from wrapping field offsets.
Changes in v2:
- parse explicit structure sizes into a u32 and reject values above INT_MAX
before assigning them to the signed size variable
Patch 1 is unchanged.
Yifan Zhang (2):
tracing/user_events: validate dynamic cpumask size
tracing/user_events: reject overflowing field offsets
kernel/trace/trace_events_user.c | 20 ++++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
--
2.39.5 (Apple Git-154)
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 1/2] tracing/user_events: validate dynamic cpumask size
2026-11-03 2:45 [PATCH v2 0/2] tracing/user_events: validate dynamic field bounds Yifan Zhang
@ 2026-11-03 2:45 ` Yifan Zhang
2026-11-04 21:39 ` Beau Belgrave
2026-11-03 2:45 ` [PATCH v2 2/2] tracing/user_events: reject overflowing field offsets Yifan Zhang
1 sibling, 1 reply; 4+ messages in thread
From: Yifan Zhang @ 2026-11-03 2:45 UTC (permalink / raw)
To: Steven Rostedt, Masami Hiramatsu, linux-trace-kernel
Cc: Mathieu Desnoyers, Beau Belgrave, linux-kernel
user_event_validate() checks that a dynamic field lies inside the event but
does not verify the minimum size required by its filter type. A one-byte
dynamic cpumask can therefore reach filter_pred_cpumask(), which consumes
cpumask_size() bytes beyond the event buffer.
KASAN reports:
BUG: KASAN: slab-use-after-free in filter_match_preds
Read of size 8
filter_match_preds
trace_event_buffer_commit
user_event_ftrace
user_events_write_core
Mark dynamic cpumask fields and reject locations shorter than
cpumask_size().
The patched kernel rejects the short event and accepts a full-size control
event without a KASAN report.
Fixes: 2467cda1b5c9 ("user_events: Validate user payloads for size and null termination")
Signed-off-by: Yifan Zhang <yfzhang23@stu.pku.edu.cn>
---
kernel/trace/trace_events_user.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c
index f658c3a77aa7a..85938b45b7618 100644
--- a/kernel/trace/trace_events_user.c
+++ b/kernel/trace/trace_events_user.c
@@ -170,6 +170,7 @@ struct user_event_file_info {
#define VALIDATOR_ENSURE_NULL (1 << 0)
#define VALIDATOR_REL (1 << 1)
+#define VALIDATOR_CPUMASK BIT(2)
struct user_event_validator {
struct list_head user_event_link;
@@ -1159,6 +1160,9 @@ static int user_event_add_field(struct user_event *user, const char *type,
if (strstr(type, "char") != NULL)
validator_flags |= VALIDATOR_ENSURE_NULL;
+ if (strstr(type, "cpumask_t"))
+ validator_flags |= VALIDATOR_CPUMASK;
+
validator = kmalloc_obj(*validator, GFP_KERNEL_ACCOUNT);
if (!validator) {
@@ -1598,6 +1602,10 @@ static int user_event_validate(struct user_event *user, void *data, int len)
offset = loc & 0xffff;
size = loc >> 16;
+ if (unlikely((validator->flags & VALIDATOR_CPUMASK) &&
+ size < cpumask_size()))
+ return -EFAULT;
+
if (likely(validator->flags & VALIDATOR_REL))
pos += offset + sizeof(loc);
else
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 2/2] tracing/user_events: reject overflowing field offsets
2026-11-03 2:45 [PATCH v2 0/2] tracing/user_events: validate dynamic field bounds Yifan Zhang
2026-11-03 2:45 ` [PATCH v2 1/2] tracing/user_events: validate dynamic cpumask size Yifan Zhang
@ 2026-11-03 2:45 ` Yifan Zhang
1 sibling, 0 replies; 4+ messages in thread
From: Yifan Zhang @ 2026-11-03 2:45 UTC (permalink / raw)
To: Steven Rostedt, Masami Hiramatsu, linux-trace-kernel
Cc: Mathieu Desnoyers, Beau Belgrave, linux-kernel
user_event_parse_field() accepts large structure sizes but accumulates
field offsets in a u32 before storing them in signed int fields. A
declaration can wrap the recorded minimum event size while a fixed-width
field retains an offset outside the accepted record. A short write is
then accepted and a field filter reads beyond the event buffer.
KASAN reports:
BUG: KASAN: slab-use-after-free in filter_match_preds
Read of size 8
filter_match_preds
trace_event_buffer_commit
user_event_ftrace
user_events_write_core
Parse an explicit structure size into a u32, reject values greater than
INT_MAX before converting them to int, and use checked addition for the
resulting field offset. This prevents both signed conversion and offset
overflow from bypassing the downstream bounds checks.
Fixes: 7f5a08c79df3 ("user_events: Add minimal support for trace_event into ftrace")
Signed-off-by: Yifan Zhang <yfzhang23@stu.pku.edu.cn>
---
kernel/trace/trace_events_user.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c
index 85938b45b7618..04eef4865490b 100644
--- a/kernel/trace/trace_events_user.c
+++ b/kernel/trace/trace_events_user.c
@@ -1207,6 +1207,7 @@ static int user_event_parse_field(char *field, struct user_event *user,
{
char *part, *type, *name;
u32 depth = 0, saved_offset = *offset;
+ u32 new_offset, struct_size;
int len, size = -EINVAL;
bool is_struct = false;
@@ -1267,8 +1268,11 @@ static int user_event_parse_field(char *field, struct user_event *user,
if (!is_struct)
return -EINVAL;
- if (kstrtou32(part, 10, &size))
+ if (kstrtou32(part, 10, &struct_size))
return -EINVAL;
+ if (struct_size > INT_MAX)
+ return -E2BIG;
+ size = struct_size;
break;
default:
return -EINVAL;
@@ -1287,7 +1291,11 @@ static int user_event_parse_field(char *field, struct user_event *user,
if (size < 0)
return size;
- *offset = saved_offset + size;
+ if (check_add_overflow(saved_offset, (u32)size, &new_offset) ||
+ new_offset > INT_MAX)
+ return -E2BIG;
+
+ *offset = new_offset;
return user_event_add_field(user, type, name, saved_offset, size,
type[0] != 'u', FILTER_OTHER);
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v2 1/2] tracing/user_events: validate dynamic cpumask size
2026-11-03 2:45 ` [PATCH v2 1/2] tracing/user_events: validate dynamic cpumask size Yifan Zhang
@ 2026-11-04 21:39 ` Beau Belgrave
0 siblings, 0 replies; 4+ messages in thread
From: Beau Belgrave @ 2026-11-04 21:39 UTC (permalink / raw)
To: Yifan Zhang
Cc: Steven Rostedt, Masami Hiramatsu, linux-trace-kernel,
Mathieu Desnoyers, linux-kernel
On Tue, Nov 03, 2026 at 10:45:19AM +0800, Yifan Zhang wrote:
> user_event_validate() checks that a dynamic field lies inside the event but
> does not verify the minimum size required by its filter type. A one-byte
> dynamic cpumask can therefore reach filter_pred_cpumask(), which consumes
> cpumask_size() bytes beyond the event buffer.
>
> KASAN reports:
>
> BUG: KASAN: slab-use-after-free in filter_match_preds
> Read of size 8
> filter_match_preds
Hey Yifan,
In the V1 there was a repro case where this value was a __data_loc,
which defines where the actual data (and it's size) is in the payload.
There isn't a type min-size requirement when __data_loc is used, this
seems like the bug resides possibly in filter_match_preds for
__data_loc cases? See comments futher down.
Steve, do you think this is the case?
If not, then I guess we would have to validate min-size requirements of
all types in the dynamic case, and I hope we could do that centrally to
avoid fixing these in various spots.
> trace_event_buffer_commit
> user_event_ftrace
> user_events_write_core
>
> Mark dynamic cpumask fields and reject locations shorter than
> cpumask_size().
>
> The patched kernel rejects the short event and accepts a full-size control
> event without a KASAN report.
>
> Fixes: 2467cda1b5c9 ("user_events: Validate user payloads for size and null termination")
> Signed-off-by: Yifan Zhang <yfzhang23@stu.pku.edu.cn>
> ---
> kernel/trace/trace_events_user.c | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c
> index f658c3a77aa7a..85938b45b7618 100644
> --- a/kernel/trace/trace_events_user.c
> +++ b/kernel/trace/trace_events_user.c
> @@ -170,6 +170,7 @@ struct user_event_file_info {
>
> #define VALIDATOR_ENSURE_NULL (1 << 0)
> #define VALIDATOR_REL (1 << 1)
> +#define VALIDATOR_CPUMASK BIT(2)
>
> struct user_event_validator {
> struct list_head user_event_link;
> @@ -1159,6 +1160,9 @@ static int user_event_add_field(struct user_event *user, const char *type,
> if (strstr(type, "char") != NULL)
> validator_flags |= VALIDATOR_ENSURE_NULL;
>
> + if (strstr(type, "cpumask_t"))
> + validator_flags |= VALIDATOR_CPUMASK;
> +
You can only get to this case if you put struct, __rel_loc, or __data_loc.
Those have their own size requirements and are dynamic in nature, IE:
Each write describes the actual size in the __rel_loc and __data_loc
cases, and statically for the struct case.
user_field_size() checks if a type name has a known size, if not, it
gets rejected. The only time this isn't the case is if you put struct in
front and then have to give a size that's expected. The other case is if
you put __data_loc or __rel_loc, both require the payload to dynamically
have a size associated.
In the dynamic case, the filter should be ensuring these values are
minimally sized.
> validator = kmalloc_obj(*validator, GFP_KERNEL_ACCOUNT);
>
> if (!validator) {
> @@ -1598,6 +1602,10 @@ static int user_event_validate(struct user_event *user, void *data, int len)
> offset = loc & 0xffff;
> size = loc >> 16;
>
> + if (unlikely((validator->flags & VALIDATOR_CPUMASK) &&
> + size < cpumask_size()))
> + return -EFAULT;
> +
> if (likely(validator->flags & VALIDATOR_REL))
> pos += offset + sizeof(loc);
> else
> --
> 2.39.5 (Apple Git-154)
Thanks,
-Beau
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-11-04 21:39 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-03 2:45 [PATCH v2 0/2] tracing/user_events: validate dynamic field bounds Yifan Zhang
2026-11-03 2:45 ` [PATCH v2 1/2] tracing/user_events: validate dynamic cpumask size Yifan Zhang
2026-11-04 21:39 ` Beau Belgrave
2026-11-03 2:45 ` [PATCH v2 2/2] tracing/user_events: reject overflowing field offsets Yifan Zhang
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.