Commit 089331d4 authored by Beau Belgrave's avatar Beau Belgrave Committed by Steven Rostedt (Google)

user_events: Add trace event call as root for low permission cases

Tracefs by default is locked down heavily. System operators can open up
some files, such as user_events to a broader set of users. These users
do not have access within tracefs beyond just the user_event files. Due
to this restriction the trace_add_event_call/remove calls will silently
fail since the caller does not have permissions to create directories.

To fix this trace_add_event_call/remove calls will be issued with
override creds of the global root UID. Creds are reverted immediately
afterward.

Link: https://lkml.kernel.org/r/20220308222807.2040-1-beaub@linux.microsoft.comSigned-off-by: default avatarBeau Belgrave <beaub@linux.microsoft.com>
Signed-off-by: default avatarSteven Rostedt (Google) <rostedt@goodmis.org>
parent bc47ee48
...@@ -562,6 +562,41 @@ static struct trace_event_functions user_event_funcs = { ...@@ -562,6 +562,41 @@ static struct trace_event_functions user_event_funcs = {
.trace = user_event_print_trace, .trace = user_event_print_trace,
}; };
static int user_event_set_call_visible(struct user_event *user, bool visible)
{
int ret;
const struct cred *old_cred;
struct cred *cred;
cred = prepare_creds();
if (!cred)
return -ENOMEM;
/*
* While by default tracefs is locked down, systems can be configured
* to allow user_event files to be less locked down. The extreme case
* being "other" has read/write access to user_events_data/status.
*
* When not locked down, processes may not have have permissions to
* add/remove calls themselves to tracefs. We need to temporarily
* switch to root file permission to allow for this scenario.
*/
cred->fsuid = GLOBAL_ROOT_UID;
old_cred = override_creds(cred);
if (visible)
ret = trace_add_event_call(&user->call);
else
ret = trace_remove_event_call(&user->call);
revert_creds(old_cred);
put_cred(cred);
return ret;
}
static int destroy_user_event(struct user_event *user) static int destroy_user_event(struct user_event *user)
{ {
int ret = 0; int ret = 0;
...@@ -569,7 +604,7 @@ static int destroy_user_event(struct user_event *user) ...@@ -569,7 +604,7 @@ static int destroy_user_event(struct user_event *user)
/* Must destroy fields before call removal */ /* Must destroy fields before call removal */
user_event_destroy_fields(user); user_event_destroy_fields(user);
ret = trace_remove_event_call(&user->call); ret = user_event_set_call_visible(user, false);
if (ret) if (ret)
return ret; return ret;
...@@ -1049,7 +1084,7 @@ static int user_event_trace_register(struct user_event *user) ...@@ -1049,7 +1084,7 @@ static int user_event_trace_register(struct user_event *user)
if (!ret) if (!ret)
return -ENODEV; return -ENODEV;
ret = trace_add_event_call(&user->call); ret = user_event_set_call_visible(user, true);
if (ret) if (ret)
unregister_trace_event(&user->call.event); unregister_trace_event(&user->call.event);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment