2 * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
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>
21 #define IS_SYSCALL_EVENT_RULE(rule) \
22 (lttng_event_rule_get_type(rule) == LTTNG_EVENT_RULE_TYPE_SYSCALL)
24 static void lttng_event_rule_syscall_destroy(struct lttng_event_rule
*rule
)
26 struct lttng_event_rule_syscall
*syscall
;
32 syscall
= container_of(rule
, struct lttng_event_rule_syscall
, parent
);
34 free(syscall
->pattern
);
35 free(syscall
->filter_expression
);
36 free(syscall
->internal_filter
.filter
);
37 free(syscall
->internal_filter
.bytecode
);
41 static bool lttng_event_rule_syscall_validate(
42 const struct lttng_event_rule
*rule
)
45 struct lttng_event_rule_syscall
*syscall
;
51 syscall
= container_of(rule
, struct lttng_event_rule_syscall
, parent
);
54 if (!syscall
->pattern
) {
55 ERR("Invalid syscall event rule: a pattern must be set.");
64 static int lttng_event_rule_syscall_serialize(
65 const struct lttng_event_rule
*rule
,
66 struct lttng_payload
*payload
)
69 size_t pattern_len
, filter_expression_len
;
70 struct lttng_event_rule_syscall
*syscall
;
71 struct lttng_event_rule_syscall_comm syscall_comm
;
73 if (!rule
|| !IS_SYSCALL_EVENT_RULE(rule
)) {
78 DBG("Serializing syscall event rule");
79 syscall
= container_of(rule
, struct lttng_event_rule_syscall
, parent
);
81 pattern_len
= strlen(syscall
->pattern
) + 1;
83 if (syscall
->filter_expression
!= NULL
) {
84 filter_expression_len
= strlen(syscall
->filter_expression
) + 1;
86 filter_expression_len
= 0;
89 syscall_comm
.pattern_len
= pattern_len
;
90 syscall_comm
.filter_expression_len
= filter_expression_len
;
92 ret
= lttng_dynamic_buffer_append(
93 &payload
->buffer
, &syscall_comm
, sizeof(syscall_comm
));
98 ret
= lttng_dynamic_buffer_append(
99 &payload
->buffer
, syscall
->pattern
, pattern_len
);
104 ret
= lttng_dynamic_buffer_append(&payload
->buffer
,
105 syscall
->filter_expression
, filter_expression_len
);
110 static bool lttng_event_rule_syscall_is_equal(const struct lttng_event_rule
*_a
,
111 const struct lttng_event_rule
*_b
)
113 bool is_equal
= false;
114 struct lttng_event_rule_syscall
*a
, *b
;
116 a
= container_of(_a
, struct lttng_event_rule_syscall
, parent
);
117 b
= container_of(_b
, struct lttng_event_rule_syscall
, parent
);
119 if (!!a
->filter_expression
!= !!b
->filter_expression
) {
125 if (strcmp(a
->pattern
, b
->pattern
)) {
129 if (a
->filter_expression
&& b
->filter_expression
) {
130 if (strcmp(a
->filter_expression
, b
->filter_expression
)) {
133 } else if (!!a
->filter_expression
!= !!b
->filter_expression
) {
134 /* One is set and not the other. */
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
)
148 enum lttng_error_code ret_code
= LTTNG_OK
;
149 struct lttng_event_rule_syscall
*syscall
;
150 enum lttng_event_rule_status status
;
152 struct lttng_bytecode
*bytecode
= NULL
;
156 syscall
= container_of(rule
, struct lttng_event_rule_syscall
, parent
);
158 /* Generate the filter bytecode. */
159 status
= lttng_event_rule_syscall_get_filter(rule
, &filter
);
160 if (status
== LTTNG_EVENT_RULE_STATUS_UNSET
) {
162 } else if (status
!= LTTNG_EVENT_RULE_STATUS_OK
) {
163 ret_code
= LTTNG_ERR_FILTER_INVAL
;
167 if (filter
&& filter
[0] == '\0') {
168 ret_code
= LTTNG_ERR_FILTER_INVAL
;
172 if (filter
== NULL
) {
178 syscall
->internal_filter
.filter
= strdup(filter
);
179 if (syscall
->internal_filter
.filter
== NULL
) {
180 ret_code
= LTTNG_ERR_NOMEM
;
184 ret
= run_as_generate_filter_bytecode(
185 syscall
->internal_filter
.filter
, creds
, &bytecode
);
187 ret_code
= LTTNG_ERR_FILTER_INVAL
;
190 syscall
->internal_filter
.bytecode
= bytecode
;
198 static const char *lttng_event_rule_syscall_get_internal_filter(
199 const struct lttng_event_rule
*rule
)
201 struct lttng_event_rule_syscall
*syscall
;
204 syscall
= container_of(rule
, struct lttng_event_rule_syscall
, parent
);
206 return syscall
->internal_filter
.filter
;
209 static const struct lttng_bytecode
*
210 lttng_event_rule_syscall_get_internal_filter_bytecode(
211 const struct lttng_event_rule
*rule
)
213 struct lttng_event_rule_syscall
*syscall
;
216 syscall
= container_of(rule
, struct lttng_event_rule_syscall
, parent
);
218 return syscall
->internal_filter
.bytecode
;
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
)
227 return LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE
;
231 lttng_event_rule_syscall_hash(
232 const struct lttng_event_rule
*rule
)
235 struct lttng_event_rule_syscall
*syscall_rule
=
236 container_of(rule
, typeof(*syscall_rule
), parent
);
238 hash
= hash_key_ulong((void *) LTTNG_EVENT_RULE_TYPE_SYSCALL
,
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
,
249 struct lttng_event_rule
*lttng_event_rule_syscall_create(void)
251 struct lttng_event_rule
*rule
= NULL
;
252 struct lttng_event_rule_syscall
*syscall_rule
;
253 enum lttng_event_rule_status status
;
255 syscall_rule
= zmalloc(sizeof(struct lttng_event_rule_syscall
));
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
;
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
);
289 ssize_t
lttng_event_rule_syscall_create_from_payload(
290 struct lttng_payload_view
*view
,
291 struct lttng_event_rule
**_event_rule
)
293 ssize_t ret
, offset
= 0;
294 enum lttng_event_rule_status status
;
295 const struct lttng_event_rule_syscall_comm
*syscall_comm
;
297 const char *filter_expression
= NULL
;
298 struct lttng_buffer_view current_buffer_view
;
299 struct lttng_event_rule
*rule
= NULL
;
306 if (view
->buffer
.size
< sizeof(*syscall_comm
)) {
307 ERR("Failed to initialize from malformed event rule syscall: buffer too short to contain header");
312 current_buffer_view
= lttng_buffer_view_from_view(
313 &view
->buffer
, offset
, sizeof(*syscall_comm
));
314 if (!lttng_buffer_view_is_valid(¤t_buffer_view
)) {
319 syscall_comm
= (typeof(syscall_comm
)) current_buffer_view
.data
;
320 rule
= lttng_event_rule_syscall_create();
322 ERR("Failed to create event rule syscall");
327 /* Skip to payload. */
328 offset
+= current_buffer_view
.size
;
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(¤t_buffer_view
)) {
338 pattern
= current_buffer_view
.data
;
339 if (!lttng_buffer_view_contains_string(¤t_buffer_view
, pattern
,
340 syscall_comm
->pattern_len
)) {
345 /* Skip after the pattern. */
346 offset
+= syscall_comm
->pattern_len
;
348 if (!syscall_comm
->filter_expression_len
) {
349 goto skip_filter_expression
;
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(¤t_buffer_view
)) {
360 filter_expression
= current_buffer_view
.data
;
361 if (!lttng_buffer_view_contains_string(¤t_buffer_view
,
363 syscall_comm
->filter_expression_len
)) {
368 /* Skip after the pattern. */
369 offset
+= syscall_comm
->filter_expression_len
;
371 skip_filter_expression
:
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");
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");
394 lttng_event_rule_destroy(rule
);
398 enum lttng_event_rule_status
lttng_event_rule_syscall_set_pattern(
399 struct lttng_event_rule
*rule
, const char *pattern
)
401 char *pattern_copy
= NULL
;
402 struct lttng_event_rule_syscall
*syscall
;
403 enum lttng_event_rule_status status
= LTTNG_EVENT_RULE_STATUS_OK
;
405 if (!rule
|| !IS_SYSCALL_EVENT_RULE(rule
) || !pattern
||
406 strlen(pattern
) == 0) {
407 status
= LTTNG_EVENT_RULE_STATUS_INVALID
;
411 syscall
= container_of(rule
, struct lttng_event_rule_syscall
, parent
);
412 pattern_copy
= strdup(pattern
);
414 status
= LTTNG_EVENT_RULE_STATUS_ERROR
;
418 strutils_normalize_star_glob_pattern(pattern_copy
);
420 free(syscall
->pattern
);
422 syscall
->pattern
= pattern_copy
;
428 enum lttng_event_rule_status
lttng_event_rule_syscall_get_pattern(
429 const struct lttng_event_rule
*rule
, const char **pattern
)
431 struct lttng_event_rule_syscall
*syscall
;
432 enum lttng_event_rule_status status
= LTTNG_EVENT_RULE_STATUS_OK
;
434 if (!rule
|| !IS_SYSCALL_EVENT_RULE(rule
) || !pattern
) {
435 status
= LTTNG_EVENT_RULE_STATUS_INVALID
;
439 syscall
= container_of(rule
, struct lttng_event_rule_syscall
, parent
);
440 if (!syscall
->pattern
) {
441 status
= LTTNG_EVENT_RULE_STATUS_UNSET
;
445 *pattern
= syscall
->pattern
;
450 enum lttng_event_rule_status
lttng_event_rule_syscall_set_filter(
451 struct lttng_event_rule
*rule
, const char *expression
)
453 char *expression_copy
= NULL
;
454 struct lttng_event_rule_syscall
*syscall
;
455 enum lttng_event_rule_status status
= LTTNG_EVENT_RULE_STATUS_OK
;
457 /* TODO: validate that the passed expression is valid. */
459 if (!rule
|| !IS_SYSCALL_EVENT_RULE(rule
) || !expression
||
460 strlen(expression
) == 0) {
461 status
= LTTNG_EVENT_RULE_STATUS_INVALID
;
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
;
472 if (syscall
->filter_expression
) {
473 free(syscall
->filter_expression
);
476 syscall
->filter_expression
= expression_copy
;
477 expression_copy
= NULL
;
482 enum lttng_event_rule_status
lttng_event_rule_syscall_get_filter(
483 const struct lttng_event_rule
*rule
, const char **expression
)
485 struct lttng_event_rule_syscall
*syscall
;
486 enum lttng_event_rule_status status
= LTTNG_EVENT_RULE_STATUS_OK
;
488 if (!rule
|| !IS_SYSCALL_EVENT_RULE(rule
) || !expression
) {
489 status
= LTTNG_EVENT_RULE_STATUS_INVALID
;
493 syscall
= container_of(rule
, struct lttng_event_rule_syscall
, parent
);
494 if (!syscall
->filter_expression
) {
495 status
= LTTNG_EVENT_RULE_STATUS_UNSET
;
499 *expression
= syscall
->filter_expression
;