2 * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
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>
15 #define IS_SYSCALL_EVENT_RULE(rule) \
16 (lttng_event_rule_get_type(rule) == LTTNG_EVENT_RULE_TYPE_SYSCALL)
18 static void lttng_event_rule_syscall_destroy(struct lttng_event_rule
*rule
)
20 struct lttng_event_rule_syscall
*syscall
;
26 syscall
= container_of(rule
, struct lttng_event_rule_syscall
, parent
);
28 free(syscall
->pattern
);
29 free(syscall
->filter_expression
);
30 free(syscall
->internal_filter
.filter
);
31 free(syscall
->internal_filter
.bytecode
);
35 static bool lttng_event_rule_syscall_validate(
36 const struct lttng_event_rule
*rule
)
39 struct lttng_event_rule_syscall
*syscall
;
45 syscall
= container_of(rule
, struct lttng_event_rule_syscall
, parent
);
48 if (!syscall
->pattern
) {
49 ERR("Invalid syscall event rule: a pattern must be set.");
58 static int lttng_event_rule_syscall_serialize(
59 const struct lttng_event_rule
*rule
,
60 struct lttng_dynamic_buffer
*buf
,
64 size_t pattern_len
, filter_expression_len
;
65 struct lttng_event_rule_syscall
*syscall
;
66 struct lttng_event_rule_syscall_comm syscall_comm
;
68 if (!rule
|| !IS_SYSCALL_EVENT_RULE(rule
)) {
73 DBG("Serializing syscall event rule");
74 syscall
= container_of(rule
, struct lttng_event_rule_syscall
, parent
);
76 pattern_len
= strlen(syscall
->pattern
) + 1;
78 if (syscall
->filter_expression
!= NULL
) {
79 filter_expression_len
= strlen(syscall
->filter_expression
) + 1;
81 filter_expression_len
= 0;
84 syscall_comm
.pattern_len
= pattern_len
;
85 syscall_comm
.filter_expression_len
= filter_expression_len
;
87 ret
= lttng_dynamic_buffer_append(
88 buf
, &syscall_comm
, sizeof(syscall_comm
));
92 ret
= lttng_dynamic_buffer_append(buf
, syscall
->pattern
, pattern_len
);
96 ret
= lttng_dynamic_buffer_append(
97 buf
, syscall
->filter_expression
, filter_expression_len
);
103 /* Nothing to send */
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
) {
124 /* syscall is invalid if this is not true */
127 if (strcmp(a
->pattern
, b
->pattern
)) {
131 if (a
->filter_expression
&& b
->filter_expression
) {
132 if (strcmp(a
->filter_expression
, b
->filter_expression
)) {
142 static enum lttng_error_code
lttng_event_rule_syscall_populate(
143 struct lttng_event_rule
*rule
, uid_t uid
, gid_t gid
)
146 enum lttng_error_code ret_code
= LTTNG_OK
;
147 struct lttng_event_rule_syscall
*syscall
;
148 enum lttng_event_rule_status status
;
150 struct lttng_bytecode
*bytecode
= NULL
;
154 syscall
= container_of(rule
, struct lttng_event_rule_syscall
, parent
);
156 /* Generate the filter bytecode */
157 status
= lttng_event_rule_syscall_get_filter(rule
, &filter
);
158 if (status
== LTTNG_EVENT_RULE_STATUS_UNSET
) {
160 } else if (status
!= LTTNG_EVENT_RULE_STATUS_OK
) {
161 ret_code
= LTTNG_ERR_FILTER_INVAL
;
165 if (filter
&& filter
[0] == '\0') {
166 ret_code
= LTTNG_ERR_FILTER_INVAL
;
170 if (filter
== NULL
) {
176 syscall
->internal_filter
.filter
= strdup(filter
);
177 if (syscall
->internal_filter
.filter
== NULL
) {
178 ret_code
= LTTNG_ERR_NOMEM
;
182 ret
= run_as_generate_filter_bytecode(
183 syscall
->internal_filter
.filter
, uid
, gid
, &bytecode
);
185 ret_code
= LTTNG_ERR_FILTER_INVAL
;
188 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
);
204 return syscall
->internal_filter
.filter
;
207 static const struct lttng_bytecode
*
208 lttng_event_rule_syscall_get_internal_filter_bytecode(
209 const struct lttng_event_rule
*rule
)
211 struct lttng_event_rule_syscall
*syscall
;
214 syscall
= container_of(rule
, struct lttng_event_rule_syscall
, parent
);
215 return syscall
->internal_filter
.bytecode
;
218 static struct lttng_event_exclusion
*
219 lttng_event_rule_syscall_generate_exclusions(struct lttng_event_rule
*rule
)
225 struct lttng_event_rule
*lttng_event_rule_syscall_create()
227 struct lttng_event_rule_syscall
*rule
;
229 rule
= zmalloc(sizeof(struct lttng_event_rule_syscall
));
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
;
249 ssize_t
lttng_event_rule_syscall_create_from_buffer(
250 const struct lttng_buffer_view
*view
,
251 struct lttng_event_rule
**_event_rule
)
253 ssize_t ret
, offset
= 0;
254 enum lttng_event_rule_status status
;
255 const struct lttng_event_rule_syscall_comm
*syscall_comm
;
257 const char *filter_expression
= NULL
;
258 struct lttng_buffer_view current_view
;
259 struct lttng_event_rule
*rule
= NULL
;
266 if (view
->size
< sizeof(*syscall_comm
)) {
267 ERR("Failed to initialize from malformed event rule syscall: buffer too short to contain header");
272 current_view
= lttng_buffer_view_from_view(
273 view
, offset
, sizeof(*syscall_comm
));
274 syscall_comm
= (typeof(syscall_comm
)) current_view
.data
;
281 rule
= lttng_event_rule_syscall_create();
283 ERR("Failed to create event rule syscall");
288 /* Skip to payload */
289 offset
+= current_view
.size
;
291 /* Map the pattern */
292 current_view
= lttng_buffer_view_from_view(
293 view
, offset
, syscall_comm
->pattern_len
);
294 pattern
= current_view
.data
;
300 if (syscall_comm
->pattern_len
== 1 ||
301 pattern
[syscall_comm
->pattern_len
- 1] != '\0' ||
302 strlen(pattern
) != syscall_comm
->pattern_len
- 1) {
304 * Check that the pattern is not NULL, is NULL-terminated, and
305 * does not contain a NULL before the last byte.
311 /* Skip after the pattern */
312 offset
+= syscall_comm
->pattern_len
;
314 if (!syscall_comm
->filter_expression_len
) {
315 goto skip_filter_expression
;
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
) {
327 if (syscall_comm
->filter_expression_len
== 1 ||
328 filter_expression
[syscall_comm
->filter_expression_len
-
330 strlen(filter_expression
) !=
331 syscall_comm
->filter_expression_len
-
334 * Check that the filter expression is not NULL, is
335 * NULL-terminated, and does not contain a NULL before the last
342 /* Skip after the pattern */
343 offset
+= syscall_comm
->filter_expression_len
;
345 skip_filter_expression
:
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");
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");
368 lttng_event_rule_destroy(rule
);
372 enum lttng_event_rule_status
lttng_event_rule_syscall_set_pattern(
373 struct lttng_event_rule
*rule
, const char *pattern
)
375 char *pattern_copy
= NULL
;
376 struct lttng_event_rule_syscall
*syscall
;
377 enum lttng_event_rule_status status
= LTTNG_EVENT_RULE_STATUS_OK
;
379 if (!rule
|| !IS_SYSCALL_EVENT_RULE(rule
) || !pattern
||
380 strlen(pattern
) == 0) {
381 status
= LTTNG_EVENT_RULE_STATUS_INVALID
;
385 syscall
= container_of(rule
, struct lttng_event_rule_syscall
, parent
);
386 pattern_copy
= strdup(pattern
);
388 status
= LTTNG_EVENT_RULE_STATUS_ERROR
;
392 if (syscall
->pattern
) {
393 free(syscall
->pattern
);
396 syscall
->pattern
= pattern_copy
;
402 enum lttng_event_rule_status
lttng_event_rule_syscall_get_pattern(
403 const struct lttng_event_rule
*rule
, const char **pattern
)
405 struct lttng_event_rule_syscall
*syscall
;
406 enum lttng_event_rule_status status
= LTTNG_EVENT_RULE_STATUS_OK
;
408 if (!rule
|| !IS_SYSCALL_EVENT_RULE(rule
) || !pattern
) {
409 status
= LTTNG_EVENT_RULE_STATUS_INVALID
;
413 syscall
= container_of(rule
, struct lttng_event_rule_syscall
, parent
);
414 if (!syscall
->pattern
) {
415 status
= LTTNG_EVENT_RULE_STATUS_UNSET
;
419 *pattern
= syscall
->pattern
;
424 enum lttng_event_rule_status
lttng_event_rule_syscall_set_filter(
425 struct lttng_event_rule
*rule
, const char *expression
)
427 char *expression_copy
= NULL
;
428 struct lttng_event_rule_syscall
*syscall
;
429 enum lttng_event_rule_status status
= LTTNG_EVENT_RULE_STATUS_OK
;
431 /* TODO: validate that the passed expression is valid */
433 if (!rule
|| !IS_SYSCALL_EVENT_RULE(rule
) || !expression
||
434 strlen(expression
) == 0) {
435 status
= LTTNG_EVENT_RULE_STATUS_INVALID
;
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
;
446 if (syscall
->filter_expression
) {
447 free(syscall
->filter_expression
);
450 syscall
->filter_expression
= expression_copy
;
451 expression_copy
= NULL
;
456 enum lttng_event_rule_status
lttng_event_rule_syscall_get_filter(
457 const struct lttng_event_rule
*rule
, const char **expression
)
459 struct lttng_event_rule_syscall
*syscall
;
460 enum lttng_event_rule_status status
= LTTNG_EVENT_RULE_STATUS_OK
;
462 if (!rule
|| !IS_SYSCALL_EVENT_RULE(rule
) || !expression
) {
463 status
= LTTNG_EVENT_RULE_STATUS_INVALID
;
467 syscall
= container_of(rule
, struct lttng_event_rule_syscall
, parent
);
468 if (!syscall
->filter_expression
) {
469 status
= LTTNG_EVENT_RULE_STATUS_UNSET
;
473 *expression
= syscall
->filter_expression
;