diff options
Diffstat (limited to 'meta/recipes-kernel/lttng/lttng-modules/0010-Fix-system-call-filter-table.patch')
-rw-r--r-- | meta/recipes-kernel/lttng/lttng-modules/0010-Fix-system-call-filter-table.patch | 918 |
1 files changed, 0 insertions, 918 deletions
diff --git a/meta/recipes-kernel/lttng/lttng-modules/0010-Fix-system-call-filter-table.patch b/meta/recipes-kernel/lttng/lttng-modules/0010-Fix-system-call-filter-table.patch deleted file mode 100644 index a16750ddb3..0000000000 --- a/meta/recipes-kernel/lttng/lttng-modules/0010-Fix-system-call-filter-table.patch +++ /dev/null | |||
@@ -1,918 +0,0 @@ | |||
1 | From ad594e3a953db1b0c3c059fde45b5a5494f6be78 Mon Sep 17 00:00:00 2001 | ||
2 | From: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | ||
3 | Date: Tue, 28 Jan 2020 16:02:44 -0500 | ||
4 | Subject: [PATCH 10/10] Fix: system call filter table | ||
5 | |||
6 | The system call filter table has effectively been unused for a long | ||
7 | time due to system call name prefix mismatch. This means the overhead of | ||
8 | selective system call tracing was larger than it should have been because | ||
9 | the event payload preparation would be done for all system calls as soon | ||
10 | as a single system call is traced. | ||
11 | |||
12 | However, fixing this underlying issue unearths several issues that crept | ||
13 | unnoticed when the "enabler" concept was introduced (after the original | ||
14 | implementation of the system call filter table). | ||
15 | |||
16 | Here is a list of the issues which are resolved here: | ||
17 | |||
18 | - Split lttng_syscalls_unregister into an unregister and destroy | ||
19 | function, thus awaiting for a grace period (and therefore quiescence | ||
20 | of the users) after unregistering the system call tracepoints before | ||
21 | freeing the system call filter data structures. This effectively fixes | ||
22 | a use-after-free. | ||
23 | |||
24 | - The state for enabling "all" system calls vs enabling specific system | ||
25 | calls (and sequences of enable-disable) was incorrect with respect to | ||
26 | the "enablers" semantic. This is solved by always tracking the | ||
27 | bitmap of enabled system calls, and keeping this bitmap even when | ||
28 | enabling all system calls. The sc_filter is now always allocated | ||
29 | before system call tracing is registered to tracepoints, which means | ||
30 | it does not need to be RCU dereferenced anymore. | ||
31 | |||
32 | Padding fields in the ABI are reserved to select whether to: | ||
33 | |||
34 | - Trace either native or compat system call (or both, which is the | ||
35 | behavior currently implemented), | ||
36 | - Trace either system call entry or exit (or both, which is the | ||
37 | behavior currently implemented), | ||
38 | - Select the system call to trace by name (behavior currently | ||
39 | implemented) or by system call number, | ||
40 | |||
41 | Upstream-Status: Backport | ||
42 | |||
43 | Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | ||
44 | --- | ||
45 | lttng-abi.c | 43 ++++++ | ||
46 | lttng-abi.h | 26 ++++ | ||
47 | lttng-events.c | 112 +++++++++++++-- | ||
48 | lttng-events.h | 31 ++++- | ||
49 | lttng-syscalls.c | 348 +++++++++++++++++++++++++---------------------- | ||
50 | 5 files changed, 380 insertions(+), 180 deletions(-) | ||
51 | |||
52 | diff --git a/lttng-abi.c b/lttng-abi.c | ||
53 | index 64ea99d..b33879d 100644 | ||
54 | --- a/lttng-abi.c | ||
55 | +++ b/lttng-abi.c | ||
56 | @@ -1264,6 +1264,46 @@ nomem: | ||
57 | return ret; | ||
58 | } | ||
59 | |||
60 | +static | ||
61 | +int lttng_abi_validate_event_param(struct lttng_kernel_event *event_param) | ||
62 | +{ | ||
63 | + /* Limit ABI to implemented features. */ | ||
64 | + switch (event_param->instrumentation) { | ||
65 | + case LTTNG_KERNEL_SYSCALL: | ||
66 | + switch (event_param->u.syscall.entryexit) { | ||
67 | + case LTTNG_KERNEL_SYSCALL_ENTRYEXIT: | ||
68 | + break; | ||
69 | + default: | ||
70 | + return -EINVAL; | ||
71 | + } | ||
72 | + switch (event_param->u.syscall.abi) { | ||
73 | + case LTTNG_KERNEL_SYSCALL_ABI_ALL: | ||
74 | + break; | ||
75 | + default: | ||
76 | + return -EINVAL; | ||
77 | + } | ||
78 | + switch (event_param->u.syscall.match) { | ||
79 | + case LTTNG_SYSCALL_MATCH_NAME: | ||
80 | + break; | ||
81 | + default: | ||
82 | + return -EINVAL; | ||
83 | + } | ||
84 | + break; | ||
85 | + | ||
86 | + case LTTNG_KERNEL_TRACEPOINT: /* Fallthrough */ | ||
87 | + case LTTNG_KERNEL_KPROBE: /* Fallthrough */ | ||
88 | + case LTTNG_KERNEL_KRETPROBE: /* Fallthrough */ | ||
89 | + case LTTNG_KERNEL_NOOP: /* Fallthrough */ | ||
90 | + case LTTNG_KERNEL_UPROBE: | ||
91 | + break; | ||
92 | + | ||
93 | + case LTTNG_KERNEL_FUNCTION: /* Fallthrough */ | ||
94 | + default: | ||
95 | + return -EINVAL; | ||
96 | + } | ||
97 | + return 0; | ||
98 | +} | ||
99 | + | ||
100 | static | ||
101 | int lttng_abi_create_event(struct file *channel_file, | ||
102 | struct lttng_kernel_event *event_param) | ||
103 | @@ -1305,6 +1345,9 @@ int lttng_abi_create_event(struct file *channel_file, | ||
104 | ret = -EOVERFLOW; | ||
105 | goto refcount_error; | ||
106 | } | ||
107 | + ret = lttng_abi_validate_event_param(event_param); | ||
108 | + if (ret) | ||
109 | + goto event_error; | ||
110 | if (event_param->instrumentation == LTTNG_KERNEL_TRACEPOINT | ||
111 | || event_param->instrumentation == LTTNG_KERNEL_SYSCALL) { | ||
112 | struct lttng_enabler *enabler; | ||
113 | diff --git a/lttng-abi.h b/lttng-abi.h | ||
114 | index 1d356ab..51d60e5 100644 | ||
115 | --- a/lttng-abi.h | ||
116 | +++ b/lttng-abi.h | ||
117 | @@ -90,6 +90,31 @@ struct lttng_kernel_event_callsite { | ||
118 | } u; | ||
119 | } __attribute__((packed)); | ||
120 | |||
121 | +enum lttng_kernel_syscall_entryexit { | ||
122 | + LTTNG_KERNEL_SYSCALL_ENTRYEXIT = 0, | ||
123 | + LTTNG_KERNEL_SYSCALL_ENTRY = 1, /* Not implemented. */ | ||
124 | + LTTNG_KERNEL_SYSCALL_EXIT = 2, /* Not implemented. */ | ||
125 | +}; | ||
126 | + | ||
127 | +enum lttng_kernel_syscall_abi { | ||
128 | + LTTNG_KERNEL_SYSCALL_ABI_ALL = 0, | ||
129 | + LTTNG_KERNEL_SYSCALL_ABI_NATIVE = 1, /* Not implemented. */ | ||
130 | + LTTNG_KERNEL_SYSCALL_ABI_COMPAT = 2, /* Not implemented. */ | ||
131 | +}; | ||
132 | + | ||
133 | +enum lttng_kernel_syscall_match { | ||
134 | + LTTNG_SYSCALL_MATCH_NAME = 0, | ||
135 | + LTTNG_SYSCALL_MATCH_NR = 1, /* Not implemented. */ | ||
136 | +}; | ||
137 | + | ||
138 | +struct lttng_kernel_syscall { | ||
139 | + uint8_t entryexit; /* enum lttng_kernel_syscall_entryexit */ | ||
140 | + uint8_t abi; /* enum lttng_kernel_syscall_abi */ | ||
141 | + uint8_t match; /* enum lttng_kernel_syscall_match */ | ||
142 | + uint8_t padding; | ||
143 | + uint32_t nr; /* For LTTNG_SYSCALL_MATCH_NR */ | ||
144 | +} __attribute__((packed)); | ||
145 | + | ||
146 | /* | ||
147 | * For syscall tracing, name = "*" means "enable all". | ||
148 | */ | ||
149 | @@ -106,6 +131,7 @@ struct lttng_kernel_event { | ||
150 | struct lttng_kernel_kprobe kprobe; | ||
151 | struct lttng_kernel_function_tracer ftrace; | ||
152 | struct lttng_kernel_uprobe uprobe; | ||
153 | + struct lttng_kernel_syscall syscall; | ||
154 | char padding[LTTNG_KERNEL_EVENT_PADDING2]; | ||
155 | } u; | ||
156 | } __attribute__((packed)); | ||
157 | diff --git a/lttng-events.c b/lttng-events.c | ||
158 | index d719294..4c0b04a 100644 | ||
159 | --- a/lttng-events.c | ||
160 | +++ b/lttng-events.c | ||
161 | @@ -201,6 +201,10 @@ void lttng_session_destroy(struct lttng_session *session) | ||
162 | WARN_ON(ret); | ||
163 | } | ||
164 | synchronize_trace(); /* Wait for in-flight events to complete */ | ||
165 | + list_for_each_entry(chan, &session->chan, list) { | ||
166 | + ret = lttng_syscalls_destroy(chan); | ||
167 | + WARN_ON(ret); | ||
168 | + } | ||
169 | list_for_each_entry_safe(enabler, tmpenabler, | ||
170 | &session->enablers_head, node) | ||
171 | lttng_enabler_destroy(enabler); | ||
172 | @@ -740,6 +744,28 @@ struct lttng_event *_lttng_event_create(struct lttng_channel *chan, | ||
173 | event->enabled = 0; | ||
174 | event->registered = 0; | ||
175 | event->desc = event_desc; | ||
176 | + switch (event_param->u.syscall.entryexit) { | ||
177 | + case LTTNG_KERNEL_SYSCALL_ENTRYEXIT: | ||
178 | + ret = -EINVAL; | ||
179 | + goto register_error; | ||
180 | + case LTTNG_KERNEL_SYSCALL_ENTRY: | ||
181 | + event->u.syscall.entryexit = LTTNG_SYSCALL_ENTRY; | ||
182 | + break; | ||
183 | + case LTTNG_KERNEL_SYSCALL_EXIT: | ||
184 | + event->u.syscall.entryexit = LTTNG_SYSCALL_EXIT; | ||
185 | + break; | ||
186 | + } | ||
187 | + switch (event_param->u.syscall.abi) { | ||
188 | + case LTTNG_KERNEL_SYSCALL_ABI_ALL: | ||
189 | + ret = -EINVAL; | ||
190 | + goto register_error; | ||
191 | + case LTTNG_KERNEL_SYSCALL_ABI_NATIVE: | ||
192 | + event->u.syscall.abi = LTTNG_SYSCALL_ABI_NATIVE; | ||
193 | + break; | ||
194 | + case LTTNG_KERNEL_SYSCALL_ABI_COMPAT: | ||
195 | + event->u.syscall.abi = LTTNG_SYSCALL_ABI_COMPAT; | ||
196 | + break; | ||
197 | + } | ||
198 | if (!event->desc) { | ||
199 | ret = -EINVAL; | ||
200 | goto register_error; | ||
201 | @@ -826,8 +852,7 @@ void register_event(struct lttng_event *event) | ||
202 | event); | ||
203 | break; | ||
204 | case LTTNG_KERNEL_SYSCALL: | ||
205 | - ret = lttng_syscall_filter_enable(event->chan, | ||
206 | - desc->name); | ||
207 | + ret = lttng_syscall_filter_enable(event->chan, event); | ||
208 | break; | ||
209 | case LTTNG_KERNEL_KPROBE: | ||
210 | case LTTNG_KERNEL_UPROBE: | ||
211 | @@ -870,8 +895,7 @@ int _lttng_event_unregister(struct lttng_event *event) | ||
212 | ret = 0; | ||
213 | break; | ||
214 | case LTTNG_KERNEL_SYSCALL: | ||
215 | - ret = lttng_syscall_filter_disable(event->chan, | ||
216 | - desc->name); | ||
217 | + ret = lttng_syscall_filter_disable(event->chan, event); | ||
218 | break; | ||
219 | case LTTNG_KERNEL_NOOP: | ||
220 | ret = 0; | ||
221 | @@ -1203,39 +1227,87 @@ int lttng_desc_match_enabler(const struct lttng_event_desc *desc, | ||
222 | struct lttng_enabler *enabler) | ||
223 | { | ||
224 | const char *desc_name, *enabler_name; | ||
225 | + bool compat = false, entry = false; | ||
226 | |||
227 | enabler_name = enabler->event_param.name; | ||
228 | switch (enabler->event_param.instrumentation) { | ||
229 | case LTTNG_KERNEL_TRACEPOINT: | ||
230 | desc_name = desc->name; | ||
231 | + switch (enabler->type) { | ||
232 | + case LTTNG_ENABLER_STAR_GLOB: | ||
233 | + return lttng_match_enabler_star_glob(desc_name, enabler_name); | ||
234 | + case LTTNG_ENABLER_NAME: | ||
235 | + return lttng_match_enabler_name(desc_name, enabler_name); | ||
236 | + default: | ||
237 | + return -EINVAL; | ||
238 | + } | ||
239 | break; | ||
240 | case LTTNG_KERNEL_SYSCALL: | ||
241 | desc_name = desc->name; | ||
242 | - if (!strncmp(desc_name, "compat_", strlen("compat_"))) | ||
243 | + if (!strncmp(desc_name, "compat_", strlen("compat_"))) { | ||
244 | desc_name += strlen("compat_"); | ||
245 | + compat = true; | ||
246 | + } | ||
247 | if (!strncmp(desc_name, "syscall_exit_", | ||
248 | strlen("syscall_exit_"))) { | ||
249 | desc_name += strlen("syscall_exit_"); | ||
250 | } else if (!strncmp(desc_name, "syscall_entry_", | ||
251 | strlen("syscall_entry_"))) { | ||
252 | desc_name += strlen("syscall_entry_"); | ||
253 | + entry = true; | ||
254 | } else { | ||
255 | WARN_ON_ONCE(1); | ||
256 | return -EINVAL; | ||
257 | } | ||
258 | + switch (enabler->event_param.u.syscall.entryexit) { | ||
259 | + case LTTNG_KERNEL_SYSCALL_ENTRYEXIT: | ||
260 | + break; | ||
261 | + case LTTNG_KERNEL_SYSCALL_ENTRY: | ||
262 | + if (!entry) | ||
263 | + return 0; | ||
264 | + break; | ||
265 | + case LTTNG_KERNEL_SYSCALL_EXIT: | ||
266 | + if (entry) | ||
267 | + return 0; | ||
268 | + break; | ||
269 | + default: | ||
270 | + return -EINVAL; | ||
271 | + } | ||
272 | + switch (enabler->event_param.u.syscall.abi) { | ||
273 | + case LTTNG_KERNEL_SYSCALL_ABI_ALL: | ||
274 | + break; | ||
275 | + case LTTNG_KERNEL_SYSCALL_ABI_NATIVE: | ||
276 | + if (compat) | ||
277 | + return 0; | ||
278 | + break; | ||
279 | + case LTTNG_KERNEL_SYSCALL_ABI_COMPAT: | ||
280 | + if (!compat) | ||
281 | + return 0; | ||
282 | + break; | ||
283 | + default: | ||
284 | + return -EINVAL; | ||
285 | + } | ||
286 | + switch (enabler->event_param.u.syscall.match) { | ||
287 | + case LTTNG_SYSCALL_MATCH_NAME: | ||
288 | + switch (enabler->type) { | ||
289 | + case LTTNG_ENABLER_STAR_GLOB: | ||
290 | + return lttng_match_enabler_star_glob(desc_name, enabler_name); | ||
291 | + case LTTNG_ENABLER_NAME: | ||
292 | + return lttng_match_enabler_name(desc_name, enabler_name); | ||
293 | + default: | ||
294 | + return -EINVAL; | ||
295 | + } | ||
296 | + break; | ||
297 | + case LTTNG_SYSCALL_MATCH_NR: | ||
298 | + return -EINVAL; /* Not implemented. */ | ||
299 | + default: | ||
300 | + return -EINVAL; | ||
301 | + } | ||
302 | break; | ||
303 | default: | ||
304 | WARN_ON_ONCE(1); | ||
305 | return -EINVAL; | ||
306 | } | ||
307 | - switch (enabler->type) { | ||
308 | - case LTTNG_ENABLER_STAR_GLOB: | ||
309 | - return lttng_match_enabler_star_glob(desc_name, enabler_name); | ||
310 | - case LTTNG_ENABLER_NAME: | ||
311 | - return lttng_match_enabler_name(desc_name, enabler_name); | ||
312 | - default: | ||
313 | - return -EINVAL; | ||
314 | - } | ||
315 | } | ||
316 | |||
317 | static | ||
318 | @@ -1361,9 +1433,21 @@ void lttng_create_event_if_missing(struct lttng_enabler *enabler) | ||
319 | static | ||
320 | int lttng_enabler_ref_events(struct lttng_enabler *enabler) | ||
321 | { | ||
322 | - struct lttng_session *session = enabler->chan->session; | ||
323 | + struct lttng_channel *chan = enabler->chan; | ||
324 | + struct lttng_session *session = chan->session; | ||
325 | struct lttng_event *event; | ||
326 | |||
327 | + if (enabler->event_param.instrumentation == LTTNG_KERNEL_SYSCALL && | ||
328 | + enabler->event_param.u.syscall.entryexit == LTTNG_KERNEL_SYSCALL_ENTRYEXIT && | ||
329 | + enabler->event_param.u.syscall.abi == LTTNG_KERNEL_SYSCALL_ABI_ALL && | ||
330 | + enabler->event_param.u.syscall.match == LTTNG_SYSCALL_MATCH_NAME && | ||
331 | + !strcmp(enabler->event_param.name, "*")) { | ||
332 | + if (enabler->enabled) | ||
333 | + WRITE_ONCE(chan->syscall_all, 1); | ||
334 | + else | ||
335 | + WRITE_ONCE(chan->syscall_all, 0); | ||
336 | + } | ||
337 | + | ||
338 | /* First ensure that probe events are created for this enabler. */ | ||
339 | lttng_create_event_if_missing(enabler); | ||
340 | |||
341 | diff --git a/lttng-events.h b/lttng-events.h | ||
342 | index a36a312..d4d9976 100644 | ||
343 | --- a/lttng-events.h | ||
344 | +++ b/lttng-events.h | ||
345 | @@ -292,6 +292,16 @@ struct lttng_uprobe_handler { | ||
346 | struct list_head node; | ||
347 | }; | ||
348 | |||
349 | +enum lttng_syscall_entryexit { | ||
350 | + LTTNG_SYSCALL_ENTRY, | ||
351 | + LTTNG_SYSCALL_EXIT, | ||
352 | +}; | ||
353 | + | ||
354 | +enum lttng_syscall_abi { | ||
355 | + LTTNG_SYSCALL_ABI_NATIVE, | ||
356 | + LTTNG_SYSCALL_ABI_COMPAT, | ||
357 | +}; | ||
358 | + | ||
359 | /* | ||
360 | * lttng_event structure is referred to by the tracing fast path. It must be | ||
361 | * kept small. | ||
362 | @@ -318,6 +328,11 @@ struct lttng_event { | ||
363 | struct inode *inode; | ||
364 | struct list_head head; | ||
365 | } uprobe; | ||
366 | + struct { | ||
367 | + char *syscall_name; | ||
368 | + enum lttng_syscall_entryexit entryexit; | ||
369 | + enum lttng_syscall_abi abi; | ||
370 | + } syscall; | ||
371 | } u; | ||
372 | struct list_head list; /* Event list in session */ | ||
373 | unsigned int metadata_dumped:1; | ||
374 | @@ -457,10 +472,10 @@ struct lttng_channel { | ||
375 | struct lttng_syscall_filter *sc_filter; | ||
376 | int header_type; /* 0: unset, 1: compact, 2: large */ | ||
377 | enum channel_type channel_type; | ||
378 | + int syscall_all; | ||
379 | unsigned int metadata_dumped:1, | ||
380 | sys_enter_registered:1, | ||
381 | sys_exit_registered:1, | ||
382 | - syscall_all:1, | ||
383 | tstate:1; /* Transient enable state */ | ||
384 | }; | ||
385 | |||
386 | @@ -653,10 +668,11 @@ void lttng_clock_unref(void); | ||
387 | #if defined(CONFIG_HAVE_SYSCALL_TRACEPOINTS) | ||
388 | int lttng_syscalls_register(struct lttng_channel *chan, void *filter); | ||
389 | int lttng_syscalls_unregister(struct lttng_channel *chan); | ||
390 | +int lttng_syscalls_destroy(struct lttng_channel *chan); | ||
391 | int lttng_syscall_filter_enable(struct lttng_channel *chan, | ||
392 | - const char *name); | ||
393 | + struct lttng_event *event); | ||
394 | int lttng_syscall_filter_disable(struct lttng_channel *chan, | ||
395 | - const char *name); | ||
396 | + struct lttng_event *event); | ||
397 | long lttng_channel_syscall_mask(struct lttng_channel *channel, | ||
398 | struct lttng_kernel_syscall_mask __user *usyscall_mask); | ||
399 | #else | ||
400 | @@ -670,14 +686,19 @@ static inline int lttng_syscalls_unregister(struct lttng_channel *chan) | ||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | +static inline int lttng_syscalls_destroy(struct lttng_channel *chan) | ||
405 | +{ | ||
406 | + return 0; | ||
407 | +} | ||
408 | + | ||
409 | static inline int lttng_syscall_filter_enable(struct lttng_channel *chan, | ||
410 | - const char *name) | ||
411 | + struct lttng_event *event); | ||
412 | { | ||
413 | return -ENOSYS; | ||
414 | } | ||
415 | |||
416 | static inline int lttng_syscall_filter_disable(struct lttng_channel *chan, | ||
417 | - const char *name) | ||
418 | + struct lttng_event *event); | ||
419 | { | ||
420 | return -ENOSYS; | ||
421 | } | ||
422 | diff --git a/lttng-syscalls.c b/lttng-syscalls.c | ||
423 | index 97f1ba9..26cead6 100644 | ||
424 | --- a/lttng-syscalls.c | ||
425 | +++ b/lttng-syscalls.c | ||
426 | @@ -367,8 +367,10 @@ const struct trace_syscall_entry compat_sc_exit_table[] = { | ||
427 | #undef CREATE_SYSCALL_TABLE | ||
428 | |||
429 | struct lttng_syscall_filter { | ||
430 | - DECLARE_BITMAP(sc, NR_syscalls); | ||
431 | - DECLARE_BITMAP(sc_compat, NR_compat_syscalls); | ||
432 | + DECLARE_BITMAP(sc_entry, NR_syscalls); | ||
433 | + DECLARE_BITMAP(sc_exit, NR_syscalls); | ||
434 | + DECLARE_BITMAP(sc_compat_entry, NR_compat_syscalls); | ||
435 | + DECLARE_BITMAP(sc_compat_exit, NR_compat_syscalls); | ||
436 | }; | ||
437 | |||
438 | static void syscall_entry_unknown(struct lttng_event *event, | ||
439 | @@ -391,29 +393,23 @@ void syscall_entry_probe(void *__data, struct pt_regs *regs, long id) | ||
440 | size_t table_len; | ||
441 | |||
442 | if (unlikely(in_compat_syscall())) { | ||
443 | - struct lttng_syscall_filter *filter; | ||
444 | - | ||
445 | - filter = lttng_rcu_dereference(chan->sc_filter); | ||
446 | - if (filter) { | ||
447 | - if (id < 0 || id >= NR_compat_syscalls | ||
448 | - || !test_bit(id, filter->sc_compat)) { | ||
449 | - /* System call filtered out. */ | ||
450 | - return; | ||
451 | - } | ||
452 | + struct lttng_syscall_filter *filter = chan->sc_filter; | ||
453 | + | ||
454 | + if (id < 0 || id >= NR_compat_syscalls | ||
455 | + || (!READ_ONCE(chan->syscall_all) && !test_bit(id, filter->sc_compat_entry))) { | ||
456 | + /* System call filtered out. */ | ||
457 | + return; | ||
458 | } | ||
459 | table = compat_sc_table; | ||
460 | table_len = ARRAY_SIZE(compat_sc_table); | ||
461 | unknown_event = chan->sc_compat_unknown; | ||
462 | } else { | ||
463 | - struct lttng_syscall_filter *filter; | ||
464 | - | ||
465 | - filter = lttng_rcu_dereference(chan->sc_filter); | ||
466 | - if (filter) { | ||
467 | - if (id < 0 || id >= NR_syscalls | ||
468 | - || !test_bit(id, filter->sc)) { | ||
469 | - /* System call filtered out. */ | ||
470 | - return; | ||
471 | - } | ||
472 | + struct lttng_syscall_filter *filter = chan->sc_filter; | ||
473 | + | ||
474 | + if (id < 0 || id >= NR_syscalls | ||
475 | + || (!READ_ONCE(chan->syscall_all) && !test_bit(id, filter->sc_entry))) { | ||
476 | + /* System call filtered out. */ | ||
477 | + return; | ||
478 | } | ||
479 | table = sc_table; | ||
480 | table_len = ARRAY_SIZE(sc_table); | ||
481 | @@ -545,29 +541,23 @@ void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret) | ||
482 | |||
483 | id = syscall_get_nr(current, regs); | ||
484 | if (unlikely(in_compat_syscall())) { | ||
485 | - struct lttng_syscall_filter *filter; | ||
486 | - | ||
487 | - filter = lttng_rcu_dereference(chan->sc_filter); | ||
488 | - if (filter) { | ||
489 | - if (id < 0 || id >= NR_compat_syscalls | ||
490 | - || !test_bit(id, filter->sc_compat)) { | ||
491 | - /* System call filtered out. */ | ||
492 | - return; | ||
493 | - } | ||
494 | + struct lttng_syscall_filter *filter = chan->sc_filter; | ||
495 | + | ||
496 | + if (id < 0 || id >= NR_compat_syscalls | ||
497 | + || (!READ_ONCE(chan->syscall_all) && !test_bit(id, filter->sc_compat_exit))) { | ||
498 | + /* System call filtered out. */ | ||
499 | + return; | ||
500 | } | ||
501 | table = compat_sc_exit_table; | ||
502 | table_len = ARRAY_SIZE(compat_sc_exit_table); | ||
503 | unknown_event = chan->compat_sc_exit_unknown; | ||
504 | } else { | ||
505 | - struct lttng_syscall_filter *filter; | ||
506 | - | ||
507 | - filter = lttng_rcu_dereference(chan->sc_filter); | ||
508 | - if (filter) { | ||
509 | - if (id < 0 || id >= NR_syscalls | ||
510 | - || !test_bit(id, filter->sc)) { | ||
511 | - /* System call filtered out. */ | ||
512 | - return; | ||
513 | - } | ||
514 | + struct lttng_syscall_filter *filter = chan->sc_filter; | ||
515 | + | ||
516 | + if (id < 0 || id >= NR_syscalls | ||
517 | + || (!READ_ONCE(chan->syscall_all) && !test_bit(id, filter->sc_exit))) { | ||
518 | + /* System call filtered out. */ | ||
519 | + return; | ||
520 | } | ||
521 | table = sc_exit_table; | ||
522 | table_len = ARRAY_SIZE(sc_exit_table); | ||
523 | @@ -713,27 +703,23 @@ int fill_table(const struct trace_syscall_entry *table, size_t table_len, | ||
524 | memset(&ev, 0, sizeof(ev)); | ||
525 | switch (type) { | ||
526 | case SC_TYPE_ENTRY: | ||
527 | - strncpy(ev.name, SYSCALL_ENTRY_STR, | ||
528 | - LTTNG_KERNEL_SYM_NAME_LEN); | ||
529 | + ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRY; | ||
530 | + ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE; | ||
531 | break; | ||
532 | case SC_TYPE_EXIT: | ||
533 | - strncpy(ev.name, SYSCALL_EXIT_STR, | ||
534 | - LTTNG_KERNEL_SYM_NAME_LEN); | ||
535 | + ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_EXIT; | ||
536 | + ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE; | ||
537 | break; | ||
538 | case SC_TYPE_COMPAT_ENTRY: | ||
539 | - strncpy(ev.name, COMPAT_SYSCALL_ENTRY_STR, | ||
540 | - LTTNG_KERNEL_SYM_NAME_LEN); | ||
541 | + ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRY; | ||
542 | + ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT; | ||
543 | break; | ||
544 | case SC_TYPE_COMPAT_EXIT: | ||
545 | - strncpy(ev.name, COMPAT_SYSCALL_EXIT_STR, | ||
546 | - LTTNG_KERNEL_SYM_NAME_LEN); | ||
547 | - break; | ||
548 | - default: | ||
549 | - BUG_ON(1); | ||
550 | + ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_EXIT; | ||
551 | + ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT; | ||
552 | break; | ||
553 | } | ||
554 | - strncat(ev.name, desc->name, | ||
555 | - LTTNG_KERNEL_SYM_NAME_LEN - strlen(ev.name) - 1); | ||
556 | + strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN); | ||
557 | ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; | ||
558 | ev.instrumentation = LTTNG_KERNEL_SYSCALL; | ||
559 | chan_table[i] = _lttng_event_create(chan, &ev, filter, | ||
560 | @@ -803,6 +789,8 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) | ||
561 | strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN); | ||
562 | ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; | ||
563 | ev.instrumentation = LTTNG_KERNEL_SYSCALL; | ||
564 | + ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRY; | ||
565 | + ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE; | ||
566 | chan->sc_unknown = _lttng_event_create(chan, &ev, filter, | ||
567 | desc, | ||
568 | ev.instrumentation); | ||
569 | @@ -820,6 +808,8 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) | ||
570 | strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN); | ||
571 | ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; | ||
572 | ev.instrumentation = LTTNG_KERNEL_SYSCALL; | ||
573 | + ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRY; | ||
574 | + ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT; | ||
575 | chan->sc_compat_unknown = _lttng_event_create(chan, &ev, filter, | ||
576 | desc, | ||
577 | ev.instrumentation); | ||
578 | @@ -837,6 +827,8 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) | ||
579 | strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN); | ||
580 | ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; | ||
581 | ev.instrumentation = LTTNG_KERNEL_SYSCALL; | ||
582 | + ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_EXIT; | ||
583 | + ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT; | ||
584 | chan->compat_sc_exit_unknown = _lttng_event_create(chan, &ev, | ||
585 | filter, desc, | ||
586 | ev.instrumentation); | ||
587 | @@ -854,6 +846,8 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) | ||
588 | strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN); | ||
589 | ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; | ||
590 | ev.instrumentation = LTTNG_KERNEL_SYSCALL; | ||
591 | + ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_EXIT; | ||
592 | + ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE; | ||
593 | chan->sc_exit_unknown = _lttng_event_create(chan, &ev, filter, | ||
594 | desc, ev.instrumentation); | ||
595 | WARN_ON_ONCE(!chan->sc_exit_unknown); | ||
596 | @@ -883,6 +877,14 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) | ||
597 | if (ret) | ||
598 | return ret; | ||
599 | #endif | ||
600 | + | ||
601 | + if (!chan->sc_filter) { | ||
602 | + chan->sc_filter = kzalloc(sizeof(struct lttng_syscall_filter), | ||
603 | + GFP_KERNEL); | ||
604 | + if (!chan->sc_filter) | ||
605 | + return -ENOMEM; | ||
606 | + } | ||
607 | + | ||
608 | if (!chan->sys_enter_registered) { | ||
609 | ret = lttng_wrapper_tracepoint_probe_register("sys_enter", | ||
610 | (void *) syscall_entry_probe, chan); | ||
611 | @@ -930,7 +932,11 @@ int lttng_syscalls_unregister(struct lttng_channel *chan) | ||
612 | return ret; | ||
613 | chan->sys_exit_registered = 0; | ||
614 | } | ||
615 | - /* lttng_event destroy will be performed by lttng_session_destroy() */ | ||
616 | + return 0; | ||
617 | +} | ||
618 | + | ||
619 | +int lttng_syscalls_destroy(struct lttng_channel *chan) | ||
620 | +{ | ||
621 | kfree(chan->sc_table); | ||
622 | kfree(chan->sc_exit_table); | ||
623 | #ifdef CONFIG_COMPAT | ||
624 | @@ -993,136 +999,150 @@ uint32_t get_sc_tables_len(void) | ||
625 | return ARRAY_SIZE(sc_table) + ARRAY_SIZE(compat_sc_table); | ||
626 | } | ||
627 | |||
628 | -int lttng_syscall_filter_enable(struct lttng_channel *chan, | ||
629 | - const char *name) | ||
630 | +static | ||
631 | +const char *get_syscall_name(struct lttng_event *event) | ||
632 | { | ||
633 | - int syscall_nr, compat_syscall_nr, ret; | ||
634 | - struct lttng_syscall_filter *filter; | ||
635 | + size_t prefix_len = 0; | ||
636 | |||
637 | - WARN_ON_ONCE(!chan->sc_table); | ||
638 | + WARN_ON_ONCE(event->instrumentation != LTTNG_KERNEL_SYSCALL); | ||
639 | |||
640 | - if (!name) { | ||
641 | - /* Enable all system calls by removing filter */ | ||
642 | - if (chan->sc_filter) { | ||
643 | - filter = chan->sc_filter; | ||
644 | - rcu_assign_pointer(chan->sc_filter, NULL); | ||
645 | - synchronize_trace(); | ||
646 | - kfree(filter); | ||
647 | + switch (event->u.syscall.entryexit) { | ||
648 | + case LTTNG_SYSCALL_ENTRY: | ||
649 | + switch (event->u.syscall.abi) { | ||
650 | + case LTTNG_SYSCALL_ABI_NATIVE: | ||
651 | + prefix_len = strlen(SYSCALL_ENTRY_STR); | ||
652 | + break; | ||
653 | + case LTTNG_SYSCALL_ABI_COMPAT: | ||
654 | + prefix_len = strlen(COMPAT_SYSCALL_ENTRY_STR); | ||
655 | + break; | ||
656 | } | ||
657 | - chan->syscall_all = 1; | ||
658 | - return 0; | ||
659 | - } | ||
660 | - | ||
661 | - if (!chan->sc_filter) { | ||
662 | - if (chan->syscall_all) { | ||
663 | - /* | ||
664 | - * All syscalls are already enabled. | ||
665 | - */ | ||
666 | - return -EEXIST; | ||
667 | + break; | ||
668 | + case LTTNG_SYSCALL_EXIT: | ||
669 | + switch (event->u.syscall.abi) { | ||
670 | + case LTTNG_SYSCALL_ABI_NATIVE: | ||
671 | + prefix_len = strlen(SYSCALL_EXIT_STR); | ||
672 | + break; | ||
673 | + case LTTNG_SYSCALL_ABI_COMPAT: | ||
674 | + prefix_len = strlen(COMPAT_SYSCALL_EXIT_STR); | ||
675 | + break; | ||
676 | } | ||
677 | - filter = kzalloc(sizeof(struct lttng_syscall_filter), | ||
678 | - GFP_KERNEL); | ||
679 | - if (!filter) | ||
680 | - return -ENOMEM; | ||
681 | - } else { | ||
682 | - filter = chan->sc_filter; | ||
683 | + break; | ||
684 | } | ||
685 | - syscall_nr = get_syscall_nr(name); | ||
686 | - compat_syscall_nr = get_compat_syscall_nr(name); | ||
687 | - if (syscall_nr < 0 && compat_syscall_nr < 0) { | ||
688 | - ret = -ENOENT; | ||
689 | - goto error; | ||
690 | + WARN_ON_ONCE(prefix_len == 0); | ||
691 | + return event->desc->name + prefix_len; | ||
692 | +} | ||
693 | + | ||
694 | +int lttng_syscall_filter_enable(struct lttng_channel *chan, | ||
695 | + struct lttng_event *event) | ||
696 | +{ | ||
697 | + struct lttng_syscall_filter *filter = chan->sc_filter; | ||
698 | + const char *syscall_name; | ||
699 | + unsigned long *bitmap; | ||
700 | + int syscall_nr; | ||
701 | + | ||
702 | + WARN_ON_ONCE(!chan->sc_table); | ||
703 | + | ||
704 | + syscall_name = get_syscall_name(event); | ||
705 | + | ||
706 | + switch (event->u.syscall.abi) { | ||
707 | + case LTTNG_SYSCALL_ABI_NATIVE: | ||
708 | + syscall_nr = get_syscall_nr(syscall_name); | ||
709 | + break; | ||
710 | + case LTTNG_SYSCALL_ABI_COMPAT: | ||
711 | + syscall_nr = get_compat_syscall_nr(syscall_name); | ||
712 | + break; | ||
713 | + default: | ||
714 | + return -EINVAL; | ||
715 | } | ||
716 | - if (syscall_nr >= 0) { | ||
717 | - if (test_bit(syscall_nr, filter->sc)) { | ||
718 | - ret = -EEXIST; | ||
719 | - goto error; | ||
720 | + if (syscall_nr < 0) | ||
721 | + return -ENOENT; | ||
722 | + | ||
723 | + | ||
724 | + switch (event->u.syscall.entryexit) { | ||
725 | + case LTTNG_SYSCALL_ENTRY: | ||
726 | + switch (event->u.syscall.abi) { | ||
727 | + case LTTNG_SYSCALL_ABI_NATIVE: | ||
728 | + bitmap = filter->sc_entry; | ||
729 | + break; | ||
730 | + case LTTNG_SYSCALL_ABI_COMPAT: | ||
731 | + bitmap = filter->sc_compat_entry; | ||
732 | + break; | ||
733 | } | ||
734 | - bitmap_set(filter->sc, syscall_nr, 1); | ||
735 | - } | ||
736 | - if (compat_syscall_nr >= 0) { | ||
737 | - if (test_bit(compat_syscall_nr, filter->sc_compat)) { | ||
738 | - ret = -EEXIST; | ||
739 | - goto error; | ||
740 | + break; | ||
741 | + case LTTNG_SYSCALL_EXIT: | ||
742 | + switch (event->u.syscall.abi) { | ||
743 | + case LTTNG_SYSCALL_ABI_NATIVE: | ||
744 | + bitmap = filter->sc_exit; | ||
745 | + break; | ||
746 | + case LTTNG_SYSCALL_ABI_COMPAT: | ||
747 | + bitmap = filter->sc_compat_exit; | ||
748 | + break; | ||
749 | } | ||
750 | - bitmap_set(filter->sc_compat, compat_syscall_nr, 1); | ||
751 | + break; | ||
752 | + default: | ||
753 | + return -EINVAL; | ||
754 | } | ||
755 | - if (!chan->sc_filter) | ||
756 | - rcu_assign_pointer(chan->sc_filter, filter); | ||
757 | + if (test_bit(syscall_nr, bitmap)) | ||
758 | + return -EEXIST; | ||
759 | + bitmap_set(bitmap, syscall_nr, 1); | ||
760 | return 0; | ||
761 | - | ||
762 | -error: | ||
763 | - if (!chan->sc_filter) | ||
764 | - kfree(filter); | ||
765 | - return ret; | ||
766 | } | ||
767 | |||
768 | int lttng_syscall_filter_disable(struct lttng_channel *chan, | ||
769 | - const char *name) | ||
770 | + struct lttng_event *event) | ||
771 | { | ||
772 | - int syscall_nr, compat_syscall_nr, ret; | ||
773 | - struct lttng_syscall_filter *filter; | ||
774 | + struct lttng_syscall_filter *filter = chan->sc_filter; | ||
775 | + const char *syscall_name; | ||
776 | + unsigned long *bitmap; | ||
777 | + int syscall_nr; | ||
778 | |||
779 | WARN_ON_ONCE(!chan->sc_table); | ||
780 | |||
781 | - if (!chan->sc_filter) { | ||
782 | - if (!chan->syscall_all) | ||
783 | - return -EEXIST; | ||
784 | - filter = kzalloc(sizeof(struct lttng_syscall_filter), | ||
785 | - GFP_KERNEL); | ||
786 | - if (!filter) | ||
787 | - return -ENOMEM; | ||
788 | - /* Trace all system calls, then apply disable. */ | ||
789 | - bitmap_set(filter->sc, 0, NR_syscalls); | ||
790 | - bitmap_set(filter->sc_compat, 0, NR_compat_syscalls); | ||
791 | - } else { | ||
792 | - filter = chan->sc_filter; | ||
793 | + syscall_name = get_syscall_name(event); | ||
794 | + | ||
795 | + switch (event->u.syscall.abi) { | ||
796 | + case LTTNG_SYSCALL_ABI_NATIVE: | ||
797 | + syscall_nr = get_syscall_nr(syscall_name); | ||
798 | + break; | ||
799 | + case LTTNG_SYSCALL_ABI_COMPAT: | ||
800 | + syscall_nr = get_compat_syscall_nr(syscall_name); | ||
801 | + break; | ||
802 | + default: | ||
803 | + return -EINVAL; | ||
804 | } | ||
805 | + if (syscall_nr < 0) | ||
806 | + return -ENOENT; | ||
807 | |||
808 | - if (!name) { | ||
809 | - /* Fail if all syscalls are already disabled. */ | ||
810 | - if (bitmap_empty(filter->sc, NR_syscalls) | ||
811 | - && bitmap_empty(filter->sc_compat, | ||
812 | - NR_compat_syscalls)) { | ||
813 | - ret = -EEXIST; | ||
814 | - goto error; | ||
815 | - } | ||
816 | |||
817 | - /* Disable all system calls */ | ||
818 | - bitmap_clear(filter->sc, 0, NR_syscalls); | ||
819 | - bitmap_clear(filter->sc_compat, 0, NR_compat_syscalls); | ||
820 | - goto apply_filter; | ||
821 | - } | ||
822 | - syscall_nr = get_syscall_nr(name); | ||
823 | - compat_syscall_nr = get_compat_syscall_nr(name); | ||
824 | - if (syscall_nr < 0 && compat_syscall_nr < 0) { | ||
825 | - ret = -ENOENT; | ||
826 | - goto error; | ||
827 | - } | ||
828 | - if (syscall_nr >= 0) { | ||
829 | - if (!test_bit(syscall_nr, filter->sc)) { | ||
830 | - ret = -EEXIST; | ||
831 | - goto error; | ||
832 | + switch (event->u.syscall.entryexit) { | ||
833 | + case LTTNG_SYSCALL_ENTRY: | ||
834 | + switch (event->u.syscall.abi) { | ||
835 | + case LTTNG_SYSCALL_ABI_NATIVE: | ||
836 | + bitmap = filter->sc_entry; | ||
837 | + break; | ||
838 | + case LTTNG_SYSCALL_ABI_COMPAT: | ||
839 | + bitmap = filter->sc_compat_entry; | ||
840 | + break; | ||
841 | } | ||
842 | - bitmap_clear(filter->sc, syscall_nr, 1); | ||
843 | - } | ||
844 | - if (compat_syscall_nr >= 0) { | ||
845 | - if (!test_bit(compat_syscall_nr, filter->sc_compat)) { | ||
846 | - ret = -EEXIST; | ||
847 | - goto error; | ||
848 | + break; | ||
849 | + case LTTNG_SYSCALL_EXIT: | ||
850 | + switch (event->u.syscall.abi) { | ||
851 | + case LTTNG_SYSCALL_ABI_NATIVE: | ||
852 | + bitmap = filter->sc_exit; | ||
853 | + break; | ||
854 | + case LTTNG_SYSCALL_ABI_COMPAT: | ||
855 | + bitmap = filter->sc_compat_exit; | ||
856 | + break; | ||
857 | } | ||
858 | - bitmap_clear(filter->sc_compat, compat_syscall_nr, 1); | ||
859 | + break; | ||
860 | + default: | ||
861 | + return -EINVAL; | ||
862 | } | ||
863 | -apply_filter: | ||
864 | - if (!chan->sc_filter) | ||
865 | - rcu_assign_pointer(chan->sc_filter, filter); | ||
866 | - chan->syscall_all = 0; | ||
867 | - return 0; | ||
868 | + if (!test_bit(syscall_nr, bitmap)) | ||
869 | + return -EEXIST; | ||
870 | + bitmap_clear(bitmap, syscall_nr, 1); | ||
871 | |||
872 | -error: | ||
873 | - if (!chan->sc_filter) | ||
874 | - kfree(filter); | ||
875 | - return ret; | ||
876 | + return 0; | ||
877 | } | ||
878 | |||
879 | static | ||
880 | @@ -1236,6 +1256,9 @@ const struct file_operations lttng_syscall_list_fops = { | ||
881 | .release = seq_release, | ||
882 | }; | ||
883 | |||
884 | +/* | ||
885 | + * A syscall is enabled if it is traced for either entry or exit. | ||
886 | + */ | ||
887 | long lttng_channel_syscall_mask(struct lttng_channel *channel, | ||
888 | struct lttng_kernel_syscall_mask __user *usyscall_mask) | ||
889 | { | ||
890 | @@ -1262,8 +1285,9 @@ long lttng_channel_syscall_mask(struct lttng_channel *channel, | ||
891 | char state; | ||
892 | |||
893 | if (channel->sc_table) { | ||
894 | - if (filter) | ||
895 | - state = test_bit(bit, filter->sc); | ||
896 | + if (!READ_ONCE(channel->syscall_all) && filter) | ||
897 | + state = test_bit(bit, filter->sc_entry) | ||
898 | + || test_bit(bit, filter->sc_exit); | ||
899 | else | ||
900 | state = 1; | ||
901 | } else { | ||
902 | @@ -1275,9 +1299,11 @@ long lttng_channel_syscall_mask(struct lttng_channel *channel, | ||
903 | char state; | ||
904 | |||
905 | if (channel->compat_sc_table) { | ||
906 | - if (filter) | ||
907 | + if (!READ_ONCE(channel->syscall_all) && filter) | ||
908 | state = test_bit(bit - ARRAY_SIZE(sc_table), | ||
909 | - filter->sc_compat); | ||
910 | + filter->sc_compat_entry) | ||
911 | + || test_bit(bit - ARRAY_SIZE(sc_table), | ||
912 | + filter->sc_compat_exit); | ||
913 | else | ||
914 | state = 1; | ||
915 | } else { | ||
916 | -- | ||
917 | 2.19.1 | ||
918 | |||