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