2 * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
3 * Copyright (C) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 * Copyright (C) 2019 Jérémie Galarneau <jeremie.galarneau@efficios.com>
6 * SPDX-License-Identifier: GPL-2.0-only
16 #include <sys/types.h>
25 #include <common/bytecode/bytecode.h>
26 #include <common/lttng-kernel.h>
27 #include <common/common.h>
28 #include <common/utils.h>
29 #include <common/compat/errno.h>
30 #include <common/compat/getenv.h>
31 #include <common/compat/string.h>
32 #include <common/unix.h>
33 #include <common/defaults.h>
34 #include <common/lttng-elf.h>
35 #include <common/thread.h>
37 #include <lttng/constant.h>
39 #include <common/sessiond-comm/sessiond-comm.h>
40 #include <common/filter/filter-ast.h>
46 typedef int (*run_as_fct
)(struct run_as_data
*data
, struct run_as_ret
*ret_value
);
51 RUN_AS_MKDIR_RECURSIVE
,
52 RUN_AS_MKDIRAT_RECURSIVE
,
59 RUN_AS_RMDIR_RECURSIVE
,
60 RUN_AS_RMDIRAT_RECURSIVE
,
63 RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
,
64 RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
,
65 RUN_AS_GENERATE_FILTER_BYTECODE
,
68 struct run_as_mkdir_data
{
70 char path
[LTTNG_PATH_MAX
];
74 struct run_as_open_data
{
76 char path
[LTTNG_PATH_MAX
];
81 struct run_as_unlink_data
{
83 char path
[LTTNG_PATH_MAX
];
86 struct run_as_rmdir_data
{
88 char path
[LTTNG_PATH_MAX
];
89 int flags
; /* enum lttng_directory_handle_rmdir_recursive_flags. */
92 struct run_as_extract_elf_symbol_offset_data
{
94 char function
[LTTNG_SYMBOL_NAME_LEN
];
97 struct run_as_extract_sdt_probe_offsets_data
{
99 char probe_name
[LTTNG_SYMBOL_NAME_LEN
];
100 char provider_name
[LTTNG_SYMBOL_NAME_LEN
];
103 struct run_as_generate_filter_bytecode_data
{
104 char filter_expression
[LTTNG_FILTER_MAX_LEN
];
107 struct run_as_rename_data
{
113 char old_path
[LTTNG_PATH_MAX
];
114 char new_path
[LTTNG_PATH_MAX
];
117 struct run_as_open_ret
{
121 struct run_as_extract_elf_symbol_offset_ret
{
125 struct run_as_extract_sdt_probe_offsets_ret
{
127 uint64_t offsets
[LTTNG_KERNEL_ABI_MAX_UPROBE_NUM
];
130 struct run_as_generate_filter_bytecode_ret
{
131 /* A lttng_bytecode_filter struct with 'dynamic' payload. */
132 char bytecode
[LTTNG_FILTER_MAX_LEN
];
138 struct run_as_mkdir_data mkdir
;
139 struct run_as_open_data open
;
140 struct run_as_unlink_data unlink
;
141 struct run_as_rmdir_data rmdir
;
142 struct run_as_rename_data rename
;
143 struct run_as_extract_elf_symbol_offset_data extract_elf_symbol_offset
;
144 struct run_as_extract_sdt_probe_offsets_data extract_sdt_probe_offsets
;
145 struct run_as_generate_filter_bytecode_data generate_filter_bytecode
;
152 * The run_as_ret structure holds the returned value and status of the command.
154 * The `u` union field holds the return value of the command; in most cases it
155 * represents the success or the failure of the command. In more complex
156 * commands, it holds a computed value.
158 * The _errno field is the errno recorded after the execution of the command.
160 * The _error fields is used the signify that return status of the command. For
161 * simple commands returning `int` the _error field will be the same as the
162 * ret_int field. In complex commands, it signify the success or failure of the
169 struct run_as_open_ret open
;
170 struct run_as_extract_elf_symbol_offset_ret extract_elf_symbol_offset
;
171 struct run_as_extract_sdt_probe_offsets_ret extract_sdt_probe_offsets
;
172 struct run_as_generate_filter_bytecode_ret generate_filter_bytecode
;
178 #define COMMAND_IN_FDS(data_ptr) ({ \
180 if (command_properties[data_ptr->cmd].in_fds_offset != -1) { \
181 fds = (int *) ((char *) data_ptr + command_properties[data_ptr->cmd].in_fds_offset); \
186 #define COMMAND_OUT_FDS(cmd, ret_ptr) ({ \
188 if (command_properties[cmd].out_fds_offset != -1) { \
189 fds = (int *) ((char *) ret_ptr + command_properties[cmd].out_fds_offset); \
194 #define COMMAND_IN_FD_COUNT(data_ptr) ({ \
195 command_properties[data_ptr->cmd].in_fd_count; \
198 #define COMMAND_OUT_FD_COUNT(cmd) ({ \
199 command_properties[cmd].out_fd_count; \
202 #define COMMAND_USE_CWD_FD(data_ptr) command_properties[data_ptr->cmd].use_cwd_fd
204 struct run_as_command_properties
{
205 /* Set to -1 when not applicable. */
206 ptrdiff_t in_fds_offset
, out_fds_offset
;
207 unsigned int in_fd_count
, out_fd_count
;
211 static const struct run_as_command_properties command_properties
[] = {
213 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
215 .out_fds_offset
= -1,
220 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
222 .out_fds_offset
= -1,
226 [RUN_AS_MKDIR_RECURSIVE
] = {
227 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
229 .out_fds_offset
= -1,
233 [RUN_AS_MKDIRAT_RECURSIVE
] = {
234 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
236 .out_fds_offset
= -1,
241 .in_fds_offset
= offsetof(struct run_as_data
, u
.open
.dirfd
),
243 .out_fds_offset
= offsetof(struct run_as_ret
, u
.open
.fd
),
248 .in_fds_offset
= offsetof(struct run_as_data
, u
.open
.dirfd
),
250 .out_fds_offset
= offsetof(struct run_as_ret
, u
.open
.fd
),
255 .in_fds_offset
= offsetof(struct run_as_data
, u
.unlink
.dirfd
),
257 .out_fds_offset
= -1,
261 [RUN_AS_UNLINKAT
] = {
262 .in_fds_offset
= offsetof(struct run_as_data
, u
.unlink
.dirfd
),
264 .out_fds_offset
= -1,
268 [RUN_AS_RMDIR_RECURSIVE
] = {
269 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
271 .out_fds_offset
= -1,
275 [RUN_AS_RMDIRAT_RECURSIVE
] = {
276 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
278 .out_fds_offset
= -1,
283 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
285 .out_fds_offset
= -1,
290 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
292 .out_fds_offset
= -1,
297 .in_fds_offset
= offsetof(struct run_as_data
, u
.rename
.dirfds
),
299 .out_fds_offset
= -1,
303 [RUN_AS_RENAMEAT
] = {
304 .in_fds_offset
= offsetof(struct run_as_data
, u
.rename
.dirfds
),
306 .out_fds_offset
= -1,
310 [RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
] = {
311 .in_fds_offset
= offsetof(struct run_as_data
,
312 u
.extract_elf_symbol_offset
.fd
),
314 .out_fds_offset
= -1,
318 [RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
] = {
319 .in_fds_offset
= offsetof(struct run_as_data
,
320 u
.extract_sdt_probe_offsets
.fd
),
322 .out_fds_offset
= -1,
326 [RUN_AS_GENERATE_FILTER_BYTECODE
] = {
329 .out_fds_offset
= -1,
335 struct run_as_worker
{
336 pid_t pid
; /* Worker PID. */
341 /* Single global worker per process (for now). */
342 static struct run_as_worker
*global_worker
;
343 /* Lock protecting the worker. */
344 static pthread_mutex_t worker_lock
= PTHREAD_MUTEX_INITIALIZER
;
356 return !lttng_secure_getenv("LTTNG_DEBUG_NOCLONE");
361 * Create recursively directory using the FULL path.
364 int _mkdirat_recursive(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
368 struct lttng_directory_handle
*handle
;
370 path
= data
->u
.mkdir
.path
;
371 mode
= data
->u
.mkdir
.mode
;
373 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.mkdir
.dirfd
);
375 ret_value
->_errno
= errno
;
376 ret_value
->_error
= true;
377 ret_value
->u
.ret
= -1;
380 /* Ownership of dirfd is transferred to the handle. */
381 data
->u
.mkdir
.dirfd
= -1;
382 /* Safe to call as we have transitioned to the requested uid/gid. */
383 ret_value
->u
.ret
= lttng_directory_handle_create_subdirectory_recursive(
385 ret_value
->_errno
= errno
;
386 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
387 lttng_directory_handle_put(handle
);
389 return ret_value
->u
.ret
;
393 int _mkdirat(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
397 struct lttng_directory_handle
*handle
;
399 path
= data
->u
.mkdir
.path
;
400 mode
= data
->u
.mkdir
.mode
;
402 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.mkdir
.dirfd
);
404 ret_value
->u
.ret
= -1;
405 ret_value
->_errno
= errno
;
406 ret_value
->_error
= true;
409 /* Ownership of dirfd is transferred to the handle. */
410 data
->u
.mkdir
.dirfd
= -1;
411 /* Safe to call as we have transitioned to the requested uid/gid. */
412 ret_value
->u
.ret
= lttng_directory_handle_create_subdirectory(
414 ret_value
->_errno
= errno
;
415 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
416 lttng_directory_handle_put(handle
);
418 return ret_value
->u
.ret
;
422 int _open(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
425 struct lttng_directory_handle
*handle
;
427 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.open
.dirfd
);
429 ret_value
->_errno
= errno
;
430 ret_value
->_error
= true;
431 ret_value
->u
.ret
= -1;
434 /* Ownership of dirfd is transferred to the handle. */
435 data
->u
.open
.dirfd
= -1;
437 fd
= lttng_directory_handle_open_file(handle
,
438 data
->u
.open
.path
, data
->u
.open
.flags
,
441 ret_value
->u
.ret
= -1;
442 ret_value
->u
.open
.fd
= -1;
444 ret_value
->u
.ret
= 0;
445 ret_value
->u
.open
.fd
= fd
;
448 ret_value
->_errno
= errno
;
449 ret_value
->_error
= fd
< 0;
450 lttng_directory_handle_put(handle
);
452 return ret_value
->u
.ret
;
456 int _unlink(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
458 struct lttng_directory_handle
*handle
;
460 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.unlink
.dirfd
);
462 ret_value
->u
.ret
= -1;
463 ret_value
->_errno
= errno
;
464 ret_value
->_error
= true;
468 /* Ownership of dirfd is transferred to the handle. */
469 data
->u
.unlink
.dirfd
= -1;
471 ret_value
->u
.ret
= lttng_directory_handle_unlink_file(handle
,
472 data
->u
.unlink
.path
);
473 ret_value
->_errno
= errno
;
474 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
475 lttng_directory_handle_put(handle
);
477 return ret_value
->u
.ret
;
481 int _rmdir(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
483 struct lttng_directory_handle
*handle
;
485 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.rmdir
.dirfd
);
487 ret_value
->u
.ret
= -1;
488 ret_value
->_errno
= errno
;
489 ret_value
->_error
= true;
493 /* Ownership of dirfd is transferred to the handle. */
494 data
->u
.rmdir
.dirfd
= -1;
496 ret_value
->u
.ret
= lttng_directory_handle_remove_subdirectory(
497 handle
, data
->u
.rmdir
.path
);
498 ret_value
->_errno
= errno
;
499 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
500 lttng_directory_handle_put(handle
);
502 return ret_value
->u
.ret
;
506 int _rmdir_recursive(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
508 struct lttng_directory_handle
*handle
;
510 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.rmdir
.dirfd
);
512 ret_value
->u
.ret
= -1;
513 ret_value
->_errno
= errno
;
514 ret_value
->_error
= true;
518 /* Ownership of dirfd is transferred to the handle. */
519 data
->u
.rmdir
.dirfd
= -1;
521 ret_value
->u
.ret
= lttng_directory_handle_remove_subdirectory_recursive(
522 handle
, data
->u
.rmdir
.path
, data
->u
.rmdir
.flags
);
523 ret_value
->_errno
= errno
;
524 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
525 lttng_directory_handle_put(handle
);
527 return ret_value
->u
.ret
;
531 int _rename(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
533 const char *old_path
, *new_path
;
534 struct lttng_directory_handle
*old_handle
= NULL
, *new_handle
= NULL
;
536 old_path
= data
->u
.rename
.old_path
;
537 new_path
= data
->u
.rename
.new_path
;
539 old_handle
= lttng_directory_handle_create_from_dirfd(
540 data
->u
.rename
.dirfds
[0]);
542 ret_value
->u
.ret
= -1;
545 new_handle
= lttng_directory_handle_create_from_dirfd(
546 data
->u
.rename
.dirfds
[1]);
548 ret_value
->u
.ret
= -1;
552 /* Ownership of dirfds are transferred to the handles. */
553 data
->u
.rename
.dirfds
[0] = data
->u
.rename
.dirfds
[1] = -1;
555 /* Safe to call as we have transitioned to the requested uid/gid. */
556 ret_value
->u
.ret
= lttng_directory_handle_rename(
557 old_handle
, old_path
, new_handle
, new_path
);
559 lttng_directory_handle_put(old_handle
);
560 lttng_directory_handle_put(new_handle
);
561 ret_value
->_errno
= errno
;
562 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
563 return ret_value
->u
.ret
;
568 int _extract_elf_symbol_offset(struct run_as_data
*data
,
569 struct run_as_ret
*ret_value
)
574 ret_value
->_error
= false;
575 ret
= lttng_elf_get_symbol_offset(data
->u
.extract_elf_symbol_offset
.fd
,
576 data
->u
.extract_elf_symbol_offset
.function
,
579 DBG("Failed to extract ELF function offset");
580 ret_value
->_error
= true;
582 ret_value
->u
.extract_elf_symbol_offset
.offset
= offset
;
588 int _extract_sdt_probe_offsets(struct run_as_data
*data
,
589 struct run_as_ret
*ret_value
)
592 uint64_t *offsets
= NULL
;
595 ret_value
->_error
= false;
597 /* On success, this call allocates the offsets paramater. */
598 ret
= lttng_elf_get_sdt_probe_offsets(
599 data
->u
.extract_sdt_probe_offsets
.fd
,
600 data
->u
.extract_sdt_probe_offsets
.provider_name
,
601 data
->u
.extract_sdt_probe_offsets
.probe_name
,
602 &offsets
, &num_offset
);
605 DBG("Failed to extract SDT probe offsets");
606 ret_value
->_error
= true;
610 if (num_offset
<= 0 || num_offset
> LTTNG_KERNEL_ABI_MAX_UPROBE_NUM
) {
611 DBG("Wrong number of probes.");
613 ret_value
->_error
= true;
617 /* Copy the content of the offsets array to the ret struct. */
618 memcpy(ret_value
->u
.extract_sdt_probe_offsets
.offsets
,
619 offsets
, num_offset
* sizeof(uint64_t));
621 ret_value
->u
.extract_sdt_probe_offsets
.num_offset
= num_offset
;
630 int _extract_elf_symbol_offset(struct run_as_data
*data
,
631 struct run_as_ret
*ret_value
)
633 ERR("Unimplemented runas command RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET");
638 int _extract_sdt_probe_offsets(struct run_as_data
*data
,
639 struct run_as_ret
*ret_value
)
641 ERR("Unimplemented runas command RUN_AS_EXTRACT_SDT_PROBE_OFFSETS");
647 int _generate_filter_bytecode(struct run_as_data
*data
,
648 struct run_as_ret
*ret_value
) {
650 const char *filter_expression
= NULL
;
651 struct filter_parser_ctx
*ctx
= NULL
;
653 ret_value
->_error
= false;
655 filter_expression
= data
->u
.generate_filter_bytecode
.filter_expression
;
657 if (lttng_strnlen(filter_expression
, LTTNG_FILTER_MAX_LEN
- 1) == LTTNG_FILTER_MAX_LEN
- 1) {
658 ret_value
->_error
= true;
663 ret
= filter_parser_ctx_create_from_filter_expression(filter_expression
, &ctx
);
665 ret_value
->_error
= true;
670 DBG("Size of bytecode generated: %u bytes.",
671 bytecode_get_len(&ctx
->bytecode
->b
));
673 /* Copy the lttng_bytecode_filter object to the return structure. */
674 memcpy(ret_value
->u
.generate_filter_bytecode
.bytecode
,
676 sizeof(ctx
->bytecode
->b
) +
677 bytecode_get_len(&ctx
->bytecode
->b
));
681 filter_bytecode_free(ctx
);
683 filter_parser_ctx_free(ctx
);
689 run_as_fct
run_as_enum_to_fct(enum run_as_cmd cmd
)
695 case RUN_AS_MKDIR_RECURSIVE
:
696 case RUN_AS_MKDIRAT_RECURSIVE
:
697 return _mkdirat_recursive
;
702 case RUN_AS_UNLINKAT
:
707 case RUN_AS_RMDIR_RECURSIVE
:
708 case RUN_AS_RMDIRAT_RECURSIVE
:
709 return _rmdir_recursive
;
711 case RUN_AS_RENAMEAT
:
713 case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
:
714 return _extract_elf_symbol_offset
;
715 case RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
:
716 return _extract_sdt_probe_offsets
;
717 case RUN_AS_GENERATE_FILTER_BYTECODE
:
718 return _generate_filter_bytecode
;
720 ERR("Unknown command %d", (int) cmd
);
726 int do_send_fds(int sock
, const int *fds
, unsigned int fd_count
)
731 for (i
= 0; i
< fd_count
; i
++) {
733 DBG("Attempt to send invalid file descriptor (fd = %i)",
735 /* Return 0 as this is not a fatal error. */
740 len
= lttcomm_send_fds_unix_sock(sock
, fds
, fd_count
);
741 return len
< 0 ? -1 : 0;
745 int do_recv_fds(int sock
, int *fds
, unsigned int fd_count
)
751 len
= lttcomm_recv_fds_unix_sock(sock
, fds
, fd_count
);
755 } else if (len
< 0) {
756 PERROR("Failed to receive file descriptors from socket");
761 for (i
= 0; i
< fd_count
; i
++) {
763 ERR("Invalid file descriptor received from worker (fd = %i)", fds
[i
]);
764 /* Return 0 as this is not a fatal error. */
772 int send_fds_to_worker(const struct run_as_worker
*worker
,
773 const struct run_as_data
*data
)
778 if (COMMAND_USE_CWD_FD(data
) || COMMAND_IN_FD_COUNT(data
) == 0) {
782 for (i
= 0; i
< COMMAND_IN_FD_COUNT(data
); i
++) {
783 if (COMMAND_IN_FDS(data
)[i
] < 0) {
784 ERR("Refusing to send invalid fd to worker (fd = %i)",
785 COMMAND_IN_FDS(data
)[i
]);
791 ret
= do_send_fds(worker
->sockpair
[0], COMMAND_IN_FDS(data
),
792 COMMAND_IN_FD_COUNT(data
));
794 PERROR("Failed to send file descriptor to run-as worker");
803 int send_fds_to_master(struct run_as_worker
*worker
, enum run_as_cmd cmd
,
804 struct run_as_ret
*run_as_ret
)
809 if (COMMAND_OUT_FD_COUNT(cmd
) == 0) {
813 ret
= do_send_fds(worker
->sockpair
[1], COMMAND_OUT_FDS(cmd
, run_as_ret
),
814 COMMAND_OUT_FD_COUNT(cmd
));
816 PERROR("Failed to send file descriptor to master process");
820 for (i
= 0; i
< COMMAND_OUT_FD_COUNT(cmd
); i
++) {
821 int fd
= COMMAND_OUT_FDS(cmd
, run_as_ret
)[i
];
823 int ret_close
= close(fd
);
826 PERROR("Failed to close result file descriptor (fd = %i)",
836 int recv_fds_from_worker(const struct run_as_worker
*worker
, enum run_as_cmd cmd
,
837 struct run_as_ret
*run_as_ret
)
841 if (COMMAND_OUT_FD_COUNT(cmd
) == 0) {
845 ret
= do_recv_fds(worker
->sockpair
[0], COMMAND_OUT_FDS(cmd
, run_as_ret
),
846 COMMAND_OUT_FD_COUNT(cmd
));
848 PERROR("Failed to receive file descriptor from run-as worker");
856 int recv_fds_from_master(struct run_as_worker
*worker
, struct run_as_data
*data
)
860 if (COMMAND_USE_CWD_FD(data
)) {
863 for (i
= 0; i
< COMMAND_IN_FD_COUNT(data
); i
++) {
864 COMMAND_IN_FDS(data
)[i
] = AT_FDCWD
;
869 if (COMMAND_IN_FD_COUNT(data
) == 0) {
873 ret
= do_recv_fds(worker
->sockpair
[1], COMMAND_IN_FDS(data
),
874 COMMAND_IN_FD_COUNT(data
));
876 PERROR("Failed to receive file descriptors from master process");
884 int cleanup_received_fds(struct run_as_data
*data
)
888 for (i
= 0; i
< COMMAND_IN_FD_COUNT(data
); i
++) {
889 if (COMMAND_IN_FDS(data
)[i
] == -1) {
892 ret
= close(COMMAND_IN_FDS(data
)[i
]);
894 PERROR("Failed to close file descriptor received fd in run-as worker");
903 * Return < 0 on error, 0 if OK, 1 on hangup.
906 int handle_one_cmd(struct run_as_worker
*worker
)
909 struct run_as_data data
= {};
910 ssize_t readlen
, writelen
;
911 struct run_as_ret sendret
= {};
916 * Stage 1: Receive run_as_data struct from the master.
917 * The structure contains the command type and all the parameters needed for
920 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[1], &data
,
927 if (readlen
< sizeof(data
)) {
928 PERROR("lttcomm_recv_unix_sock error");
933 cmd
= run_as_enum_to_fct(data
.cmd
);
940 * Stage 2: Receive file descriptor from master.
941 * Some commands need a file descriptor as input so if it's needed we
942 * receive the fd using the Unix socket.
944 ret
= recv_fds_from_master(worker
, &data
);
946 PERROR("recv_fd_from_master error");
951 prev_euid
= getuid();
952 if (data
.gid
!= getegid()) {
953 ret
= setegid(data
.gid
);
955 sendret
._error
= true;
956 sendret
._errno
= errno
;
961 if (data
.uid
!= prev_euid
) {
962 ret
= seteuid(data
.uid
);
964 sendret
._error
= true;
965 sendret
._errno
= errno
;
972 * Also set umask to 0 for mkdir executable bit.
977 * Stage 3: Execute the command
979 ret
= (*cmd
)(&data
, &sendret
);
981 DBG("Execution of command returned an error");
985 ret
= cleanup_received_fds(&data
);
987 ERR("Error cleaning up FD");
992 * Stage 4: Send run_as_ret structure to the master.
993 * This structure contain the return value of the command and the errno.
995 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[1], &sendret
,
997 if (writelen
< sizeof(sendret
)) {
998 PERROR("lttcomm_send_unix_sock error");
1004 * Stage 5: Send resulting file descriptors to the master.
1006 ret
= send_fds_to_master(worker
, data
.cmd
, &sendret
);
1008 DBG("Sending FD to master returned an error");
1012 if (seteuid(prev_euid
) < 0) {
1023 int run_as_worker(struct run_as_worker
*worker
)
1027 struct run_as_ret sendret
;
1028 size_t proc_orig_len
;
1031 * Initialize worker. Set a different process cmdline.
1033 proc_orig_len
= strlen(worker
->procname
);
1034 memset(worker
->procname
, 0, proc_orig_len
);
1035 strncpy(worker
->procname
, DEFAULT_RUN_AS_WORKER_NAME
, proc_orig_len
);
1037 ret
= lttng_thread_setname(DEFAULT_RUN_AS_WORKER_NAME
);
1038 if (ret
&& ret
!= -ENOSYS
) {
1039 /* Don't fail as this is not essential. */
1040 DBG("Failed to set pthread name attribute");
1043 memset(&sendret
, 0, sizeof(sendret
));
1045 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[1], &sendret
,
1047 if (writelen
< sizeof(sendret
)) {
1048 PERROR("lttcomm_send_unix_sock error");
1054 ret
= handle_one_cmd(worker
);
1058 } else if (ret
> 0) {
1061 continue; /* Next command. */
1070 int run_as_cmd(struct run_as_worker
*worker
,
1071 enum run_as_cmd cmd
,
1072 struct run_as_data
*data
,
1073 struct run_as_ret
*ret_value
,
1074 uid_t uid
, gid_t gid
)
1077 ssize_t readlen
, writelen
;
1080 * If we are non-root, we can only deal with our own uid.
1082 if (geteuid() != 0) {
1083 if (uid
!= geteuid()) {
1085 ret_value
->_errno
= EPERM
;
1086 ERR("Client (%d)/Server (%d) UID mismatch (and sessiond is not root)",
1087 (int) uid
, (int) geteuid());
1097 * Stage 1: Send the run_as_data struct to the worker process
1099 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[0], data
,
1101 if (writelen
< sizeof(*data
)) {
1102 PERROR("Error writing message to run_as");
1104 ret_value
->_errno
= EIO
;
1109 * Stage 2: Send file descriptor to the worker process if needed
1111 ret
= send_fds_to_worker(worker
, data
);
1113 PERROR("do_send_fd error");
1115 ret_value
->_errno
= EIO
;
1120 * Stage 3: Wait for the execution of the command
1124 * Stage 4: Receive the run_as_ret struct containing the return value and
1127 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[0], ret_value
,
1128 sizeof(*ret_value
));
1130 ERR("Run-as worker has hung-up during run_as_cmd");
1132 ret_value
->_errno
= EIO
;
1134 } else if (readlen
< sizeof(*ret_value
)) {
1135 PERROR("Error reading response from run_as");
1137 ret_value
->_errno
= errno
;
1141 if (ret_value
->_error
) {
1142 /* Skip stage 5 on error as there will be no fd to receive. */
1147 * Stage 5: Receive file descriptor if needed
1149 ret
= recv_fds_from_worker(worker
, cmd
, ret_value
);
1151 ERR("Error receiving fd");
1153 ret_value
->_errno
= EIO
;
1161 * This is for debugging ONLY and should not be considered secure.
1164 int run_as_noworker(enum run_as_cmd cmd
,
1165 struct run_as_data
*data
, struct run_as_ret
*ret_value
,
1166 uid_t uid
, gid_t gid
)
1168 int ret
, saved_errno
;
1172 fct
= run_as_enum_to_fct(cmd
);
1178 old_mask
= umask(0);
1179 ret
= fct(data
, ret_value
);
1180 saved_errno
= ret_value
->_errno
;
1182 errno
= saved_errno
;
1188 int reset_sighandler(void)
1192 DBG("Resetting run_as worker signal handlers to default");
1193 for (sig
= 1; sig
<= 31; sig
++) {
1194 (void) signal(sig
, SIG_DFL
);
1200 void worker_sighandler(int sig
)
1202 const char *signame
;
1205 * The worker will inherit its parent's signals since they are part of
1206 * the same process group. However, in the case of SIGINT and SIGTERM,
1207 * we want to give the worker a chance to teardown gracefully when its
1208 * parent closes the command socket.
1215 signame
= "SIGTERM";
1222 DBG("run_as worker received signal %s", signame
);
1224 DBG("run_as_worker received signal %d", sig
);
1229 int set_worker_sighandlers(void)
1233 struct sigaction sa
;
1235 if ((ret
= sigemptyset(&sigset
)) < 0) {
1236 PERROR("sigemptyset");
1240 sa
.sa_handler
= worker_sighandler
;
1241 sa
.sa_mask
= sigset
;
1243 if ((ret
= sigaction(SIGINT
, &sa
, NULL
)) < 0) {
1244 PERROR("sigaction SIGINT");
1248 if ((ret
= sigaction(SIGTERM
, &sa
, NULL
)) < 0) {
1249 PERROR("sigaction SIGTERM");
1253 DBG("run_as signal handler set for SIGTERM and SIGINT");
1259 int run_as_create_worker_no_lock(const char *procname
,
1260 post_fork_cleanup_cb clean_up_func
,
1261 void *clean_up_user_data
)
1266 struct run_as_ret recvret
;
1267 struct run_as_worker
*worker
;
1269 assert(!global_worker
);
1272 * Don't initialize a worker, all run_as tasks will be performed
1273 * in the current process.
1278 worker
= zmalloc(sizeof(*worker
));
1283 worker
->procname
= strdup(procname
);
1284 if (!worker
->procname
) {
1286 goto error_procname_alloc
;
1288 /* Create unix socket. */
1289 if (lttcomm_create_anon_unix_socketpair(worker
->sockpair
) < 0) {
1300 } else if (pid
== 0) {
1305 set_worker_sighandlers();
1307 logger_set_thread_name("Run-as worker", true);
1309 if (clean_up_func
) {
1310 if (clean_up_func(clean_up_user_data
) < 0) {
1311 ERR("Run-as post-fork clean-up failed, exiting.");
1316 /* Just close, no shutdown. */
1317 if (close(worker
->sockpair
[0])) {
1323 * Close all FDs aside from STDIN, STDOUT, STDERR and sockpair[1]
1324 * Sockpair[1] is used as a control channel with the master
1326 for (i
= 3; i
< sysconf(_SC_OPEN_MAX
); i
++) {
1327 if (i
!= worker
->sockpair
[1]) {
1332 worker
->sockpair
[0] = -1;
1333 ret
= run_as_worker(worker
);
1334 if (lttcomm_close_unix_sock(worker
->sockpair
[1])) {
1338 worker
->sockpair
[1] = -1;
1339 free(worker
->procname
);
1341 LOG(ret
? PRINT_ERR
: PRINT_DBG
, "run_as worker exiting (ret = %d)", ret
);
1342 exit(ret
? EXIT_FAILURE
: EXIT_SUCCESS
);
1346 /* Just close, no shutdown. */
1347 if (close(worker
->sockpair
[1])) {
1352 worker
->sockpair
[1] = -1;
1354 /* Wait for worker to become ready. */
1355 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[0],
1356 &recvret
, sizeof(recvret
));
1357 if (readlen
< sizeof(recvret
)) {
1358 ERR("readlen: %zd", readlen
);
1359 PERROR("Error reading response from run_as at creation");
1363 global_worker
= worker
;
1368 /* Error handling. */
1370 for (i
= 0; i
< 2; i
++) {
1371 if (worker
->sockpair
[i
] < 0) {
1374 if (lttcomm_close_unix_sock(worker
->sockpair
[i
])) {
1377 worker
->sockpair
[i
] = -1;
1380 free(worker
->procname
);
1381 error_procname_alloc
:
1387 void run_as_destroy_worker_no_lock(void)
1389 struct run_as_worker
*worker
= global_worker
;
1391 DBG("Destroying run_as worker");
1395 /* Close unix socket */
1396 DBG("Closing run_as worker socket");
1397 if (lttcomm_close_unix_sock(worker
->sockpair
[0])) {
1400 worker
->sockpair
[0] = -1;
1401 /* Wait for worker. */
1406 wait_ret
= waitpid(worker
->pid
, &status
, 0);
1408 if (errno
== EINTR
) {
1415 if (WIFEXITED(status
)) {
1416 LOG(WEXITSTATUS(status
) == 0 ? PRINT_DBG
: PRINT_ERR
,
1417 DEFAULT_RUN_AS_WORKER_NAME
" terminated with status code %d",
1418 WEXITSTATUS(status
));
1420 } else if (WIFSIGNALED(status
)) {
1421 ERR(DEFAULT_RUN_AS_WORKER_NAME
" was killed by signal %d",
1426 free(worker
->procname
);
1428 global_worker
= NULL
;
1432 int run_as_restart_worker(struct run_as_worker
*worker
)
1435 char *procname
= NULL
;
1437 procname
= worker
->procname
;
1439 /* Close socket to run_as worker process and clean up the zombie process */
1440 run_as_destroy_worker_no_lock();
1442 /* Create a new run_as worker process*/
1443 ret
= run_as_create_worker_no_lock(procname
, NULL
, NULL
);
1445 ERR("Restarting the worker process failed");
1454 int run_as(enum run_as_cmd cmd
, struct run_as_data
*data
,
1455 struct run_as_ret
*ret_value
, uid_t uid
, gid_t gid
)
1457 int ret
, saved_errno
;
1459 pthread_mutex_lock(&worker_lock
);
1461 DBG("Using run_as worker");
1463 assert(global_worker
);
1465 ret
= run_as_cmd(global_worker
, cmd
, data
, ret_value
, uid
, gid
);
1466 saved_errno
= ret_value
->_errno
;
1469 * If the worker thread crashed the errno is set to EIO. we log
1470 * the error and start a new worker process.
1472 if (ret
== -1 && saved_errno
== EIO
) {
1473 DBG("Socket closed unexpectedly... "
1474 "Restarting the worker process");
1475 ret
= run_as_restart_worker(global_worker
);
1477 ERR("Failed to restart worker process.");
1482 DBG("Using run_as without worker");
1483 ret
= run_as_noworker(cmd
, data
, ret_value
, uid
, gid
);
1486 pthread_mutex_unlock(&worker_lock
);
1491 int run_as_mkdir_recursive(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
1493 return run_as_mkdirat_recursive(AT_FDCWD
, path
, mode
, uid
, gid
);
1497 int run_as_mkdirat_recursive(int dirfd
, const char *path
, mode_t mode
,
1498 uid_t uid
, gid_t gid
)
1501 struct run_as_data data
= {};
1502 struct run_as_ret run_as_ret
= {};
1504 DBG3("mkdirat() recursive fd = %d%s, path = %s, mode = %d, uid = %d, gid = %d",
1505 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1506 path
, (int) mode
, (int) uid
, (int) gid
);
1507 ret
= lttng_strncpy(data
.u
.mkdir
.path
, path
,
1508 sizeof(data
.u
.mkdir
.path
));
1510 ERR("Failed to copy path argument of mkdirat recursive command");
1513 data
.u
.mkdir
.path
[sizeof(data
.u
.mkdir
.path
) - 1] = '\0';
1514 data
.u
.mkdir
.mode
= mode
;
1515 data
.u
.mkdir
.dirfd
= dirfd
;
1516 run_as(dirfd
== AT_FDCWD
? RUN_AS_MKDIR_RECURSIVE
: RUN_AS_MKDIRAT_RECURSIVE
,
1517 &data
, &run_as_ret
, uid
, gid
);
1518 errno
= run_as_ret
._errno
;
1519 ret
= run_as_ret
.u
.ret
;
1525 int run_as_mkdir(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
1527 return run_as_mkdirat(AT_FDCWD
, path
, mode
, uid
, gid
);
1531 int run_as_mkdirat(int dirfd
, const char *path
, mode_t mode
,
1532 uid_t uid
, gid_t gid
)
1535 struct run_as_data data
= {};
1536 struct run_as_ret run_as_ret
= {};
1538 DBG3("mkdirat() recursive fd = %d%s, path = %s, mode = %d, uid = %d, gid = %d",
1539 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1540 path
, (int) mode
, (int) uid
, (int) gid
);
1541 ret
= lttng_strncpy(data
.u
.mkdir
.path
, path
,
1542 sizeof(data
.u
.mkdir
.path
));
1544 ERR("Failed to copy path argument of mkdirat command");
1547 data
.u
.mkdir
.path
[sizeof(data
.u
.mkdir
.path
) - 1] = '\0';
1548 data
.u
.mkdir
.mode
= mode
;
1549 data
.u
.mkdir
.dirfd
= dirfd
;
1550 run_as(dirfd
== AT_FDCWD
? RUN_AS_MKDIR
: RUN_AS_MKDIRAT
,
1551 &data
, &run_as_ret
, uid
, gid
);
1552 errno
= run_as_ret
._errno
;
1553 ret
= run_as_ret
.u
.ret
;
1559 int run_as_open(const char *path
, int flags
, mode_t mode
, uid_t uid
,
1562 return run_as_openat(AT_FDCWD
, path
, flags
, mode
, uid
, gid
);
1566 int run_as_openat(int dirfd
, const char *path
, int flags
, mode_t mode
,
1567 uid_t uid
, gid_t gid
)
1570 struct run_as_data data
= {};
1571 struct run_as_ret run_as_ret
= {};
1573 DBG3("openat() fd = %d%s, path = %s, flags = %X, mode = %d, uid %d, gid %d",
1574 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1575 path
, flags
, (int) mode
, (int) uid
, (int) gid
);
1576 ret
= lttng_strncpy(data
.u
.open
.path
, path
, sizeof(data
.u
.open
.path
));
1578 ERR("Failed to copy path argument of open command");
1581 data
.u
.open
.flags
= flags
;
1582 data
.u
.open
.mode
= mode
;
1583 data
.u
.open
.dirfd
= dirfd
;
1584 run_as(dirfd
== AT_FDCWD
? RUN_AS_OPEN
: RUN_AS_OPENAT
,
1585 &data
, &run_as_ret
, uid
, gid
);
1586 errno
= run_as_ret
._errno
;
1587 ret
= run_as_ret
.u
.ret
< 0 ? run_as_ret
.u
.ret
:
1588 run_as_ret
.u
.open
.fd
;
1594 int run_as_unlink(const char *path
, uid_t uid
, gid_t gid
)
1596 return run_as_unlinkat(AT_FDCWD
, path
, uid
, gid
);
1600 int run_as_unlinkat(int dirfd
, const char *path
, uid_t uid
, gid_t gid
)
1603 struct run_as_data data
= {};
1604 struct run_as_ret run_as_ret
= {};
1606 DBG3("unlinkat() fd = %d%s, path = %s, uid = %d, gid = %d",
1607 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1608 path
, (int) uid
, (int) gid
);
1609 ret
= lttng_strncpy(data
.u
.unlink
.path
, path
,
1610 sizeof(data
.u
.unlink
.path
));
1614 data
.u
.unlink
.dirfd
= dirfd
;
1615 run_as(dirfd
== AT_FDCWD
? RUN_AS_UNLINK
: RUN_AS_UNLINKAT
, &data
,
1616 &run_as_ret
, uid
, gid
);
1617 errno
= run_as_ret
._errno
;
1618 ret
= run_as_ret
.u
.ret
;
1624 int run_as_rmdir(const char *path
, uid_t uid
, gid_t gid
)
1626 return run_as_rmdirat(AT_FDCWD
, path
, uid
, gid
);
1630 int run_as_rmdirat(int dirfd
, const char *path
, uid_t uid
, gid_t gid
)
1633 struct run_as_data data
= {};
1634 struct run_as_ret run_as_ret
= {};
1636 DBG3("rmdirat() fd = %d%s, path = %s, uid = %d, gid = %d",
1637 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1638 path
, (int) uid
, (int) gid
);
1639 ret
= lttng_strncpy(data
.u
.rmdir
.path
, path
,
1640 sizeof(data
.u
.rmdir
.path
));
1644 data
.u
.rmdir
.dirfd
= dirfd
;
1645 run_as(dirfd
== AT_FDCWD
? RUN_AS_RMDIR
: RUN_AS_RMDIRAT
, &data
,
1646 &run_as_ret
, uid
, gid
);
1647 errno
= run_as_ret
._errno
;
1648 ret
= run_as_ret
.u
.ret
;
1654 int run_as_rmdir_recursive(const char *path
, uid_t uid
, gid_t gid
, int flags
)
1656 return run_as_rmdirat_recursive(AT_FDCWD
, path
, uid
, gid
, flags
);
1660 int run_as_rmdirat_recursive(int dirfd
, const char *path
, uid_t uid
, gid_t gid
, int flags
)
1663 struct run_as_data data
= {};
1664 struct run_as_ret run_as_ret
= {};
1666 DBG3("rmdirat() recursive fd = %d%s, path = %s, uid = %d, gid = %d",
1667 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1668 path
, (int) uid
, (int) gid
);
1669 ret
= lttng_strncpy(data
.u
.rmdir
.path
, path
,
1670 sizeof(data
.u
.rmdir
.path
));
1674 data
.u
.rmdir
.dirfd
= dirfd
;
1675 data
.u
.rmdir
.flags
= flags
;
1676 run_as(dirfd
== AT_FDCWD
? RUN_AS_RMDIR_RECURSIVE
: RUN_AS_RMDIRAT_RECURSIVE
,
1677 &data
, &run_as_ret
, uid
, gid
);
1678 errno
= run_as_ret
._errno
;
1679 ret
= run_as_ret
.u
.ret
;
1685 int run_as_rename(const char *old
, const char *new, uid_t uid
, gid_t gid
)
1687 return run_as_renameat(AT_FDCWD
, old
, AT_FDCWD
, new, uid
, gid
);
1691 int run_as_renameat(int old_dirfd
, const char *old_name
,
1692 int new_dirfd
, const char *new_name
, uid_t uid
, gid_t gid
)
1695 struct run_as_data data
= {};
1696 struct run_as_ret run_as_ret
= {};
1698 DBG3("renameat() old_dirfd = %d%s, old_name = %s, new_dirfd = %d%s, new_name = %s, uid = %d, gid = %d",
1699 old_dirfd
, old_dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1701 new_dirfd
, new_dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1702 new_name
, (int) uid
, (int) gid
);
1703 ret
= lttng_strncpy(data
.u
.rename
.old_path
, old_name
,
1704 sizeof(data
.u
.rename
.old_path
));
1708 ret
= lttng_strncpy(data
.u
.rename
.new_path
, new_name
,
1709 sizeof(data
.u
.rename
.new_path
));
1714 data
.u
.rename
.dirfds
[0] = old_dirfd
;
1715 data
.u
.rename
.dirfds
[1] = new_dirfd
;
1716 run_as(old_dirfd
== AT_FDCWD
&& new_dirfd
== AT_FDCWD
?
1717 RUN_AS_RENAME
: RUN_AS_RENAMEAT
,
1718 &data
, &run_as_ret
, uid
, gid
);
1719 errno
= run_as_ret
._errno
;
1720 ret
= run_as_ret
.u
.ret
;
1726 int run_as_extract_elf_symbol_offset(int fd
, const char* function
,
1727 uid_t uid
, gid_t gid
, uint64_t *offset
)
1730 struct run_as_data data
= {};
1731 struct run_as_ret run_as_ret
= {};
1733 DBG3("extract_elf_symbol_offset() on fd=%d and function=%s "
1734 "with for uid %d and gid %d", fd
, function
,
1735 (int) uid
, (int) gid
);
1737 data
.u
.extract_elf_symbol_offset
.fd
= fd
;
1739 strncpy(data
.u
.extract_elf_symbol_offset
.function
, function
, LTTNG_SYMBOL_NAME_LEN
- 1);
1740 data
.u
.extract_elf_symbol_offset
.function
[LTTNG_SYMBOL_NAME_LEN
- 1] = '\0';
1741 ret
= lttng_strncpy(data
.u
.extract_elf_symbol_offset
.function
,
1743 sizeof(data
.u
.extract_elf_symbol_offset
.function
));
1748 run_as(RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
, &data
, &run_as_ret
, uid
, gid
);
1749 errno
= run_as_ret
._errno
;
1750 if (run_as_ret
._error
) {
1755 *offset
= run_as_ret
.u
.extract_elf_symbol_offset
.offset
;
1761 int run_as_extract_sdt_probe_offsets(int fd
, const char* provider_name
,
1762 const char* probe_name
, uid_t uid
, gid_t gid
,
1763 uint64_t **offsets
, uint32_t *num_offset
)
1766 struct run_as_data data
= {};
1767 struct run_as_ret run_as_ret
= {};
1769 DBG3("extract_sdt_probe_offsets() on fd=%d, probe_name=%s and "
1770 "provider_name=%s with for uid %d and gid %d", fd
,
1771 probe_name
, provider_name
, (int) uid
, (int) gid
);
1773 data
.u
.extract_sdt_probe_offsets
.fd
= fd
;
1775 ret
= lttng_strncpy(data
.u
.extract_sdt_probe_offsets
.probe_name
, probe_name
,
1776 sizeof(data
.u
.extract_sdt_probe_offsets
.probe_name
));
1780 ret
= lttng_strncpy(data
.u
.extract_sdt_probe_offsets
.provider_name
,
1782 sizeof(data
.u
.extract_sdt_probe_offsets
.provider_name
));
1787 run_as(RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
, &data
, &run_as_ret
, uid
, gid
);
1788 errno
= run_as_ret
._errno
;
1789 if (run_as_ret
._error
) {
1794 *num_offset
= run_as_ret
.u
.extract_sdt_probe_offsets
.num_offset
;
1795 *offsets
= zmalloc(*num_offset
* sizeof(uint64_t));
1801 memcpy(*offsets
, run_as_ret
.u
.extract_sdt_probe_offsets
.offsets
,
1802 *num_offset
* sizeof(uint64_t));
1808 int run_as_generate_filter_bytecode(const char *filter_expression
,
1809 const struct lttng_credentials
*creds
,
1810 struct lttng_bytecode
**bytecode
)
1813 struct run_as_data data
= {};
1814 struct run_as_ret run_as_ret
= {};
1815 const struct lttng_bytecode
*view_bytecode
= NULL
;
1816 struct lttng_bytecode
*local_bytecode
= NULL
;
1817 const uid_t uid
= lttng_credentials_get_uid(creds
);
1818 const gid_t gid
= lttng_credentials_get_gid(creds
);
1820 DBG3("generate_filter_bytecode() from expression=\"%s\" for uid %d and gid %d",
1821 filter_expression
, (int) uid
, (int) gid
);
1823 ret
= lttng_strncpy(data
.u
.generate_filter_bytecode
.filter_expression
, filter_expression
,
1824 sizeof(data
.u
.generate_filter_bytecode
.filter_expression
));
1829 run_as(RUN_AS_GENERATE_FILTER_BYTECODE
, &data
, &run_as_ret
, uid
, gid
);
1830 errno
= run_as_ret
._errno
;
1831 if (run_as_ret
._error
) {
1836 view_bytecode
= (const struct lttng_bytecode
*) run_as_ret
.u
.generate_filter_bytecode
.bytecode
;
1838 local_bytecode
= zmalloc(sizeof(*local_bytecode
) + view_bytecode
->len
);
1839 if (!local_bytecode
) {
1844 memcpy(local_bytecode
, run_as_ret
.u
.generate_filter_bytecode
.bytecode
,
1845 sizeof(*local_bytecode
) + view_bytecode
->len
);
1846 *bytecode
= local_bytecode
;
1852 int run_as_create_worker(const char *procname
,
1853 post_fork_cleanup_cb clean_up_func
,
1854 void *clean_up_user_data
)
1858 pthread_mutex_lock(&worker_lock
);
1859 ret
= run_as_create_worker_no_lock(procname
, clean_up_func
,
1860 clean_up_user_data
);
1861 pthread_mutex_unlock(&worker_lock
);
1866 void run_as_destroy_worker(void)
1868 pthread_mutex_lock(&worker_lock
);
1869 run_as_destroy_worker_no_lock();
1870 pthread_mutex_unlock(&worker_lock
);