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.com Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
This commit is contained in:
parent
bc47ee4844
commit
089331d473
@ -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)
|
|||||||
/* 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)
|
|||||||
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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user