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