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 <lttng/event-rule/event-rule-internal.h>
18 #include <lttng/event-rule/syscall-internal.h>
20 #define IS_SYSCALL_EVENT_RULE(rule) \
21 (lttng_event_rule_get_type(rule) == LTTNG_EVENT_RULE_TYPE_SYSCALL)
23 static void lttng_event_rule_syscall_destroy(struct lttng_event_rule
*rule
)
25 struct lttng_event_rule_syscall
*syscall
;
31 syscall
= container_of(rule
, struct lttng_event_rule_syscall
, parent
);
33 free(syscall
->pattern
);
34 free(syscall
->filter_expression
);
35 free(syscall
->internal_filter
.filter
);
36 free(syscall
->internal_filter
.bytecode
);
40 static bool lttng_event_rule_syscall_validate(
41 const struct lttng_event_rule
*rule
)
44 struct lttng_event_rule_syscall
*syscall
;
50 syscall
= container_of(rule
, struct lttng_event_rule_syscall
, parent
);
53 if (!syscall
->pattern
) {
54 ERR("Invalid syscall event rule: a pattern must be set.");
63 static int lttng_event_rule_syscall_serialize(
64 const struct lttng_event_rule
*rule
,
65 struct lttng_payload
*payload
)
68 size_t pattern_len
, filter_expression_len
;
69 struct lttng_event_rule_syscall
*syscall
;
70 struct lttng_event_rule_syscall_comm syscall_comm
;
72 if (!rule
|| !IS_SYSCALL_EVENT_RULE(rule
)) {
77 DBG("Serializing syscall event rule");
78 syscall
= container_of(rule
, struct lttng_event_rule_syscall
, parent
);
80 pattern_len
= strlen(syscall
->pattern
) + 1;
82 if (syscall
->filter_expression
!= NULL
) {
83 filter_expression_len
= strlen(syscall
->filter_expression
) + 1;
85 filter_expression_len
= 0;
88 syscall_comm
.pattern_len
= pattern_len
;
89 syscall_comm
.filter_expression_len
= filter_expression_len
;
91 ret
= lttng_dynamic_buffer_append(
92 &payload
->buffer
, &syscall_comm
, sizeof(syscall_comm
));
97 ret
= lttng_dynamic_buffer_append(
98 &payload
->buffer
, syscall
->pattern
, pattern_len
);
103 ret
= lttng_dynamic_buffer_append(&payload
->buffer
,
104 syscall
->filter_expression
, filter_expression_len
);
109 static bool lttng_event_rule_syscall_is_equal(const struct lttng_event_rule
*_a
,
110 const struct lttng_event_rule
*_b
)
112 bool is_equal
= false;
113 struct lttng_event_rule_syscall
*a
, *b
;
115 a
= container_of(_a
, struct lttng_event_rule_syscall
, parent
);
116 b
= container_of(_b
, struct lttng_event_rule_syscall
, parent
);
118 if (!!a
->filter_expression
!= !!b
->filter_expression
) {
124 if (strcmp(a
->pattern
, b
->pattern
)) {
128 if (a
->filter_expression
&& b
->filter_expression
) {
129 if (strcmp(a
->filter_expression
, b
->filter_expression
)) {
132 } else if (!!a
->filter_expression
!= !!b
->filter_expression
) {
133 /* One is set and not the other. */
142 static enum lttng_error_code
lttng_event_rule_syscall_generate_filter_bytecode(
143 struct lttng_event_rule
*rule
,
144 const struct lttng_credentials
*creds
)
147 enum lttng_error_code ret_code
= LTTNG_OK
;
148 struct lttng_event_rule_syscall
*syscall
;
149 enum lttng_event_rule_status status
;
151 struct lttng_bytecode
*bytecode
= NULL
;
155 syscall
= container_of(rule
, struct lttng_event_rule_syscall
, parent
);
157 /* Generate the filter bytecode. */
158 status
= lttng_event_rule_syscall_get_filter(rule
, &filter
);
159 if (status
== LTTNG_EVENT_RULE_STATUS_UNSET
) {
161 } else if (status
!= LTTNG_EVENT_RULE_STATUS_OK
) {
162 ret_code
= LTTNG_ERR_FILTER_INVAL
;
166 if (filter
&& filter
[0] == '\0') {
167 ret_code
= LTTNG_ERR_FILTER_INVAL
;
171 if (filter
== NULL
) {
177 syscall
->internal_filter
.filter
= strdup(filter
);
178 if (syscall
->internal_filter
.filter
== NULL
) {
179 ret_code
= LTTNG_ERR_NOMEM
;
183 ret
= run_as_generate_filter_bytecode(
184 syscall
->internal_filter
.filter
, creds
, &bytecode
);
186 ret_code
= LTTNG_ERR_FILTER_INVAL
;
189 syscall
->internal_filter
.bytecode
= bytecode
;
197 static const char *lttng_event_rule_syscall_get_internal_filter(
198 const struct lttng_event_rule
*rule
)
200 struct lttng_event_rule_syscall
*syscall
;
203 syscall
= container_of(rule
, struct lttng_event_rule_syscall
, parent
);
205 return syscall
->internal_filter
.filter
;
208 static const struct lttng_bytecode
*
209 lttng_event_rule_syscall_get_internal_filter_bytecode(
210 const struct lttng_event_rule
*rule
)
212 struct lttng_event_rule_syscall
*syscall
;
215 syscall
= container_of(rule
, struct lttng_event_rule_syscall
, parent
);
217 return syscall
->internal_filter
.bytecode
;
220 static enum lttng_event_rule_generate_exclusions_status
221 lttng_event_rule_syscall_generate_exclusions(const struct lttng_event_rule
*rule
,
222 struct lttng_event_exclusion
**exclusions
)
226 return LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE
;
230 lttng_event_rule_syscall_hash(
231 const struct lttng_event_rule
*rule
)
234 struct lttng_event_rule_syscall
*syscall_rule
=
235 container_of(rule
, typeof(*syscall_rule
), parent
);
237 hash
= hash_key_ulong((void *) LTTNG_EVENT_RULE_TYPE_SYSCALL
,
239 hash
^= hash_key_str(syscall_rule
->pattern
, lttng_ht_seed
);
240 if (syscall_rule
->filter_expression
) {
241 hash
^= hash_key_str(syscall_rule
->filter_expression
,
248 struct lttng_event_rule
*lttng_event_rule_syscall_create(void)
250 struct lttng_event_rule
*rule
= NULL
;
251 struct lttng_event_rule_syscall
*syscall_rule
;
252 enum lttng_event_rule_status status
;
254 syscall_rule
= zmalloc(sizeof(struct lttng_event_rule_syscall
));
259 rule
= &syscall_rule
->parent
;
260 lttng_event_rule_init(
261 &syscall_rule
->parent
, LTTNG_EVENT_RULE_TYPE_SYSCALL
);
262 syscall_rule
->parent
.validate
= lttng_event_rule_syscall_validate
;
263 syscall_rule
->parent
.serialize
= lttng_event_rule_syscall_serialize
;
264 syscall_rule
->parent
.equal
= lttng_event_rule_syscall_is_equal
;
265 syscall_rule
->parent
.destroy
= lttng_event_rule_syscall_destroy
;
266 syscall_rule
->parent
.generate_filter_bytecode
=
267 lttng_event_rule_syscall_generate_filter_bytecode
;
268 syscall_rule
->parent
.get_filter
=
269 lttng_event_rule_syscall_get_internal_filter
;
270 syscall_rule
->parent
.get_filter_bytecode
=
271 lttng_event_rule_syscall_get_internal_filter_bytecode
;
272 syscall_rule
->parent
.generate_exclusions
=
273 lttng_event_rule_syscall_generate_exclusions
;
274 syscall_rule
->parent
.hash
= lttng_event_rule_syscall_hash
;
276 /* Default pattern is '*'. */
277 status
= lttng_event_rule_syscall_set_pattern(rule
, "*");
278 if (status
!= LTTNG_EVENT_RULE_STATUS_OK
) {
279 lttng_event_rule_destroy(rule
);
288 ssize_t
lttng_event_rule_syscall_create_from_payload(
289 struct lttng_payload_view
*view
,
290 struct lttng_event_rule
**_event_rule
)
292 ssize_t ret
, offset
= 0;
293 enum lttng_event_rule_status status
;
294 const struct lttng_event_rule_syscall_comm
*syscall_comm
;
296 const char *filter_expression
= NULL
;
297 struct lttng_buffer_view current_buffer_view
;
298 struct lttng_event_rule
*rule
= NULL
;
305 if (view
->buffer
.size
< sizeof(*syscall_comm
)) {
306 ERR("Failed to initialize from malformed event rule syscall: buffer too short to contain header");
311 current_buffer_view
= lttng_buffer_view_from_view(
312 &view
->buffer
, offset
, sizeof(*syscall_comm
));
313 if (!lttng_buffer_view_is_valid(¤t_buffer_view
)) {
318 syscall_comm
= (typeof(syscall_comm
)) current_buffer_view
.data
;
319 rule
= lttng_event_rule_syscall_create();
321 ERR("Failed to create event rule syscall");
326 /* Skip to payload. */
327 offset
+= current_buffer_view
.size
;
329 /* Map the pattern. */
330 current_buffer_view
= lttng_buffer_view_from_view(
331 &view
->buffer
, offset
, syscall_comm
->pattern_len
);
332 if (!lttng_buffer_view_is_valid(¤t_buffer_view
)) {
337 pattern
= current_buffer_view
.data
;
338 if (!lttng_buffer_view_contains_string(¤t_buffer_view
, pattern
,
339 syscall_comm
->pattern_len
)) {
344 /* Skip after the pattern. */
345 offset
+= syscall_comm
->pattern_len
;
347 if (!syscall_comm
->filter_expression_len
) {
348 goto skip_filter_expression
;
351 /* Map the filter_expression. */
352 current_buffer_view
= lttng_buffer_view_from_view(&view
->buffer
, offset
,
353 syscall_comm
->filter_expression_len
);
354 if (!lttng_buffer_view_is_valid(¤t_buffer_view
)) {
359 filter_expression
= current_buffer_view
.data
;
360 if (!lttng_buffer_view_contains_string(¤t_buffer_view
,
362 syscall_comm
->filter_expression_len
)) {
367 /* Skip after the pattern. */
368 offset
+= syscall_comm
->filter_expression_len
;
370 skip_filter_expression
:
372 status
= lttng_event_rule_syscall_set_pattern(rule
, pattern
);
373 if (status
!= LTTNG_EVENT_RULE_STATUS_OK
) {
374 ERR("Failed to set event rule syscall pattern");
379 if (filter_expression
) {
380 status
= lttng_event_rule_syscall_set_filter(
381 rule
, filter_expression
);
382 if (status
!= LTTNG_EVENT_RULE_STATUS_OK
) {
383 ERR("Failed to set event rule syscall pattern");
393 lttng_event_rule_destroy(rule
);
397 enum lttng_event_rule_status
lttng_event_rule_syscall_set_pattern(
398 struct lttng_event_rule
*rule
, const char *pattern
)
400 char *pattern_copy
= NULL
;
401 struct lttng_event_rule_syscall
*syscall
;
402 enum lttng_event_rule_status status
= LTTNG_EVENT_RULE_STATUS_OK
;
404 if (!rule
|| !IS_SYSCALL_EVENT_RULE(rule
) || !pattern
||
405 strlen(pattern
) == 0) {
406 status
= LTTNG_EVENT_RULE_STATUS_INVALID
;
410 syscall
= container_of(rule
, struct lttng_event_rule_syscall
, parent
);
411 pattern_copy
= strdup(pattern
);
413 status
= LTTNG_EVENT_RULE_STATUS_ERROR
;
417 if (syscall
->pattern
) {
418 free(syscall
->pattern
);
421 syscall
->pattern
= pattern_copy
;
427 enum lttng_event_rule_status
lttng_event_rule_syscall_get_pattern(
428 const struct lttng_event_rule
*rule
, const char **pattern
)
430 struct lttng_event_rule_syscall
*syscall
;
431 enum lttng_event_rule_status status
= LTTNG_EVENT_RULE_STATUS_OK
;
433 if (!rule
|| !IS_SYSCALL_EVENT_RULE(rule
) || !pattern
) {
434 status
= LTTNG_EVENT_RULE_STATUS_INVALID
;
438 syscall
= container_of(rule
, struct lttng_event_rule_syscall
, parent
);
439 if (!syscall
->pattern
) {
440 status
= LTTNG_EVENT_RULE_STATUS_UNSET
;
444 *pattern
= syscall
->pattern
;
449 enum lttng_event_rule_status
lttng_event_rule_syscall_set_filter(
450 struct lttng_event_rule
*rule
, const char *expression
)
452 char *expression_copy
= NULL
;
453 struct lttng_event_rule_syscall
*syscall
;
454 enum lttng_event_rule_status status
= LTTNG_EVENT_RULE_STATUS_OK
;
456 /* TODO: validate that the passed expression is valid. */
458 if (!rule
|| !IS_SYSCALL_EVENT_RULE(rule
) || !expression
||
459 strlen(expression
) == 0) {
460 status
= LTTNG_EVENT_RULE_STATUS_INVALID
;
464 syscall
= container_of(rule
, struct lttng_event_rule_syscall
, parent
);
465 expression_copy
= strdup(expression
);
466 if (!expression_copy
) {
467 status
= LTTNG_EVENT_RULE_STATUS_ERROR
;
471 if (syscall
->filter_expression
) {
472 free(syscall
->filter_expression
);
475 syscall
->filter_expression
= expression_copy
;
476 expression_copy
= NULL
;
481 enum lttng_event_rule_status
lttng_event_rule_syscall_get_filter(
482 const struct lttng_event_rule
*rule
, const char **expression
)
484 struct lttng_event_rule_syscall
*syscall
;
485 enum lttng_event_rule_status status
= LTTNG_EVENT_RULE_STATUS_OK
;
487 if (!rule
|| !IS_SYSCALL_EVENT_RULE(rule
) || !expression
) {
488 status
= LTTNG_EVENT_RULE_STATUS_INVALID
;
492 syscall
= container_of(rule
, struct lttng_event_rule_syscall
, parent
);
493 if (!syscall
->filter_expression
) {
494 status
= LTTNG_EVENT_RULE_STATUS_UNSET
;
498 *expression
= syscall
->filter_expression
;