Skip to content

Commit

Permalink
user_events: Add trace event call as root for low permission cases
Browse files Browse the repository at this point in the history
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.com

Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
  • Loading branch information
Beau Belgrave authored and Steven Rostedt (Google) committed Mar 15, 2022
1 parent bc47ee4 commit 089331d
Showing 1 changed file with 37 additions and 2 deletions.
39 changes: 37 additions & 2 deletions kernel/trace/trace_events_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -562,14 +562,49 @@ static struct trace_event_functions user_event_funcs = {
.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)
{
int ret = 0;

/* Must destroy fields before call removal */
user_event_destroy_fields(user);

ret = trace_remove_event_call(&user->call);
ret = user_event_set_call_visible(user, false);

if (ret)
return ret;
Expand Down Expand Up @@ -1049,7 +1084,7 @@ static int user_event_trace_register(struct user_event *user)
if (!ret)
return -ENODEV;

ret = trace_add_event_call(&user->call);
ret = user_event_set_call_visible(user, true);

if (ret)
unregister_trace_event(&user->call.event);
Expand Down

0 comments on commit 089331d

Please sign in to comment.