Skip to content

Commit 7e348b3

Browse files
beaubelgraverostedt
authored andcommitted
user_events: Prevent dyn_event delete racing with ioctl add/delete
Find user_events always while under the event_mutex and before leaving the lock, add a ref count to the user_event. This ensures that all paths under the event_mutex that check the ref counts will be synchronized. The ioctl add/delete paths are protected by the reg_mutex. However, dyn_event is only protected by the event_mutex. The dyn_event delete path cannot acquire reg_mutex, since that could cause a deadlock between the ioctl delete case acquiring event_mutex after acquiring the reg_mutex. Link: https://lkml.kernel.org/r/20220310001141.1660-1-beaub@linux.microsoft.com Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
1 parent 3a73333 commit 7e348b3

1 file changed

Lines changed: 40 additions & 6 deletions

File tree

kernel/trace/trace_events_user.c

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ static struct list_head *user_event_get_fields(struct trace_event_call *call)
135135
* NOTE: Offsets are from the user data perspective, they are not from the
136136
* trace_entry/buffer perspective. We automatically add the common properties
137137
* sizes to the offset for the user.
138+
*
139+
* Upon success user_event has its ref count increased by 1.
138140
*/
139141
static int user_event_parse_cmd(char *raw_command, struct user_event **newuser)
140142
{
@@ -593,8 +595,10 @@ static struct user_event *find_user_event(char *name, u32 *outkey)
593595
*outkey = key;
594596

595597
hash_for_each_possible(register_table, user, node, key)
596-
if (!strcmp(EVENT_NAME(user), name))
598+
if (!strcmp(EVENT_NAME(user), name)) {
599+
atomic_inc(&user->refcnt);
597600
return user;
601+
}
598602

599603
return NULL;
600604
}
@@ -883,7 +887,12 @@ static int user_event_create(const char *raw_command)
883887
return -ENOMEM;
884888

885889
mutex_lock(&reg_mutex);
890+
886891
ret = user_event_parse_cmd(name, &user);
892+
893+
if (!ret)
894+
atomic_dec(&user->refcnt);
895+
887896
mutex_unlock(&reg_mutex);
888897

889898
if (ret)
@@ -1050,14 +1059,20 @@ static int user_event_trace_register(struct user_event *user)
10501059
/*
10511060
* Parses the event name, arguments and flags then registers if successful.
10521061
* The name buffer lifetime is owned by this method for success cases only.
1062+
* Upon success the returned user_event has its ref count increased by 1.
10531063
*/
10541064
static int user_event_parse(char *name, char *args, char *flags,
10551065
struct user_event **newuser)
10561066
{
10571067
int ret;
10581068
int index;
10591069
u32 key;
1060-
struct user_event *user = find_user_event(name, &key);
1070+
struct user_event *user;
1071+
1072+
/* Prevent dyn_event from racing */
1073+
mutex_lock(&event_mutex);
1074+
user = find_user_event(name, &key);
1075+
mutex_unlock(&event_mutex);
10611076

10621077
if (user) {
10631078
*newuser = user;
@@ -1121,6 +1136,10 @@ static int user_event_parse(char *name, char *args, char *flags,
11211136
goto put_user;
11221137

11231138
user->index = index;
1139+
1140+
/* Ensure we track ref */
1141+
atomic_inc(&user->refcnt);
1142+
11241143
dyn_event_init(&user->devent, &user_event_dops);
11251144
dyn_event_add(&user->devent, &user->call);
11261145
set_bit(user->index, page_bitmap);
@@ -1147,12 +1166,21 @@ static int delete_user_event(char *name)
11471166
if (!user)
11481167
return -ENOENT;
11491168

1150-
if (atomic_read(&user->refcnt) != 0)
1151-
return -EBUSY;
1169+
/* Ensure we are the last ref */
1170+
if (atomic_read(&user->refcnt) != 1) {
1171+
ret = -EBUSY;
1172+
goto put_ref;
1173+
}
11521174

1153-
mutex_lock(&event_mutex);
11541175
ret = destroy_user_event(user);
1155-
mutex_unlock(&event_mutex);
1176+
1177+
if (ret)
1178+
goto put_ref;
1179+
1180+
return ret;
1181+
put_ref:
1182+
/* No longer have this ref */
1183+
atomic_dec(&user->refcnt);
11561184

11571185
return ret;
11581186
}
@@ -1340,6 +1368,9 @@ static long user_events_ioctl_reg(struct file *file, unsigned long uarg)
13401368

13411369
ret = user_events_ref_add(file, user);
13421370

1371+
/* No longer need parse ref, ref_add either worked or not */
1372+
atomic_dec(&user->refcnt);
1373+
13431374
/* Positive number is index and valid */
13441375
if (ret < 0)
13451376
return ret;
@@ -1364,7 +1395,10 @@ static long user_events_ioctl_del(struct file *file, unsigned long uarg)
13641395
if (IS_ERR(name))
13651396
return PTR_ERR(name);
13661397

1398+
/* event_mutex prevents dyn_event from racing */
1399+
mutex_lock(&event_mutex);
13671400
ret = delete_user_event(name);
1401+
mutex_unlock(&event_mutex);
13681402

13691403
kfree(name);
13701404

0 commit comments

Comments
 (0)