History

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

Beau Belgrave committed 4 years ago

Commit 7e348b31 parent 3a733331 file · +40 −6Browse files

Showing the changes to kernel (1 of 1 file). Show all

Unified · Split

kernel/trace/trace_events_user.c+40−6
@@ -135,6 +135,8 @@ static struct list_head *user_event_get_fields(struct trace_event_call *call) · 134 unmodified lines
135 * NOTE: Offsets are from the user data perspective, they are not from the135 * NOTE: Offsets are from the user data perspective, they are not from the
136 * trace_entry/buffer perspective. We automatically add the common properties136 * trace_entry/buffer perspective. We automatically add the common properties
137 * sizes to the offset for the user.137 * sizes to the offset for the user.
138 *
139 * Upon success user_event has its ref count increased by 1.
138 */140 */
139static int user_event_parse_cmd(char *raw_command, struct user_event **newuser)141static int user_event_parse_cmd(char *raw_command, struct user_event **newuser)
140{142{
@@ -593,8 +595,10 @@ static struct user_event *find_user_event(char *name, u32 *outkey) · 452 unmodified lines
593 *outkey = key;595 *outkey = key;
594 596
595 hash_for_each_possible(register_table, user, node, key)597 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);
597 return user;600 return user;
601 }
598 602
599 return NULL;603 return NULL;
600}604}
@@ -883,7 +887,12 @@ static int user_event_create(const char *raw_command) · 282 unmodified lines
883 return -ENOMEM;887 return -ENOMEM;
884 888
885 mutex_lock(&reg_mutex);889 mutex_lock(&reg_mutex);
890
886 ret = user_event_parse_cmd(name, &user);891 ret = user_event_parse_cmd(name, &user);
892
893 if (!ret)
894 atomic_dec(&user->refcnt);
895
887 mutex_unlock(&reg_mutex);896 mutex_unlock(&reg_mutex);
888 897
889 if (ret)898 if (ret)
@@ -1050,6 +1059,7 @@ static int user_event_trace_register(struct user_event *user) · 160 unmodified lines
1050/*1059/*
1051 * Parses the event name, arguments and flags then registers if successful.1060 * Parses the event name, arguments and flags then registers if successful.
1052 * The name buffer lifetime is owned by this method for success cases only.1061 * 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.
1053 */1063 */
1054static int user_event_parse(char *name, char *args, char *flags,1064static int user_event_parse(char *name, char *args, char *flags,
1055 struct user_event **newuser)1065 struct user_event **newuser)
@@ -1057,7 +1067,12 @@ static int user_event_parse(char *name, char *args, char *flags, · 1 unmodified line
1057 int ret;1067 int ret;
1058 int index;1068 int index;
1059 u32 key;1069 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);
1061 1076
1062 if (user) {1077 if (user) {
1063 *newuser = user;1078 *newuser = user;
@@ -1121,6 +1136,10 @@ static int user_event_parse(char *name, char *args, char *flags, · 57 unmodified lines
1121 goto put_user;1136 goto put_user;
1122 1137
1123 user->index = index;1138 user->index = index;
1139
1140 /* Ensure we track ref */
1141 atomic_inc(&user->refcnt);
1142
1124 dyn_event_init(&user->devent, &user_event_dops);1143 dyn_event_init(&user->devent, &user_event_dops);
1125 dyn_event_add(&user->devent, &user->call);1144 dyn_event_add(&user->devent, &user->call);
1126 set_bit(user->index, page_bitmap);1145 set_bit(user->index, page_bitmap);
@@ -1147,12 +1166,21 @@ static int delete_user_event(char *name) · 20 unmodified lines
1147 if (!user)1166 if (!user)
1148 return -ENOENT;1167 return -ENOENT;
1149 1168
1150 if (atomic_read(&user->refcnt) != 0)1169 /* Ensure we are the last ref */
1151 return -EBUSY;1170 if (atomic_read(&user->refcnt) != 1) {
1171 ret = -EBUSY;
1172 goto put_ref;
1173 }
1152 1174
1153 mutex_lock(&event_mutex);
1154 ret = destroy_user_event(user);1175 ret = destroy_user_event(user);
1155 mutex_unlock(&event_mutex);1176
1177 if (ret)
1178 goto put_ref;
1179
1180 return ret;
1181put_ref:
1182 /* No longer have this ref */
1183 atomic_dec(&user->refcnt);
1156 1184
1157 return ret;1185 return ret;
1158}1186}
@@ -1340,6 +1368,9 @@ static long user_events_ioctl_reg(struct file *file, unsigned long uarg) · 181 unmodified lines
1340 1368
1341 ret = user_events_ref_add(file, user);1369 ret = user_events_ref_add(file, user);
1342 1370
1371 /* No longer need parse ref, ref_add either worked or not */
1372 atomic_dec(&user->refcnt);
1373
1343 /* Positive number is index and valid */1374 /* Positive number is index and valid */
1344 if (ret < 0)1375 if (ret < 0)
1345 return ret;1376 return ret;
@@ -1364,7 +1395,10 @@ static long user_events_ioctl_del(struct file *file, unsigned long uarg) · 18 unmodified lines
1364 if (IS_ERR(name))1395 if (IS_ERR(name))
1365 return PTR_ERR(name);1396 return PTR_ERR(name);
1366 1397
1398 /* event_mutex prevents dyn_event from racing */
1399 mutex_lock(&event_mutex);
1367 ret = delete_user_event(name);1400 ret = delete_user_event(name);
1401 mutex_unlock(&event_mutex);
1368 1402
1369 kfree(name);1403 kfree(name);
1370 1404

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t