2 * Copyright (C) 2011 EfficiOS Inc.
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: LGPL-2.1-only
13 #include <common/bytecode/bytecode.hpp>
14 #include <common/common.hpp>
15 #include <common/compat/errno.hpp>
16 #include <common/compat/getenv.hpp>
17 #include <common/compat/string.hpp>
18 #include <common/defaults.hpp>
19 #include <common/filter/filter-ast.hpp>
20 #include <common/lttng-elf.hpp>
21 #include <common/lttng-kernel.hpp>
22 #include <common/sessiond-comm/sessiond-comm.hpp>
23 #include <common/thread.hpp>
24 #include <common/unix.hpp>
25 #include <common/utils.hpp>
27 #include <lttng/constant.h>
39 #include <sys/types.h>
43 #define GETPW_BUFFER_FALLBACK_SIZE 4096
48 RUN_AS_MKDIR_RECURSIVE
,
49 RUN_AS_MKDIRAT_RECURSIVE
,
56 RUN_AS_RMDIR_RECURSIVE
,
57 RUN_AS_RMDIRAT_RECURSIVE
,
60 RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
,
61 RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
,
62 RUN_AS_GENERATE_FILTER_BYTECODE
,
68 using run_as_fct
= int (*)(struct run_as_data
*, struct run_as_ret
*);
70 struct run_as_mkdir_data
{
72 char path
[LTTNG_PATH_MAX
];
76 struct run_as_open_data
{
78 char path
[LTTNG_PATH_MAX
];
83 struct run_as_unlink_data
{
85 char path
[LTTNG_PATH_MAX
];
88 struct run_as_rmdir_data
{
90 char path
[LTTNG_PATH_MAX
];
91 int flags
; /* enum lttng_directory_handle_rmdir_recursive_flags. */
94 struct run_as_extract_elf_symbol_offset_data
{
96 char function
[LTTNG_SYMBOL_NAME_LEN
];
99 struct run_as_extract_sdt_probe_offsets_data
{
101 char probe_name
[LTTNG_SYMBOL_NAME_LEN
];
102 char provider_name
[LTTNG_SYMBOL_NAME_LEN
];
105 struct run_as_generate_filter_bytecode_data
{
106 char filter_expression
[LTTNG_FILTER_MAX_LEN
];
109 struct run_as_rename_data
{
115 char old_path
[LTTNG_PATH_MAX
];
116 char new_path
[LTTNG_PATH_MAX
];
119 struct run_as_open_ret
{
123 struct run_as_extract_elf_symbol_offset_ret
{
127 struct run_as_extract_sdt_probe_offsets_ret
{
129 uint64_t offsets
[LTTNG_KERNEL_ABI_MAX_UPROBE_NUM
];
132 struct run_as_generate_filter_bytecode_ret
{
133 /* A lttng_bytecode_filter struct with 'dynamic' payload. */
134 char bytecode
[LTTNG_FILTER_MAX_LEN
];
140 struct run_as_mkdir_data mkdir
;
141 struct run_as_open_data open
;
142 struct run_as_unlink_data unlink
;
143 struct run_as_rmdir_data rmdir
;
144 struct run_as_rename_data rename
;
145 struct run_as_extract_elf_symbol_offset_data extract_elf_symbol_offset
;
146 struct run_as_extract_sdt_probe_offsets_data extract_sdt_probe_offsets
;
147 struct run_as_generate_filter_bytecode_data generate_filter_bytecode
;
154 * The run_as_ret structure holds the returned value and status of the command.
156 * The `u` union field holds the return value of the command; in most cases it
157 * represents the success or the failure of the command. In more complex
158 * commands, it holds a computed value.
160 * The _errno field is the errno recorded after the execution of the command.
162 * The _error fields is used the signify that return status of the command. For
163 * simple commands returning `int` the _error field will be the same as the
164 * ret_int field. In complex commands, it signify the success or failure of the
171 struct run_as_open_ret open
;
172 struct run_as_extract_elf_symbol_offset_ret extract_elf_symbol_offset
;
173 struct run_as_extract_sdt_probe_offsets_ret extract_sdt_probe_offsets
;
174 struct run_as_generate_filter_bytecode_ret generate_filter_bytecode
;
180 #define COMMAND_IN_FDS(data_ptr) \
183 if (command_properties[data_ptr->cmd].in_fds_offset != -1) { \
184 fds = (int *) ((char *) data_ptr + \
185 command_properties[data_ptr->cmd].in_fds_offset); \
190 #define COMMAND_OUT_FDS(cmd, ret_ptr) \
193 if (command_properties[cmd].out_fds_offset != -1) { \
194 fds = (int *) ((char *) ret_ptr + command_properties[cmd].out_fds_offset); \
199 #define COMMAND_IN_FD_COUNT(data_ptr) ({ command_properties[data_ptr->cmd].in_fd_count; })
201 #define COMMAND_OUT_FD_COUNT(cmd) ({ command_properties[cmd].out_fd_count; })
203 #define COMMAND_USE_CWD_FD(data_ptr) command_properties[data_ptr->cmd].use_cwd_fd
205 struct run_as_command_properties
{
206 /* Set to -1 when not applicable. */
207 ptrdiff_t in_fds_offset
, out_fds_offset
;
208 unsigned int in_fd_count
, out_fd_count
;
212 const struct run_as_command_properties command_properties
[] = {
214 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
215 .out_fds_offset
= -1,
221 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
222 .out_fds_offset
= -1,
228 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
229 .out_fds_offset
= -1,
235 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
236 .out_fds_offset
= -1,
242 .in_fds_offset
= offsetof(struct run_as_data
, u
.open
.dirfd
),
243 .out_fds_offset
= offsetof(struct run_as_ret
, u
.open
.fd
),
249 .in_fds_offset
= offsetof(struct run_as_data
, u
.open
.dirfd
),
250 .out_fds_offset
= offsetof(struct run_as_ret
, u
.open
.fd
),
256 .in_fds_offset
= offsetof(struct run_as_data
, u
.unlink
.dirfd
),
257 .out_fds_offset
= -1,
263 .in_fds_offset
= offsetof(struct run_as_data
, u
.unlink
.dirfd
),
264 .out_fds_offset
= -1,
270 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
271 .out_fds_offset
= -1,
277 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
278 .out_fds_offset
= -1,
284 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
285 .out_fds_offset
= -1,
291 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
292 .out_fds_offset
= -1,
298 .in_fds_offset
= offsetof(struct run_as_data
, u
.rename
.dirfds
),
299 .out_fds_offset
= -1,
305 .in_fds_offset
= offsetof(struct run_as_data
, u
.rename
.dirfds
),
306 .out_fds_offset
= -1,
312 .in_fds_offset
= offsetof(struct run_as_data
, u
.extract_elf_symbol_offset
.fd
),
313 .out_fds_offset
= -1,
319 .in_fds_offset
= offsetof(struct run_as_data
, u
.extract_sdt_probe_offsets
.fd
),
320 .out_fds_offset
= -1,
327 .out_fds_offset
= -1,
334 struct run_as_worker_data
{
335 pid_t pid
; /* Worker PID. */
340 /* Single global worker per process (for now). */
341 run_as_worker_data
*global_worker
;
342 /* Lock protecting the worker. */
343 pthread_mutex_t worker_lock
= PTHREAD_MUTEX_INITIALIZER
;
347 static int use_clone(void)
352 static int use_clone(void)
354 return !lttng_secure_getenv("LTTNG_DEBUG_NOCLONE");
359 * Create recursively directory using the FULL path.
361 static int _mkdirat_recursive(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
365 struct lttng_directory_handle
*handle
;
367 path
= data
->u
.mkdir
.path
;
368 mode
= data
->u
.mkdir
.mode
;
370 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.mkdir
.dirfd
);
372 ret_value
->_errno
= errno
;
373 ret_value
->_error
= true;
374 ret_value
->u
.ret
= -1;
377 /* Ownership of dirfd is transferred to the handle. */
378 data
->u
.mkdir
.dirfd
= -1;
379 /* Safe to call as we have transitioned to the requested uid/gid. */
380 ret_value
->u
.ret
= lttng_directory_handle_create_subdirectory_recursive(handle
, path
, mode
);
381 ret_value
->_errno
= errno
;
382 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
383 lttng_directory_handle_put(handle
);
385 return ret_value
->u
.ret
;
388 static int _mkdirat(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
392 struct lttng_directory_handle
*handle
;
394 path
= data
->u
.mkdir
.path
;
395 mode
= data
->u
.mkdir
.mode
;
397 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.mkdir
.dirfd
);
399 ret_value
->u
.ret
= -1;
400 ret_value
->_errno
= errno
;
401 ret_value
->_error
= true;
404 /* Ownership of dirfd is transferred to the handle. */
405 data
->u
.mkdir
.dirfd
= -1;
406 /* Safe to call as we have transitioned to the requested uid/gid. */
407 ret_value
->u
.ret
= lttng_directory_handle_create_subdirectory(handle
, path
, mode
);
408 ret_value
->_errno
= errno
;
409 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
410 lttng_directory_handle_put(handle
);
412 return ret_value
->u
.ret
;
415 static int _open(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
418 struct lttng_directory_handle
*handle
;
420 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.open
.dirfd
);
422 ret_value
->_errno
= errno
;
423 ret_value
->_error
= true;
424 ret_value
->u
.ret
= -1;
427 /* Ownership of dirfd is transferred to the handle. */
428 data
->u
.open
.dirfd
= -1;
430 fd
= lttng_directory_handle_open_file(
431 handle
, data
->u
.open
.path
, data
->u
.open
.flags
, data
->u
.open
.mode
);
433 ret_value
->u
.ret
= -1;
434 ret_value
->u
.open
.fd
= -1;
436 ret_value
->u
.ret
= 0;
437 ret_value
->u
.open
.fd
= fd
;
440 ret_value
->_errno
= errno
;
441 ret_value
->_error
= fd
< 0;
442 lttng_directory_handle_put(handle
);
444 return ret_value
->u
.ret
;
447 static int _unlink(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
449 struct lttng_directory_handle
*handle
;
451 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.unlink
.dirfd
);
453 ret_value
->u
.ret
= -1;
454 ret_value
->_errno
= errno
;
455 ret_value
->_error
= true;
459 /* Ownership of dirfd is transferred to the handle. */
460 data
->u
.unlink
.dirfd
= -1;
462 ret_value
->u
.ret
= lttng_directory_handle_unlink_file(handle
, data
->u
.unlink
.path
);
463 ret_value
->_errno
= errno
;
464 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
465 lttng_directory_handle_put(handle
);
467 return ret_value
->u
.ret
;
470 static int _rmdir(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
472 struct lttng_directory_handle
*handle
;
474 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.rmdir
.dirfd
);
476 ret_value
->u
.ret
= -1;
477 ret_value
->_errno
= errno
;
478 ret_value
->_error
= true;
482 /* Ownership of dirfd is transferred to the handle. */
483 data
->u
.rmdir
.dirfd
= -1;
485 ret_value
->u
.ret
= lttng_directory_handle_remove_subdirectory(handle
, data
->u
.rmdir
.path
);
486 ret_value
->_errno
= errno
;
487 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
488 lttng_directory_handle_put(handle
);
490 return ret_value
->u
.ret
;
493 static int _rmdir_recursive(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
495 struct lttng_directory_handle
*handle
;
497 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.rmdir
.dirfd
);
499 ret_value
->u
.ret
= -1;
500 ret_value
->_errno
= errno
;
501 ret_value
->_error
= true;
505 /* Ownership of dirfd is transferred to the handle. */
506 data
->u
.rmdir
.dirfd
= -1;
508 ret_value
->u
.ret
= lttng_directory_handle_remove_subdirectory_recursive(
509 handle
, data
->u
.rmdir
.path
, data
->u
.rmdir
.flags
);
510 ret_value
->_errno
= errno
;
511 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
512 lttng_directory_handle_put(handle
);
514 return ret_value
->u
.ret
;
517 static int _rename(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
519 const char *old_path
, *new_path
;
520 struct lttng_directory_handle
*old_handle
= NULL
, *new_handle
= NULL
;
522 old_path
= data
->u
.rename
.old_path
;
523 new_path
= data
->u
.rename
.new_path
;
525 old_handle
= lttng_directory_handle_create_from_dirfd(data
->u
.rename
.dirfds
[0]);
527 ret_value
->u
.ret
= -1;
530 new_handle
= lttng_directory_handle_create_from_dirfd(data
->u
.rename
.dirfds
[1]);
532 ret_value
->u
.ret
= -1;
536 /* Ownership of dirfds are transferred to the handles. */
537 data
->u
.rename
.dirfds
[0] = data
->u
.rename
.dirfds
[1] = -1;
539 /* Safe to call as we have transitioned to the requested uid/gid. */
541 lttng_directory_handle_rename(old_handle
, old_path
, new_handle
, new_path
);
543 lttng_directory_handle_put(old_handle
);
544 lttng_directory_handle_put(new_handle
);
545 ret_value
->_errno
= errno
;
546 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
547 return ret_value
->u
.ret
;
551 static int _extract_elf_symbol_offset(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
556 ret_value
->_error
= false;
557 ret
= lttng_elf_get_symbol_offset(data
->u
.extract_elf_symbol_offset
.fd
,
558 data
->u
.extract_elf_symbol_offset
.function
,
561 DBG("Failed to extract ELF function offset");
562 ret_value
->_error
= true;
564 ret_value
->u
.extract_elf_symbol_offset
.offset
= offset
;
569 static int _extract_sdt_probe_offsets(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
572 uint64_t *offsets
= NULL
;
575 ret_value
->_error
= false;
577 /* On success, this call allocates the offsets paramater. */
578 ret
= lttng_elf_get_sdt_probe_offsets(data
->u
.extract_sdt_probe_offsets
.fd
,
579 data
->u
.extract_sdt_probe_offsets
.provider_name
,
580 data
->u
.extract_sdt_probe_offsets
.probe_name
,
585 DBG("Failed to extract SDT probe offsets");
586 ret_value
->_error
= true;
590 if (num_offset
<= 0 || num_offset
> LTTNG_KERNEL_ABI_MAX_UPROBE_NUM
) {
591 DBG("Wrong number of probes.");
593 ret_value
->_error
= true;
597 /* Copy the content of the offsets array to the ret struct. */
598 memcpy(ret_value
->u
.extract_sdt_probe_offsets
.offsets
,
600 num_offset
* sizeof(uint64_t));
602 ret_value
->u
.extract_sdt_probe_offsets
.num_offset
= num_offset
;
610 static int _extract_elf_symbol_offset(struct run_as_data
*data
__attribute__((unused
)),
611 struct run_as_ret
*ret_value
__attribute__((unused
)))
613 ERR("Unimplemented runas command RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET");
617 static int _extract_sdt_probe_offsets(struct run_as_data
*data
__attribute__((unused
)),
618 struct run_as_ret
*ret_value
__attribute__((unused
)))
620 ERR("Unimplemented runas command RUN_AS_EXTRACT_SDT_PROBE_OFFSETS");
625 static int _generate_filter_bytecode(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
628 const char *filter_expression
= NULL
;
629 struct filter_parser_ctx
*ctx
= NULL
;
631 ret_value
->_error
= false;
633 filter_expression
= data
->u
.generate_filter_bytecode
.filter_expression
;
635 if (lttng_strnlen(filter_expression
, LTTNG_FILTER_MAX_LEN
- 1) ==
636 LTTNG_FILTER_MAX_LEN
- 1) {
637 ret_value
->_error
= true;
642 ret
= filter_parser_ctx_create_from_filter_expression(filter_expression
, &ctx
);
644 ret_value
->_error
= true;
649 DBG("Size of bytecode generated: %u bytes.", bytecode_get_len(&ctx
->bytecode
->b
));
651 /* Copy the lttng_bytecode_filter object to the return structure. */
652 memcpy(ret_value
->u
.generate_filter_bytecode
.bytecode
,
654 sizeof(ctx
->bytecode
->b
) + bytecode_get_len(&ctx
->bytecode
->b
));
658 filter_bytecode_free(ctx
);
660 filter_parser_ctx_free(ctx
);
665 static run_as_fct
run_as_enum_to_fct(enum run_as_cmd cmd
)
671 case RUN_AS_MKDIR_RECURSIVE
:
672 case RUN_AS_MKDIRAT_RECURSIVE
:
673 return _mkdirat_recursive
;
678 case RUN_AS_UNLINKAT
:
683 case RUN_AS_RMDIR_RECURSIVE
:
684 case RUN_AS_RMDIRAT_RECURSIVE
:
685 return _rmdir_recursive
;
687 case RUN_AS_RENAMEAT
:
689 case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
:
690 return _extract_elf_symbol_offset
;
691 case RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
:
692 return _extract_sdt_probe_offsets
;
693 case RUN_AS_GENERATE_FILTER_BYTECODE
:
694 return _generate_filter_bytecode
;
696 ERR("Unknown command %d", (int) cmd
);
701 static int do_send_fds(int sock
, const int *fds
, unsigned int fd_count
)
706 for (i
= 0; i
< fd_count
; i
++) {
708 DBG("Attempt to send invalid file descriptor (fd = %i)", fds
[i
]);
709 /* Return 0 as this is not a fatal error. */
714 len
= lttcomm_send_fds_unix_sock(sock
, fds
, fd_count
);
715 return len
< 0 ? -1 : 0;
718 static int do_recv_fds(int sock
, int *fds
, unsigned int fd_count
)
724 len
= lttcomm_recv_fds_unix_sock(sock
, fds
, fd_count
);
728 } else if (len
< 0) {
729 PERROR("Failed to receive file descriptors from socket");
734 for (i
= 0; i
< fd_count
; i
++) {
736 ERR("Invalid file descriptor received from worker (fd = %i)", fds
[i
]);
737 /* Return 0 as this is not a fatal error. */
744 static int send_fds_to_worker(const run_as_worker_data
*worker
, const struct run_as_data
*data
)
749 if (COMMAND_USE_CWD_FD(data
) || COMMAND_IN_FD_COUNT(data
) == 0) {
753 for (i
= 0; i
< COMMAND_IN_FD_COUNT(data
); i
++) {
754 if (COMMAND_IN_FDS(data
)[i
] < 0) {
755 ERR("Refusing to send invalid fd to worker (fd = %i)",
756 COMMAND_IN_FDS(data
)[i
]);
762 ret
= do_send_fds(worker
->sockpair
[0], COMMAND_IN_FDS(data
), COMMAND_IN_FD_COUNT(data
));
764 PERROR("Failed to send file descriptor to run-as worker");
773 send_fds_to_master(run_as_worker_data
*worker
, enum run_as_cmd cmd
, struct run_as_ret
*run_as_ret
)
778 if (COMMAND_OUT_FD_COUNT(cmd
) == 0) {
783 worker
->sockpair
[1], COMMAND_OUT_FDS(cmd
, run_as_ret
), COMMAND_OUT_FD_COUNT(cmd
));
785 PERROR("Failed to send file descriptor to master process");
789 for (i
= 0; i
< COMMAND_OUT_FD_COUNT(cmd
); i
++) {
790 int fd
= COMMAND_OUT_FDS(cmd
, run_as_ret
)[i
];
792 int ret_close
= close(fd
);
795 PERROR("Failed to close result file descriptor (fd = %i)", fd
);
803 static int recv_fds_from_worker(const run_as_worker_data
*worker
,
805 struct run_as_ret
*run_as_ret
)
809 if (COMMAND_OUT_FD_COUNT(cmd
) == 0) {
814 worker
->sockpair
[0], COMMAND_OUT_FDS(cmd
, run_as_ret
), COMMAND_OUT_FD_COUNT(cmd
));
816 PERROR("Failed to receive file descriptor from run-as worker");
823 static int recv_fds_from_master(run_as_worker_data
*worker
, struct run_as_data
*data
)
827 if (COMMAND_USE_CWD_FD(data
)) {
830 for (i
= 0; i
< COMMAND_IN_FD_COUNT(data
); i
++) {
831 COMMAND_IN_FDS(data
)[i
] = AT_FDCWD
;
836 if (COMMAND_IN_FD_COUNT(data
) == 0) {
840 ret
= do_recv_fds(worker
->sockpair
[1], COMMAND_IN_FDS(data
), COMMAND_IN_FD_COUNT(data
));
842 PERROR("Failed to receive file descriptors from master process");
849 static int cleanup_received_fds(struct run_as_data
*data
)
853 for (i
= 0; i
< COMMAND_IN_FD_COUNT(data
); i
++) {
854 if (COMMAND_IN_FDS(data
)[i
] == -1) {
857 ret
= close(COMMAND_IN_FDS(data
)[i
]);
859 PERROR("Failed to close file descriptor received fd in run-as worker");
867 static int get_user_infos_from_uid(uid_t uid
, char **username
, gid_t
*primary_gid
)
871 long raw_get_pw_buf_size
;
872 size_t get_pw_buf_size
;
874 struct passwd
*result
= NULL
;
876 /* Fetch the max size for the temporary buffer. */
878 raw_get_pw_buf_size
= sysconf(_SC_GETPW_R_SIZE_MAX
);
879 if (raw_get_pw_buf_size
< 0) {
881 PERROR("Failed to query _SC_GETPW_R_SIZE_MAX");
885 /* Limit is indeterminate. */
886 WARN("Failed to query _SC_GETPW_R_SIZE_MAX as it is "
887 "indeterminate; falling back to default buffer size");
888 raw_get_pw_buf_size
= GETPW_BUFFER_FALLBACK_SIZE
;
891 get_pw_buf_size
= (size_t) raw_get_pw_buf_size
;
893 buf
= calloc
<char>(get_pw_buf_size
);
895 PERROR("Failed to allocate buffer to get password file entries");
899 ret
= getpwuid_r(uid
, &pwd
, buf
, get_pw_buf_size
, &result
);
901 PERROR("Failed to get user information for user: uid = %d", (int) uid
);
905 if (result
== NULL
) {
906 ERR("Failed to find user information in password entries: uid = %d", (int) uid
);
911 *username
= strdup(result
->pw_name
);
912 if (*username
== NULL
) {
913 PERROR("Failed to copy user name");
917 *primary_gid
= result
->pw_gid
;
929 static int demote_creds(uid_t prev_uid
, gid_t prev_gid
, uid_t new_uid
, gid_t new_gid
)
933 char *username
= NULL
;
935 /* Change the group id. */
936 if (prev_gid
!= new_gid
) {
937 ret
= setegid(new_gid
);
939 PERROR("Failed to set effective group id: new_gid = %d", (int) new_gid
);
944 /* Change the user id. */
945 if (prev_uid
!= new_uid
) {
946 ret
= get_user_infos_from_uid(new_uid
, &username
, &primary_gid
);
952 * Initialize the supplementary group access list.
954 * This is needed to handle cases where the supplementary groups
955 * of the user the process is demoting-to would give it access
956 * to a given file/folder, but not it's primary group.
960 * Primary Group: User1
961 * Secondary group: Disk, Network
963 * mkdir inside the following directory must work since User1
964 * is part of the Network group.
966 * drwxrwx--- 2 root Network 4096 Jul 23 17:17 /tmp/my_folder/
969 * The order of the following initgroups and seteuid calls is
971 * Only a root process or one with CAP_SETGID capability can
972 * call the the initgroups() function. We must initialize the
973 * supplementary groups before we change the effective
974 * UID to a less-privileged user.
976 ret
= initgroups(username
, primary_gid
);
978 PERROR("Failed to init the supplementary group access list: "
979 "username = `%s`, primary gid = %d",
985 ret
= seteuid(new_uid
);
987 PERROR("Failed to set effective user id: new_uid = %d", (int) new_uid
);
996 static int promote_creds(uid_t prev_uid
, gid_t prev_gid
, uid_t new_uid
, gid_t new_gid
)
1000 char *username
= NULL
;
1002 /* Change the group id. */
1003 if (prev_gid
!= new_gid
) {
1004 ret
= setegid(new_gid
);
1006 PERROR("Failed to set effective group id: new_gid = %d", (int) new_gid
);
1011 /* Change the user id. */
1012 if (prev_uid
!= new_uid
) {
1013 ret
= get_user_infos_from_uid(new_uid
, &username
, &primary_gid
);
1019 * seteuid call must be done before the initgroups call because
1020 * we need to be privileged (CAP_SETGID) to call initgroups().
1022 ret
= seteuid(new_uid
);
1024 PERROR("Failed to set effective user id: new_uid = %d", (int) new_uid
);
1029 * Initialize the supplementary group access list.
1031 * There is a possibility the groups we set in the following
1032 * initgroups() call are not exactly the same as the ones we
1033 * had when we originally demoted. This can happen if the
1034 * /etc/group file is modified after the runas process is
1035 * forked. This is very unlikely.
1037 ret
= initgroups(username
, primary_gid
);
1039 PERROR("Failed to init the supplementary group access "
1040 "list: username = `%s`, primary gid = %d",
1052 * Return < 0 on error, 0 if OK, 1 on hangup.
1054 static int handle_one_cmd(run_as_worker_data
*worker
)
1056 int ret
= 0, promote_ret
;
1057 struct run_as_data data
= {};
1058 ssize_t readlen
, writelen
;
1059 struct run_as_ret sendret
= {};
1061 const uid_t prev_ruid
= getuid();
1062 const gid_t prev_rgid
= getgid();
1065 * Stage 1: Receive run_as_data struct from the master.
1066 * The structure contains the command type and all the parameters needed for
1069 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[1], &data
, sizeof(data
));
1075 if (readlen
< sizeof(data
)) {
1076 PERROR("lttcomm_recv_unix_sock error");
1081 cmd
= run_as_enum_to_fct(data
.cmd
);
1088 * Stage 2: Receive file descriptor from master.
1089 * Some commands need a file descriptor as input so if it's needed we
1090 * receive the fd using the Unix socket.
1092 ret
= recv_fds_from_master(worker
, &data
);
1094 PERROR("recv_fd_from_master error");
1099 ret
= demote_creds(prev_ruid
, prev_rgid
, data
.uid
, data
.gid
);
1105 * Also set umask to 0 for mkdir executable bit.
1110 * Stage 3: Execute the command
1112 ret
= (*cmd
)(&data
, &sendret
);
1114 DBG("Execution of command returned an error");
1118 ret
= cleanup_received_fds(&data
);
1120 ERR("Error cleaning up FD");
1125 * Stage 4: Send run_as_ret structure to the master.
1126 * This structure contain the return value of the command and the errno.
1128 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[1], &sendret
, sizeof(sendret
));
1129 if (writelen
< sizeof(sendret
)) {
1130 PERROR("lttcomm_send_unix_sock error");
1136 * Stage 5: Send resulting file descriptors to the master.
1138 ret
= send_fds_to_master(worker
, data
.cmd
, &sendret
);
1140 DBG("Sending FD to master returned an error");
1146 /* Return to previous uid/gid. */
1147 promote_ret
= promote_creds(data
.uid
, data
.gid
, prev_ruid
, prev_rgid
);
1148 if (promote_ret
< 0) {
1149 ERR("Failed to promote back to the initial credentials");
1156 static int run_as_worker(run_as_worker_data
*worker
)
1160 struct run_as_ret sendret
;
1161 size_t proc_orig_len
;
1164 * Initialize worker. Set a different process cmdline.
1166 proc_orig_len
= strlen(worker
->procname
);
1167 memset(worker
->procname
, 0, proc_orig_len
);
1168 strncpy(worker
->procname
, DEFAULT_RUN_AS_WORKER_NAME
, proc_orig_len
);
1170 ret
= lttng_thread_setname(DEFAULT_RUN_AS_WORKER_NAME
);
1171 if (ret
&& ret
!= -ENOSYS
) {
1172 /* Don't fail as this is not essential. */
1173 DBG("Failed to set pthread name attribute");
1176 memset(&sendret
, 0, sizeof(sendret
));
1178 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[1], &sendret
, sizeof(sendret
));
1179 if (writelen
< sizeof(sendret
)) {
1180 PERROR("lttcomm_send_unix_sock error");
1186 ret
= handle_one_cmd(worker
);
1190 } else if (ret
> 0) {
1193 continue; /* Next command. */
1201 static int run_as_cmd(run_as_worker_data
*worker
,
1202 enum run_as_cmd cmd
,
1203 struct run_as_data
*data
,
1204 struct run_as_ret
*ret_value
,
1209 ssize_t readlen
, writelen
;
1212 * If we are non-root, we can only deal with our own uid.
1214 if (geteuid() != 0) {
1215 if (uid
!= geteuid()) {
1217 ret_value
->_errno
= EPERM
;
1218 ERR("Client (%d)/Server (%d) UID mismatch (and sessiond is not root)",
1230 * Stage 1: Send the run_as_data struct to the worker process
1232 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[0], data
, sizeof(*data
));
1233 if (writelen
< sizeof(*data
)) {
1234 PERROR("Error writing message to run_as");
1236 ret_value
->_errno
= EIO
;
1241 * Stage 2: Send file descriptor to the worker process if needed
1243 ret
= send_fds_to_worker(worker
, data
);
1245 PERROR("do_send_fd error");
1247 ret_value
->_errno
= EIO
;
1252 * Stage 3: Wait for the execution of the command
1256 * Stage 4: Receive the run_as_ret struct containing the return value and
1259 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[0], ret_value
, sizeof(*ret_value
));
1261 ERR("Run-as worker has hung-up during run_as_cmd");
1263 ret_value
->_errno
= EIO
;
1265 } else if (readlen
< sizeof(*ret_value
)) {
1266 PERROR("Error reading response from run_as");
1268 ret_value
->_errno
= errno
;
1272 if (ret_value
->_error
) {
1273 /* Skip stage 5 on error as there will be no fd to receive. */
1278 * Stage 5: Receive file descriptor if needed
1280 ret
= recv_fds_from_worker(worker
, cmd
, ret_value
);
1282 ERR("Error receiving fd");
1284 ret_value
->_errno
= EIO
;
1292 * This is for debugging ONLY and should not be considered secure.
1294 static int run_as_noworker(enum run_as_cmd cmd
,
1295 struct run_as_data
*data
,
1296 struct run_as_ret
*ret_value
,
1297 uid_t uid
__attribute__((unused
)),
1298 gid_t gid
__attribute__((unused
)))
1300 int ret
, saved_errno
;
1304 fct
= run_as_enum_to_fct(cmd
);
1310 old_mask
= umask(0);
1311 ret
= fct(data
, ret_value
);
1312 saved_errno
= ret_value
->_errno
;
1314 errno
= saved_errno
;
1319 static int reset_sighandler(void)
1323 DBG("Resetting run_as worker signal handlers to default");
1324 for (sig
= 1; sig
<= 31; sig
++) {
1325 (void) signal(sig
, SIG_DFL
);
1330 static void worker_sighandler(int sig
)
1332 const char *signame
;
1335 * The worker will inherit its parent's signals since they are part of
1336 * the same process group. However, in the case of SIGINT and SIGTERM,
1337 * we want to give the worker a chance to teardown gracefully when its
1338 * parent closes the command socket.
1345 signame
= "SIGTERM";
1352 DBG("run_as worker received signal %s", signame
);
1354 DBG("run_as_worker received signal %d", sig
);
1358 static int set_worker_sighandlers(void)
1362 struct sigaction sa
;
1364 if ((ret
= sigemptyset(&sigset
)) < 0) {
1365 PERROR("sigemptyset");
1369 sa
.sa_handler
= worker_sighandler
;
1370 sa
.sa_mask
= sigset
;
1372 if ((ret
= sigaction(SIGINT
, &sa
, NULL
)) < 0) {
1373 PERROR("sigaction SIGINT");
1377 if ((ret
= sigaction(SIGTERM
, &sa
, NULL
)) < 0) {
1378 PERROR("sigaction SIGTERM");
1382 DBG("run_as signal handler set for SIGTERM and SIGINT");
1387 static int run_as_create_worker_no_lock(const char *procname
,
1388 post_fork_cleanup_cb clean_up_func
,
1389 void *clean_up_user_data
)
1394 struct run_as_ret recvret
;
1395 run_as_worker_data
*worker
;
1397 LTTNG_ASSERT(!global_worker
);
1400 * Don't initialize a worker, all run_as tasks will be performed
1401 * in the current process.
1406 worker
= zmalloc
<run_as_worker_data
>();
1411 worker
->procname
= strdup(procname
);
1412 if (!worker
->procname
) {
1414 goto error_procname_alloc
;
1416 /* Create unix socket. */
1417 if (lttcomm_create_anon_unix_socketpair(worker
->sockpair
) < 0) {
1428 } else if (pid
== 0) {
1433 set_worker_sighandlers();
1435 logger_set_thread_name("Run-as worker", true);
1437 if (clean_up_func
) {
1438 if (clean_up_func(clean_up_user_data
) < 0) {
1439 ERR("Run-as post-fork clean-up failed, exiting.");
1444 /* Just close, no shutdown. */
1445 if (close(worker
->sockpair
[0])) {
1451 * Close all FDs aside from STDIN, STDOUT, STDERR and sockpair[1]
1452 * Sockpair[1] is used as a control channel with the master
1454 for (i
= 3; i
< sysconf(_SC_OPEN_MAX
); i
++) {
1455 if (i
!= worker
->sockpair
[1]) {
1460 worker
->sockpair
[0] = -1;
1461 ret
= run_as_worker(worker
);
1462 if (lttcomm_close_unix_sock(worker
->sockpair
[1])) {
1466 worker
->sockpair
[1] = -1;
1467 free(worker
->procname
);
1469 LOG(ret
? PRINT_ERR
: PRINT_DBG
, "run_as worker exiting (ret = %d)", ret
);
1470 exit(ret
? EXIT_FAILURE
: EXIT_SUCCESS
);
1474 /* Just close, no shutdown. */
1475 if (close(worker
->sockpair
[1])) {
1480 worker
->sockpair
[1] = -1;
1482 /* Wait for worker to become ready. */
1483 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[0], &recvret
, sizeof(recvret
));
1484 if (readlen
< sizeof(recvret
)) {
1485 ERR("readlen: %zd", readlen
);
1486 PERROR("Error reading response from run_as at creation");
1490 global_worker
= worker
;
1495 /* Error handling. */
1497 for (i
= 0; i
< 2; i
++) {
1498 if (worker
->sockpair
[i
] < 0) {
1501 if (lttcomm_close_unix_sock(worker
->sockpair
[i
])) {
1504 worker
->sockpair
[i
] = -1;
1507 free(worker
->procname
);
1508 error_procname_alloc
:
1513 static void run_as_destroy_worker_no_lock(void)
1515 run_as_worker_data
*worker
= global_worker
;
1517 DBG("Destroying run_as worker");
1521 /* Close unix socket */
1522 DBG("Closing run_as worker socket");
1523 if (lttcomm_close_unix_sock(worker
->sockpair
[0])) {
1526 worker
->sockpair
[0] = -1;
1527 /* Wait for worker. */
1532 wait_ret
= waitpid(worker
->pid
, &status
, 0);
1534 if (errno
== EINTR
) {
1541 if (WIFEXITED(status
)) {
1542 LOG(WEXITSTATUS(status
) == 0 ? PRINT_DBG
: PRINT_ERR
,
1543 DEFAULT_RUN_AS_WORKER_NAME
" terminated with status code %d",
1544 WEXITSTATUS(status
));
1546 } else if (WIFSIGNALED(status
)) {
1547 ERR(DEFAULT_RUN_AS_WORKER_NAME
" was killed by signal %d",
1552 free(worker
->procname
);
1554 global_worker
= NULL
;
1557 static int run_as_restart_worker(run_as_worker_data
*worker
)
1560 char *procname
= NULL
;
1562 procname
= worker
->procname
;
1564 /* Close socket to run_as worker process and clean up the zombie process */
1565 run_as_destroy_worker_no_lock();
1567 /* Create a new run_as worker process*/
1568 ret
= run_as_create_worker_no_lock(procname
, NULL
, NULL
);
1570 ERR("Restarting the worker process failed");
1578 static int run_as(enum run_as_cmd cmd
,
1579 struct run_as_data
*data
,
1580 struct run_as_ret
*ret_value
,
1584 int ret
, saved_errno
;
1586 pthread_mutex_lock(&worker_lock
);
1588 DBG("Using run_as worker");
1590 LTTNG_ASSERT(global_worker
);
1592 ret
= run_as_cmd(global_worker
, cmd
, data
, ret_value
, uid
, gid
);
1593 saved_errno
= ret_value
->_errno
;
1596 * If the worker thread crashed the errno is set to EIO. we log
1597 * the error and start a new worker process.
1599 if (ret
== -1 && saved_errno
== EIO
) {
1600 DBG("Socket closed unexpectedly... "
1601 "Restarting the worker process");
1602 ret
= run_as_restart_worker(global_worker
);
1604 ERR("Failed to restart worker process.");
1609 DBG("Using run_as without worker");
1610 ret
= run_as_noworker(cmd
, data
, ret_value
, uid
, gid
);
1613 pthread_mutex_unlock(&worker_lock
);
1617 int run_as_mkdir_recursive(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
1619 return run_as_mkdirat_recursive(AT_FDCWD
, path
, mode
, uid
, gid
);
1622 int run_as_mkdirat_recursive(int dirfd
, const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
1625 struct run_as_data data
= {};
1626 struct run_as_ret run_as_ret
= {};
1628 DBG3("mkdirat() recursive fd = %d%s, path = %s, mode = %d, uid = %d, gid = %d",
1630 dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1635 ret
= lttng_strncpy(data
.u
.mkdir
.path
, path
, sizeof(data
.u
.mkdir
.path
));
1637 ERR("Failed to copy path argument of mkdirat recursive command");
1640 data
.u
.mkdir
.path
[sizeof(data
.u
.mkdir
.path
) - 1] = '\0';
1641 data
.u
.mkdir
.mode
= mode
;
1642 data
.u
.mkdir
.dirfd
= dirfd
;
1643 run_as(dirfd
== AT_FDCWD
? RUN_AS_MKDIR_RECURSIVE
: RUN_AS_MKDIRAT_RECURSIVE
,
1648 errno
= run_as_ret
._errno
;
1649 ret
= run_as_ret
.u
.ret
;
1654 int run_as_mkdir(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
1656 return run_as_mkdirat(AT_FDCWD
, path
, mode
, uid
, gid
);
1659 int run_as_mkdirat(int dirfd
, const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
1662 struct run_as_data data
= {};
1663 struct run_as_ret run_as_ret
= {};
1665 DBG3("mkdirat() recursive fd = %d%s, path = %s, mode = %d, uid = %d, gid = %d",
1667 dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1672 ret
= lttng_strncpy(data
.u
.mkdir
.path
, path
, sizeof(data
.u
.mkdir
.path
));
1674 ERR("Failed to copy path argument of mkdirat command");
1677 data
.u
.mkdir
.path
[sizeof(data
.u
.mkdir
.path
) - 1] = '\0';
1678 data
.u
.mkdir
.mode
= mode
;
1679 data
.u
.mkdir
.dirfd
= dirfd
;
1680 run_as(dirfd
== AT_FDCWD
? RUN_AS_MKDIR
: RUN_AS_MKDIRAT
, &data
, &run_as_ret
, uid
, gid
);
1681 errno
= run_as_ret
._errno
;
1682 ret
= run_as_ret
.u
.ret
;
1687 int run_as_open(const char *path
, int flags
, mode_t mode
, uid_t uid
, gid_t gid
)
1689 return run_as_openat(AT_FDCWD
, path
, flags
, mode
, uid
, gid
);
1692 int run_as_openat(int dirfd
, const char *path
, int flags
, mode_t mode
, uid_t uid
, gid_t gid
)
1695 struct run_as_data data
= {};
1696 struct run_as_ret run_as_ret
= {};
1698 DBG3("openat() fd = %d%s, path = %s, flags = %X, mode = %d, uid %d, gid %d",
1700 dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1706 ret
= lttng_strncpy(data
.u
.open
.path
, path
, sizeof(data
.u
.open
.path
));
1708 ERR("Failed to copy path argument of open command");
1711 data
.u
.open
.flags
= flags
;
1712 data
.u
.open
.mode
= mode
;
1713 data
.u
.open
.dirfd
= dirfd
;
1714 run_as(dirfd
== AT_FDCWD
? RUN_AS_OPEN
: RUN_AS_OPENAT
, &data
, &run_as_ret
, uid
, gid
);
1715 errno
= run_as_ret
._errno
;
1716 ret
= run_as_ret
.u
.ret
< 0 ? run_as_ret
.u
.ret
: run_as_ret
.u
.open
.fd
;
1721 int run_as_unlink(const char *path
, uid_t uid
, gid_t gid
)
1723 return run_as_unlinkat(AT_FDCWD
, path
, uid
, gid
);
1726 int run_as_unlinkat(int dirfd
, const char *path
, uid_t uid
, gid_t gid
)
1729 struct run_as_data data
= {};
1730 struct run_as_ret run_as_ret
= {};
1732 DBG3("unlinkat() fd = %d%s, path = %s, uid = %d, gid = %d",
1734 dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1738 ret
= lttng_strncpy(data
.u
.unlink
.path
, path
, sizeof(data
.u
.unlink
.path
));
1742 data
.u
.unlink
.dirfd
= dirfd
;
1743 run_as(dirfd
== AT_FDCWD
? RUN_AS_UNLINK
: RUN_AS_UNLINKAT
, &data
, &run_as_ret
, uid
, gid
);
1744 errno
= run_as_ret
._errno
;
1745 ret
= run_as_ret
.u
.ret
;
1750 int run_as_rmdir(const char *path
, uid_t uid
, gid_t gid
)
1752 return run_as_rmdirat(AT_FDCWD
, path
, uid
, gid
);
1755 int run_as_rmdirat(int dirfd
, const char *path
, uid_t uid
, gid_t gid
)
1758 struct run_as_data data
= {};
1759 struct run_as_ret run_as_ret
= {};
1761 DBG3("rmdirat() fd = %d%s, path = %s, uid = %d, gid = %d",
1763 dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1767 ret
= lttng_strncpy(data
.u
.rmdir
.path
, path
, sizeof(data
.u
.rmdir
.path
));
1771 data
.u
.rmdir
.dirfd
= dirfd
;
1772 run_as(dirfd
== AT_FDCWD
? RUN_AS_RMDIR
: RUN_AS_RMDIRAT
, &data
, &run_as_ret
, uid
, gid
);
1773 errno
= run_as_ret
._errno
;
1774 ret
= run_as_ret
.u
.ret
;
1779 int run_as_rmdir_recursive(const char *path
, uid_t uid
, gid_t gid
, int flags
)
1781 return run_as_rmdirat_recursive(AT_FDCWD
, path
, uid
, gid
, flags
);
1784 int run_as_rmdirat_recursive(int dirfd
, const char *path
, uid_t uid
, gid_t gid
, int flags
)
1787 struct run_as_data data
= {};
1788 struct run_as_ret run_as_ret
= {};
1790 DBG3("rmdirat() recursive fd = %d%s, path = %s, uid = %d, gid = %d",
1792 dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1796 ret
= lttng_strncpy(data
.u
.rmdir
.path
, path
, sizeof(data
.u
.rmdir
.path
));
1800 data
.u
.rmdir
.dirfd
= dirfd
;
1801 data
.u
.rmdir
.flags
= flags
;
1802 run_as(dirfd
== AT_FDCWD
? RUN_AS_RMDIR_RECURSIVE
: RUN_AS_RMDIRAT_RECURSIVE
,
1807 errno
= run_as_ret
._errno
;
1808 ret
= run_as_ret
.u
.ret
;
1813 int run_as_rename(const char *old_name
, const char *new_name
, uid_t uid
, gid_t gid
)
1815 return run_as_renameat(AT_FDCWD
, old_name
, AT_FDCWD
, new_name
, uid
, gid
);
1818 int run_as_renameat(int old_dirfd
,
1819 const char *old_name
,
1821 const char *new_name
,
1826 struct run_as_data data
= {};
1827 struct run_as_ret run_as_ret
= {};
1829 DBG3("renameat() old_dirfd = %d%s, old_name = %s, new_dirfd = %d%s, new_name = %s, uid = %d, gid = %d",
1831 old_dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1834 new_dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1838 ret
= lttng_strncpy(data
.u
.rename
.old_path
, old_name
, sizeof(data
.u
.rename
.old_path
));
1842 ret
= lttng_strncpy(data
.u
.rename
.new_path
, new_name
, sizeof(data
.u
.rename
.new_path
));
1847 data
.u
.rename
.dirfds
[0] = old_dirfd
;
1848 data
.u
.rename
.dirfds
[1] = new_dirfd
;
1849 run_as(old_dirfd
== AT_FDCWD
&& new_dirfd
== AT_FDCWD
? RUN_AS_RENAME
: RUN_AS_RENAMEAT
,
1854 errno
= run_as_ret
._errno
;
1855 ret
= run_as_ret
.u
.ret
;
1860 int run_as_extract_elf_symbol_offset(
1861 int fd
, const char *function
, uid_t uid
, gid_t gid
, uint64_t *offset
)
1864 struct run_as_data data
= {};
1865 struct run_as_ret run_as_ret
= {};
1867 DBG3("extract_elf_symbol_offset() on fd=%d and function=%s "
1868 "with for uid %d and gid %d",
1874 data
.u
.extract_elf_symbol_offset
.fd
= fd
;
1876 strncpy(data
.u
.extract_elf_symbol_offset
.function
, function
, LTTNG_SYMBOL_NAME_LEN
- 1);
1877 data
.u
.extract_elf_symbol_offset
.function
[LTTNG_SYMBOL_NAME_LEN
- 1] = '\0';
1878 ret
= lttng_strncpy(data
.u
.extract_elf_symbol_offset
.function
,
1880 sizeof(data
.u
.extract_elf_symbol_offset
.function
));
1885 run_as(RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
, &data
, &run_as_ret
, uid
, gid
);
1886 errno
= run_as_ret
._errno
;
1887 if (run_as_ret
._error
) {
1892 *offset
= run_as_ret
.u
.extract_elf_symbol_offset
.offset
;
1897 int run_as_extract_sdt_probe_offsets(int fd
,
1898 const char *provider_name
,
1899 const char *probe_name
,
1903 uint32_t *num_offset
)
1906 struct run_as_data data
= {};
1907 struct run_as_ret run_as_ret
= {};
1909 DBG3("extract_sdt_probe_offsets() on fd=%d, probe_name=%s and "
1910 "provider_name=%s with for uid %d and gid %d",
1917 data
.u
.extract_sdt_probe_offsets
.fd
= fd
;
1919 ret
= lttng_strncpy(data
.u
.extract_sdt_probe_offsets
.probe_name
,
1921 sizeof(data
.u
.extract_sdt_probe_offsets
.probe_name
));
1925 ret
= lttng_strncpy(data
.u
.extract_sdt_probe_offsets
.provider_name
,
1927 sizeof(data
.u
.extract_sdt_probe_offsets
.provider_name
));
1932 run_as(RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
, &data
, &run_as_ret
, uid
, gid
);
1933 errno
= run_as_ret
._errno
;
1934 if (run_as_ret
._error
) {
1939 *num_offset
= run_as_ret
.u
.extract_sdt_probe_offsets
.num_offset
;
1940 *offsets
= calloc
<uint64_t>(*num_offset
);
1947 run_as_ret
.u
.extract_sdt_probe_offsets
.offsets
,
1948 *num_offset
* sizeof(uint64_t));
1953 int run_as_generate_filter_bytecode(const char *filter_expression
,
1954 const struct lttng_credentials
*creds
,
1955 struct lttng_bytecode
**bytecode
)
1958 struct run_as_data data
= {};
1959 struct run_as_ret run_as_ret
= {};
1960 const struct lttng_bytecode
*view_bytecode
= NULL
;
1961 struct lttng_bytecode
*local_bytecode
= NULL
;
1962 const uid_t uid
= lttng_credentials_get_uid(creds
);
1963 const gid_t gid
= lttng_credentials_get_gid(creds
);
1965 DBG3("generate_filter_bytecode() from expression=\"%s\" for uid %d and gid %d",
1970 ret
= lttng_strncpy(data
.u
.generate_filter_bytecode
.filter_expression
,
1972 sizeof(data
.u
.generate_filter_bytecode
.filter_expression
));
1977 run_as(RUN_AS_GENERATE_FILTER_BYTECODE
, &data
, &run_as_ret
, uid
, gid
);
1978 errno
= run_as_ret
._errno
;
1979 if (run_as_ret
._error
) {
1985 (const struct lttng_bytecode
*) run_as_ret
.u
.generate_filter_bytecode
.bytecode
;
1987 local_bytecode
= calloc
<lttng_bytecode
>(view_bytecode
->len
);
1988 if (!local_bytecode
) {
1993 memcpy(local_bytecode
,
1994 run_as_ret
.u
.generate_filter_bytecode
.bytecode
,
1995 sizeof(*local_bytecode
) + view_bytecode
->len
);
1996 *bytecode
= local_bytecode
;
2001 int run_as_create_worker(const char *procname
,
2002 post_fork_cleanup_cb clean_up_func
,
2003 void *clean_up_user_data
)
2007 pthread_mutex_lock(&worker_lock
);
2008 ret
= run_as_create_worker_no_lock(procname
, clean_up_func
, clean_up_user_data
);
2009 pthread_mutex_unlock(&worker_lock
);
2013 void run_as_destroy_worker(void)
2015 pthread_mutex_lock(&worker_lock
);
2016 run_as_destroy_worker_no_lock();
2017 pthread_mutex_unlock(&worker_lock
);