summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorBeau Belgrave <beaub@linux.microsoft.com>2023-04-25 15:51:05 -0700
committerSteven Rostedt (Google) <rostedt@goodmis.org>2023-04-25 21:04:16 -0400
commit17b439db21d5dbe70c419e982262621e5e6aba7f (patch)
tree20e77f8a2a91e04fbfdb30355df7eb5fbb03643d /kernel
parentcd98c93286a30cc4588dfd02453bec63c2f4acf4 (diff)
tracing/user_events: Ensure bit is cleared on unregister
If an event is enabled and a user process unregisters user_events, the bit is left set. Fix this by always clearing the bit in the user process if unregister is successful. Update abi self-test to ensure this occurs properly. Link: https://lkml.kernel.org/r/20230425225107.8525-3-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>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/trace/trace_events_user.c34
1 files changed, 34 insertions, 0 deletions
diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c
index 546d47a57520..4f9ae63dfc5d 100644
--- a/kernel/trace/trace_events_user.c
+++ b/kernel/trace/trace_events_user.c
@@ -2149,6 +2149,35 @@ static long user_unreg_get(struct user_unreg __user *ureg,
return ret;
}
+static int user_event_mm_clear_bit(struct user_event_mm *user_mm,
+ unsigned long uaddr, unsigned char bit)
+{
+ struct user_event_enabler enabler;
+ int result;
+
+ memset(&enabler, 0, sizeof(enabler));
+ enabler.addr = uaddr;
+ enabler.values = bit;
+retry:
+ /* Prevents state changes from racing with new enablers */
+ mutex_lock(&event_mutex);
+
+ /* Force the bit to be cleared, since no event is attached */
+ mmap_read_lock(user_mm->mm);
+ result = user_event_enabler_write(user_mm, &enabler, false);
+ mmap_read_unlock(user_mm->mm);
+
+ mutex_unlock(&event_mutex);
+
+ if (result) {
+ /* Attempt to fault-in and retry if it worked */
+ if (!user_event_mm_fault_in(user_mm, uaddr))
+ goto retry;
+ }
+
+ return result;
+}
+
/*
* Unregisters an enablement address/bit within a task/user mm.
*/
@@ -2193,6 +2222,11 @@ static long user_events_ioctl_unreg(unsigned long uarg)
mutex_unlock(&event_mutex);
+ /* Ensure bit is now cleared for user, regardless of event status */
+ if (!ret)
+ ret = user_event_mm_clear_bit(mm, reg.disable_addr,
+ reg.disable_bit);
+
return ret;
}