event-rule: Normalize pattern for syscall and tracepoint
[lttng-tools.git] / src / common / event-rule / syscall.c
1 /*
2 * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8 #include <assert.h>
9 #include <common/credentials.h>
10 #include <common/error.h>
11 #include <common/macros.h>
12 #include <common/payload.h>
13 #include <common/payload-view.h>
14 #include <common/runas.h>
15 #include <common/hashtable/hashtable.h>
16 #include <common/hashtable/utils.h>
17 #include <common/string-utils/string-utils.h>
18 #include <lttng/event-rule/event-rule-internal.h>
19 #include <lttng/event-rule/syscall-internal.h>
20
21 #define IS_SYSCALL_EVENT_RULE(rule) \
22 (lttng_event_rule_get_type(rule) == LTTNG_EVENT_RULE_TYPE_SYSCALL)
23
24 static void lttng_event_rule_syscall_destroy(struct lttng_event_rule *rule)
25 {
26 struct lttng_event_rule_syscall *syscall;
27
28 if (rule == NULL) {
29 return;
30 }
31
32 syscall = container_of(rule, struct lttng_event_rule_syscall, parent);
33
34 free(syscall->pattern);
35 free(syscall->filter_expression);
36 free(syscall->internal_filter.filter);
37 free(syscall->internal_filter.bytecode);
38 free(syscall);
39 }
40
41 static bool lttng_event_rule_syscall_validate(
42 const struct lttng_event_rule *rule)
43 {
44 bool valid = false;
45 struct lttng_event_rule_syscall *syscall;
46
47 if (!rule) {
48 goto end;
49 }
50
51 syscall = container_of(rule, struct lttng_event_rule_syscall, parent);
52
53 /* Required field. */
54 if (!syscall->pattern) {
55 ERR("Invalid syscall event rule: a pattern must be set.");
56 goto end;
57 }
58
59 valid = true;
60 end:
61 return valid;
62 }
63
64 static int lttng_event_rule_syscall_serialize(
65 const struct lttng_event_rule *rule,
66 struct lttng_payload *payload)
67 {
68 int ret;
69 size_t pattern_len, filter_expression_len;
70 struct lttng_event_rule_syscall *syscall;
71 struct lttng_event_rule_syscall_comm syscall_comm;
72
73 if (!rule || !IS_SYSCALL_EVENT_RULE(rule)) {
74 ret = -1;
75 goto end;
76 }
77
78 DBG("Serializing syscall event rule");
79 syscall = container_of(rule, struct lttng_event_rule_syscall, parent);
80
81 pattern_len = strlen(syscall->pattern) + 1;
82
83 if (syscall->filter_expression != NULL) {
84 filter_expression_len = strlen(syscall->filter_expression) + 1;
85 } else {
86 filter_expression_len = 0;
87 }
88
89 syscall_comm.pattern_len = pattern_len;
90 syscall_comm.filter_expression_len = filter_expression_len;
91
92 ret = lttng_dynamic_buffer_append(
93 &payload->buffer, &syscall_comm, sizeof(syscall_comm));
94 if (ret) {
95 goto end;
96 }
97
98 ret = lttng_dynamic_buffer_append(
99 &payload->buffer, syscall->pattern, pattern_len);
100 if (ret) {
101 goto end;
102 }
103
104 ret = lttng_dynamic_buffer_append(&payload->buffer,
105 syscall->filter_expression, filter_expression_len);
106 end:
107 return ret;
108 }
109
110 static bool lttng_event_rule_syscall_is_equal(const struct lttng_event_rule *_a,
111 const struct lttng_event_rule *_b)
112 {
113 bool is_equal = false;
114 struct lttng_event_rule_syscall *a, *b;
115
116 a = container_of(_a, struct lttng_event_rule_syscall, parent);
117 b = container_of(_b, struct lttng_event_rule_syscall, parent);
118
119 if (!!a->filter_expression != !!b->filter_expression) {
120 goto end;
121 }
122
123 assert(a->pattern);
124 assert(b->pattern);
125 if (strcmp(a->pattern, b->pattern)) {
126 goto end;
127 }
128
129 if (a->filter_expression && b->filter_expression) {
130 if (strcmp(a->filter_expression, b->filter_expression)) {
131 goto end;
132 }
133 } else if (!!a->filter_expression != !!b->filter_expression) {
134 /* One is set and not the other. */
135 goto end;
136 }
137
138 is_equal = true;
139 end:
140 return is_equal;
141 }
142
143 static enum lttng_error_code lttng_event_rule_syscall_generate_filter_bytecode(
144 struct lttng_event_rule *rule,
145 const struct lttng_credentials *creds)
146 {
147 int ret;
148 enum lttng_error_code ret_code = LTTNG_OK;
149 struct lttng_event_rule_syscall *syscall;
150 enum lttng_event_rule_status status;
151 const char *filter;
152 struct lttng_bytecode *bytecode = NULL;
153
154 assert(rule);
155
156 syscall = container_of(rule, struct lttng_event_rule_syscall, parent);
157
158 /* Generate the filter bytecode. */
159 status = lttng_event_rule_syscall_get_filter(rule, &filter);
160 if (status == LTTNG_EVENT_RULE_STATUS_UNSET) {
161 filter = NULL;
162 } else if (status != LTTNG_EVENT_RULE_STATUS_OK) {
163 ret_code = LTTNG_ERR_FILTER_INVAL;
164 goto end;
165 }
166
167 if (filter && filter[0] == '\0') {
168 ret_code = LTTNG_ERR_FILTER_INVAL;
169 goto end;
170 }
171
172 if (filter == NULL) {
173 /* Nothing to do. */
174 ret = LTTNG_OK;
175 goto end;
176 }
177
178 syscall->internal_filter.filter = strdup(filter);
179 if (syscall->internal_filter.filter == NULL) {
180 ret_code = LTTNG_ERR_NOMEM;
181 goto end;
182 }
183
184 ret = run_as_generate_filter_bytecode(
185 syscall->internal_filter.filter, creds, &bytecode);
186 if (ret) {
187 ret_code = LTTNG_ERR_FILTER_INVAL;
188 }
189
190 syscall->internal_filter.bytecode = bytecode;
191 bytecode = NULL;
192
193 end:
194 free(bytecode);
195 return ret_code;
196 }
197
198 static const char *lttng_event_rule_syscall_get_internal_filter(
199 const struct lttng_event_rule *rule)
200 {
201 struct lttng_event_rule_syscall *syscall;
202
203 assert(rule);
204 syscall = container_of(rule, struct lttng_event_rule_syscall, parent);
205
206 return syscall->internal_filter.filter;
207 }
208
209 static const struct lttng_bytecode *
210 lttng_event_rule_syscall_get_internal_filter_bytecode(
211 const struct lttng_event_rule *rule)
212 {
213 struct lttng_event_rule_syscall *syscall;
214
215 assert(rule);
216 syscall = container_of(rule, struct lttng_event_rule_syscall, parent);
217
218 return syscall->internal_filter.bytecode;
219 }
220
221 static enum lttng_event_rule_generate_exclusions_status
222 lttng_event_rule_syscall_generate_exclusions(const struct lttng_event_rule *rule,
223 struct lttng_event_exclusion **exclusions)
224 {
225 /* Unsupported. */
226 *exclusions = NULL;
227 return LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE;
228 }
229
230 static unsigned long
231 lttng_event_rule_syscall_hash(
232 const struct lttng_event_rule *rule)
233 {
234 unsigned long hash;
235 struct lttng_event_rule_syscall *syscall_rule =
236 container_of(rule, typeof(*syscall_rule), parent);
237
238 hash = hash_key_ulong((void *) LTTNG_EVENT_RULE_TYPE_SYSCALL,
239 lttng_ht_seed);
240 hash ^= hash_key_str(syscall_rule->pattern, lttng_ht_seed);
241 if (syscall_rule->filter_expression) {
242 hash ^= hash_key_str(syscall_rule->filter_expression,
243 lttng_ht_seed);
244 }
245
246 return hash;
247 }
248
249 struct lttng_event_rule *lttng_event_rule_syscall_create(void)
250 {
251 struct lttng_event_rule *rule = NULL;
252 struct lttng_event_rule_syscall *syscall_rule;
253 enum lttng_event_rule_status status;
254
255 syscall_rule = zmalloc(sizeof(struct lttng_event_rule_syscall));
256 if (!syscall_rule) {
257 goto end;
258 }
259
260 rule = &syscall_rule->parent;
261 lttng_event_rule_init(
262 &syscall_rule->parent, LTTNG_EVENT_RULE_TYPE_SYSCALL);
263 syscall_rule->parent.validate = lttng_event_rule_syscall_validate;
264 syscall_rule->parent.serialize = lttng_event_rule_syscall_serialize;
265 syscall_rule->parent.equal = lttng_event_rule_syscall_is_equal;
266 syscall_rule->parent.destroy = lttng_event_rule_syscall_destroy;
267 syscall_rule->parent.generate_filter_bytecode =
268 lttng_event_rule_syscall_generate_filter_bytecode;
269 syscall_rule->parent.get_filter =
270 lttng_event_rule_syscall_get_internal_filter;
271 syscall_rule->parent.get_filter_bytecode =
272 lttng_event_rule_syscall_get_internal_filter_bytecode;
273 syscall_rule->parent.generate_exclusions =
274 lttng_event_rule_syscall_generate_exclusions;
275 syscall_rule->parent.hash = lttng_event_rule_syscall_hash;
276
277 /* Default pattern is '*'. */
278 status = lttng_event_rule_syscall_set_pattern(rule, "*");
279 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
280 lttng_event_rule_destroy(rule);
281 rule = NULL;
282 }
283
284 end:
285 return rule;
286 }
287
288 LTTNG_HIDDEN
289 ssize_t lttng_event_rule_syscall_create_from_payload(
290 struct lttng_payload_view *view,
291 struct lttng_event_rule **_event_rule)
292 {
293 ssize_t ret, offset = 0;
294 enum lttng_event_rule_status status;
295 const struct lttng_event_rule_syscall_comm *syscall_comm;
296 const char *pattern;
297 const char *filter_expression = NULL;
298 struct lttng_buffer_view current_buffer_view;
299 struct lttng_event_rule *rule = NULL;
300
301 if (!_event_rule) {
302 ret = -1;
303 goto end;
304 }
305
306 if (view->buffer.size < sizeof(*syscall_comm)) {
307 ERR("Failed to initialize from malformed event rule syscall: buffer too short to contain header");
308 ret = -1;
309 goto end;
310 }
311
312 current_buffer_view = lttng_buffer_view_from_view(
313 &view->buffer, offset, sizeof(*syscall_comm));
314 if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
315 ret = -1;
316 goto end;
317 }
318
319 syscall_comm = (typeof(syscall_comm)) current_buffer_view.data;
320 rule = lttng_event_rule_syscall_create();
321 if (!rule) {
322 ERR("Failed to create event rule syscall");
323 ret = -1;
324 goto end;
325 }
326
327 /* Skip to payload. */
328 offset += current_buffer_view.size;
329
330 /* Map the pattern. */
331 current_buffer_view = lttng_buffer_view_from_view(
332 &view->buffer, offset, syscall_comm->pattern_len);
333 if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
334 ret = -1;
335 goto end;
336 }
337
338 pattern = current_buffer_view.data;
339 if (!lttng_buffer_view_contains_string(&current_buffer_view, pattern,
340 syscall_comm->pattern_len)) {
341 ret = -1;
342 goto end;
343 }
344
345 /* Skip after the pattern. */
346 offset += syscall_comm->pattern_len;
347
348 if (!syscall_comm->filter_expression_len) {
349 goto skip_filter_expression;
350 }
351
352 /* Map the filter_expression. */
353 current_buffer_view = lttng_buffer_view_from_view(&view->buffer, offset,
354 syscall_comm->filter_expression_len);
355 if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
356 ret = -1;
357 goto end;
358 }
359
360 filter_expression = current_buffer_view.data;
361 if (!lttng_buffer_view_contains_string(&current_buffer_view,
362 filter_expression,
363 syscall_comm->filter_expression_len)) {
364 ret = -1;
365 goto end;
366 }
367
368 /* Skip after the pattern. */
369 offset += syscall_comm->filter_expression_len;
370
371 skip_filter_expression:
372
373 status = lttng_event_rule_syscall_set_pattern(rule, pattern);
374 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
375 ERR("Failed to set event rule syscall pattern");
376 ret = -1;
377 goto end;
378 }
379
380 if (filter_expression) {
381 status = lttng_event_rule_syscall_set_filter(
382 rule, filter_expression);
383 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
384 ERR("Failed to set event rule syscall pattern");
385 ret = -1;
386 goto end;
387 }
388 }
389
390 *_event_rule = rule;
391 rule = NULL;
392 ret = offset;
393 end:
394 lttng_event_rule_destroy(rule);
395 return ret;
396 }
397
398 enum lttng_event_rule_status lttng_event_rule_syscall_set_pattern(
399 struct lttng_event_rule *rule, const char *pattern)
400 {
401 char *pattern_copy = NULL;
402 struct lttng_event_rule_syscall *syscall;
403 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
404
405 if (!rule || !IS_SYSCALL_EVENT_RULE(rule) || !pattern ||
406 strlen(pattern) == 0) {
407 status = LTTNG_EVENT_RULE_STATUS_INVALID;
408 goto end;
409 }
410
411 syscall = container_of(rule, struct lttng_event_rule_syscall, parent);
412 pattern_copy = strdup(pattern);
413 if (!pattern_copy) {
414 status = LTTNG_EVENT_RULE_STATUS_ERROR;
415 goto end;
416 }
417
418 strutils_normalize_star_glob_pattern(pattern_copy);
419
420 free(syscall->pattern);
421
422 syscall->pattern = pattern_copy;
423 pattern_copy = NULL;
424 end:
425 return status;
426 }
427
428 enum lttng_event_rule_status lttng_event_rule_syscall_get_pattern(
429 const struct lttng_event_rule *rule, const char **pattern)
430 {
431 struct lttng_event_rule_syscall *syscall;
432 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
433
434 if (!rule || !IS_SYSCALL_EVENT_RULE(rule) || !pattern) {
435 status = LTTNG_EVENT_RULE_STATUS_INVALID;
436 goto end;
437 }
438
439 syscall = container_of(rule, struct lttng_event_rule_syscall, parent);
440 if (!syscall->pattern) {
441 status = LTTNG_EVENT_RULE_STATUS_UNSET;
442 goto end;
443 }
444
445 *pattern = syscall->pattern;
446 end:
447 return status;
448 }
449
450 enum lttng_event_rule_status lttng_event_rule_syscall_set_filter(
451 struct lttng_event_rule *rule, const char *expression)
452 {
453 char *expression_copy = NULL;
454 struct lttng_event_rule_syscall *syscall;
455 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
456
457 /* TODO: validate that the passed expression is valid. */
458
459 if (!rule || !IS_SYSCALL_EVENT_RULE(rule) || !expression ||
460 strlen(expression) == 0) {
461 status = LTTNG_EVENT_RULE_STATUS_INVALID;
462 goto end;
463 }
464
465 syscall = container_of(rule, struct lttng_event_rule_syscall, parent);
466 expression_copy = strdup(expression);
467 if (!expression_copy) {
468 status = LTTNG_EVENT_RULE_STATUS_ERROR;
469 goto end;
470 }
471
472 if (syscall->filter_expression) {
473 free(syscall->filter_expression);
474 }
475
476 syscall->filter_expression = expression_copy;
477 expression_copy = NULL;
478 end:
479 return status;
480 }
481
482 enum lttng_event_rule_status lttng_event_rule_syscall_get_filter(
483 const struct lttng_event_rule *rule, const char **expression)
484 {
485 struct lttng_event_rule_syscall *syscall;
486 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
487
488 if (!rule || !IS_SYSCALL_EVENT_RULE(rule) || !expression) {
489 status = LTTNG_EVENT_RULE_STATUS_INVALID;
490 goto end;
491 }
492
493 syscall = container_of(rule, struct lttng_event_rule_syscall, parent);
494 if (!syscall->filter_expression) {
495 status = LTTNG_EVENT_RULE_STATUS_UNSET;
496 goto end;
497 }
498
499 *expression = syscall->filter_expression;
500 end:
501 return status;
502 }
This page took 0.063027 seconds and 5 git commands to generate.