Skip to content

Commit 97bbce8

Browse files
beaubelgraverostedt
authored andcommitted
tracing/user_events: Prevent same address and bit per process
User processes register an address and bit pair for events. If the same address and bit pair are registered multiple times in the same process, it can cause undefined behavior when events are enabled/disabled. When more than one are used, the bit could be turned off by another event being disabled, while the original event is still enabled. Prevent undefined behavior by checking the current mm to see if any event has already been registered for the address and bit pair. Return EADDRINUSE back to the user process if it's already being used. Update ftrace self-test to ensure this occurs properly. Link: https://lkml.kernel.org/r/20230425225107.8525-4-beaub@linux.microsoft.com Suggested-by: Doug Cook <dcook@linux.microsoft.com> Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
1 parent 17b439d commit 97bbce8

2 files changed

Lines changed: 49 additions & 1 deletion

File tree

kernel/trace/trace_events_user.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,21 @@ static int user_event_enabler_write(struct user_event_mm *mm,
419419
return 0;
420420
}
421421

422+
static bool user_event_enabler_exists(struct user_event_mm *mm,
423+
unsigned long uaddr, unsigned char bit)
424+
{
425+
struct user_event_enabler *enabler;
426+
struct user_event_enabler *next;
427+
428+
list_for_each_entry_safe(enabler, next, &mm->enablers, link) {
429+
if (enabler->addr == uaddr &&
430+
(enabler->values & ENABLE_VAL_BIT_MASK) == bit)
431+
return true;
432+
}
433+
434+
return false;
435+
}
436+
422437
static void user_event_enabler_update(struct user_event *user)
423438
{
424439
struct user_event_enabler *enabler;
@@ -657,6 +672,22 @@ void user_event_mm_dup(struct task_struct *t, struct user_event_mm *old_mm)
657672
user_event_mm_remove(t);
658673
}
659674

675+
static bool current_user_event_enabler_exists(unsigned long uaddr,
676+
unsigned char bit)
677+
{
678+
struct user_event_mm *user_mm = current_user_event_mm();
679+
bool exists;
680+
681+
if (!user_mm)
682+
return false;
683+
684+
exists = user_event_enabler_exists(user_mm, uaddr, bit);
685+
686+
user_event_mm_put(user_mm);
687+
688+
return exists;
689+
}
690+
660691
static struct user_event_enabler
661692
*user_event_enabler_create(struct user_reg *reg, struct user_event *user,
662693
int *write_result)
@@ -2048,6 +2079,16 @@ static long user_events_ioctl_reg(struct user_event_file_info *info,
20482079
if (ret)
20492080
return ret;
20502081

2082+
/*
2083+
* Prevent users from using the same address and bit multiple times
2084+
* within the same mm address space. This can cause unexpected behavior
2085+
* for user processes that is far easier to debug if this is explictly
2086+
* an error upon registering.
2087+
*/
2088+
if (current_user_event_enabler_exists((unsigned long)reg.enable_addr,
2089+
reg.enable_bit))
2090+
return -EADDRINUSE;
2091+
20512092
name = strndup_user((const char __user *)(uintptr_t)reg.name_args,
20522093
MAX_EVENT_DESC);
20532094

tools/testing/selftests/user_events/ftrace_test.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,12 @@ TEST_F(user, register_events) {
219219
ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, &reg));
220220
ASSERT_EQ(0, reg.write_index);
221221

222-
/* Multiple registers should result in same index */
222+
/* Multiple registers to the same addr + bit should fail */
223+
ASSERT_EQ(-1, ioctl(self->data_fd, DIAG_IOCSREG, &reg));
224+
ASSERT_EQ(EADDRINUSE, errno);
225+
226+
/* Multiple registers to same name should result in same index */
227+
reg.enable_bit = 30;
223228
ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, &reg));
224229
ASSERT_EQ(0, reg.write_index);
225230

@@ -242,6 +247,8 @@ TEST_F(user, register_events) {
242247

243248
/* Unregister */
244249
ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSUNREG, &unreg));
250+
unreg.disable_bit = 30;
251+
ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSUNREG, &unreg));
245252

246253
/* Delete should work only after close and unregister */
247254
close(self->data_fd);

0 commit comments

Comments
 (0)