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 <[email protected]>
---
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 @@ add_validator:
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)