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
22 #include <sys/types.h>
26 #include <common/bytecode/bytecode.h>
27 #include <common/lttng-kernel.h>
28 #include <common/common.h>
29 #include <common/utils.h>
30 #include <common/compat/errno.h>
31 #include <common/compat/getenv.h>
32 #include <common/compat/string.h>
33 #include <common/unix.h>
34 #include <common/defaults.h>
35 #include <common/lttng-elf.h>
36 #include <common/thread.h>
38 #include <lttng/constant.h>
40 #include <common/sessiond-comm/sessiond-comm.h>
41 #include <common/filter/filter-ast.h>
45 #define GETPW_BUFFER_FALLBACK_SIZE 4096
49 typedef int (*run_as_fct
)(struct run_as_data
*data
, struct run_as_ret
*ret_value
);
54 RUN_AS_MKDIR_RECURSIVE
,
55 RUN_AS_MKDIRAT_RECURSIVE
,
62 RUN_AS_RMDIR_RECURSIVE
,
63 RUN_AS_RMDIRAT_RECURSIVE
,
66 RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
,
67 RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
,
68 RUN_AS_GENERATE_FILTER_BYTECODE
,
71 struct run_as_mkdir_data
{
73 char path
[LTTNG_PATH_MAX
];
77 struct run_as_open_data
{
79 char path
[LTTNG_PATH_MAX
];
84 struct run_as_unlink_data
{
86 char path
[LTTNG_PATH_MAX
];
89 struct run_as_rmdir_data
{
91 char path
[LTTNG_PATH_MAX
];
92 int flags
; /* enum lttng_directory_handle_rmdir_recursive_flags. */
95 struct run_as_extract_elf_symbol_offset_data
{
97 char function
[LTTNG_SYMBOL_NAME_LEN
];
100 struct run_as_extract_sdt_probe_offsets_data
{
102 char probe_name
[LTTNG_SYMBOL_NAME_LEN
];
103 char provider_name
[LTTNG_SYMBOL_NAME_LEN
];
106 struct run_as_generate_filter_bytecode_data
{
107 char filter_expression
[LTTNG_FILTER_MAX_LEN
];
110 struct run_as_rename_data
{
116 char old_path
[LTTNG_PATH_MAX
];
117 char new_path
[LTTNG_PATH_MAX
];
120 struct run_as_open_ret
{
124 struct run_as_extract_elf_symbol_offset_ret
{
128 struct run_as_extract_sdt_probe_offsets_ret
{
130 uint64_t offsets
[LTTNG_KERNEL_ABI_MAX_UPROBE_NUM
];
133 struct run_as_generate_filter_bytecode_ret
{
134 /* A lttng_bytecode_filter struct with 'dynamic' payload. */
135 char bytecode
[LTTNG_FILTER_MAX_LEN
];
141 struct run_as_mkdir_data mkdir
;
142 struct run_as_open_data open
;
143 struct run_as_unlink_data unlink
;
144 struct run_as_rmdir_data rmdir
;
145 struct run_as_rename_data rename
;
146 struct run_as_extract_elf_symbol_offset_data extract_elf_symbol_offset
;
147 struct run_as_extract_sdt_probe_offsets_data extract_sdt_probe_offsets
;
148 struct run_as_generate_filter_bytecode_data generate_filter_bytecode
;
155 * The run_as_ret structure holds the returned value and status of the command.
157 * The `u` union field holds the return value of the command; in most cases it
158 * represents the success or the failure of the command. In more complex
159 * commands, it holds a computed value.
161 * The _errno field is the errno recorded after the execution of the command.
163 * The _error fields is used the signify that return status of the command. For
164 * simple commands returning `int` the _error field will be the same as the
165 * ret_int field. In complex commands, it signify the success or failure of the
172 struct run_as_open_ret open
;
173 struct run_as_extract_elf_symbol_offset_ret extract_elf_symbol_offset
;
174 struct run_as_extract_sdt_probe_offsets_ret extract_sdt_probe_offsets
;
175 struct run_as_generate_filter_bytecode_ret generate_filter_bytecode
;
181 #define COMMAND_IN_FDS(data_ptr) ({ \
183 if (command_properties[data_ptr->cmd].in_fds_offset != -1) { \
184 fds = (int *) ((char *) data_ptr + command_properties[data_ptr->cmd].in_fds_offset); \
189 #define COMMAND_OUT_FDS(cmd, ret_ptr) ({ \
191 if (command_properties[cmd].out_fds_offset != -1) { \
192 fds = (int *) ((char *) ret_ptr + command_properties[cmd].out_fds_offset); \
197 #define COMMAND_IN_FD_COUNT(data_ptr) ({ \
198 command_properties[data_ptr->cmd].in_fd_count; \
201 #define COMMAND_OUT_FD_COUNT(cmd) ({ \
202 command_properties[cmd].out_fd_count; \
205 #define COMMAND_USE_CWD_FD(data_ptr) command_properties[data_ptr->cmd].use_cwd_fd
207 struct run_as_command_properties
{
208 /* Set to -1 when not applicable. */
209 ptrdiff_t in_fds_offset
, out_fds_offset
;
210 unsigned int in_fd_count
, out_fd_count
;
214 static const struct run_as_command_properties command_properties
[] = {
216 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
218 .out_fds_offset
= -1,
223 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
225 .out_fds_offset
= -1,
229 [RUN_AS_MKDIR_RECURSIVE
] = {
230 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
232 .out_fds_offset
= -1,
236 [RUN_AS_MKDIRAT_RECURSIVE
] = {
237 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
239 .out_fds_offset
= -1,
244 .in_fds_offset
= offsetof(struct run_as_data
, u
.open
.dirfd
),
246 .out_fds_offset
= offsetof(struct run_as_ret
, u
.open
.fd
),
251 .in_fds_offset
= offsetof(struct run_as_data
, u
.open
.dirfd
),
253 .out_fds_offset
= offsetof(struct run_as_ret
, u
.open
.fd
),
258 .in_fds_offset
= offsetof(struct run_as_data
, u
.unlink
.dirfd
),
260 .out_fds_offset
= -1,
264 [RUN_AS_UNLINKAT
] = {
265 .in_fds_offset
= offsetof(struct run_as_data
, u
.unlink
.dirfd
),
267 .out_fds_offset
= -1,
271 [RUN_AS_RMDIR_RECURSIVE
] = {
272 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
274 .out_fds_offset
= -1,
278 [RUN_AS_RMDIRAT_RECURSIVE
] = {
279 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
281 .out_fds_offset
= -1,
286 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
288 .out_fds_offset
= -1,
293 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
295 .out_fds_offset
= -1,
300 .in_fds_offset
= offsetof(struct run_as_data
, u
.rename
.dirfds
),
302 .out_fds_offset
= -1,
306 [RUN_AS_RENAMEAT
] = {
307 .in_fds_offset
= offsetof(struct run_as_data
, u
.rename
.dirfds
),
309 .out_fds_offset
= -1,
313 [RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
] = {
314 .in_fds_offset
= offsetof(struct run_as_data
,
315 u
.extract_elf_symbol_offset
.fd
),
317 .out_fds_offset
= -1,
321 [RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
] = {
322 .in_fds_offset
= offsetof(struct run_as_data
,
323 u
.extract_sdt_probe_offsets
.fd
),
325 .out_fds_offset
= -1,
329 [RUN_AS_GENERATE_FILTER_BYTECODE
] = {
332 .out_fds_offset
= -1,
338 struct run_as_worker
{
339 pid_t pid
; /* Worker PID. */
344 /* Single global worker per process (for now). */
345 static struct run_as_worker
*global_worker
;
346 /* Lock protecting the worker. */
347 static pthread_mutex_t worker_lock
= PTHREAD_MUTEX_INITIALIZER
;
359 return !lttng_secure_getenv("LTTNG_DEBUG_NOCLONE");
364 * Create recursively directory using the FULL path.
367 int _mkdirat_recursive(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
371 struct lttng_directory_handle
*handle
;
373 path
= data
->u
.mkdir
.path
;
374 mode
= data
->u
.mkdir
.mode
;
376 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.mkdir
.dirfd
);
378 ret_value
->_errno
= errno
;
379 ret_value
->_error
= true;
380 ret_value
->u
.ret
= -1;
383 /* Ownership of dirfd is transferred to the handle. */
384 data
->u
.mkdir
.dirfd
= -1;
385 /* Safe to call as we have transitioned to the requested uid/gid. */
386 ret_value
->u
.ret
= lttng_directory_handle_create_subdirectory_recursive(
388 ret_value
->_errno
= errno
;
389 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
390 lttng_directory_handle_put(handle
);
392 return ret_value
->u
.ret
;
396 int _mkdirat(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
400 struct lttng_directory_handle
*handle
;
402 path
= data
->u
.mkdir
.path
;
403 mode
= data
->u
.mkdir
.mode
;
405 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.mkdir
.dirfd
);
407 ret_value
->u
.ret
= -1;
408 ret_value
->_errno
= errno
;
409 ret_value
->_error
= true;
412 /* Ownership of dirfd is transferred to the handle. */
413 data
->u
.mkdir
.dirfd
= -1;
414 /* Safe to call as we have transitioned to the requested uid/gid. */
415 ret_value
->u
.ret
= lttng_directory_handle_create_subdirectory(
417 ret_value
->_errno
= errno
;
418 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
419 lttng_directory_handle_put(handle
);
421 return ret_value
->u
.ret
;
425 int _open(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
428 struct lttng_directory_handle
*handle
;
430 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.open
.dirfd
);
432 ret_value
->_errno
= errno
;
433 ret_value
->_error
= true;
434 ret_value
->u
.ret
= -1;
437 /* Ownership of dirfd is transferred to the handle. */
438 data
->u
.open
.dirfd
= -1;
440 fd
= lttng_directory_handle_open_file(handle
,
441 data
->u
.open
.path
, data
->u
.open
.flags
,
444 ret_value
->u
.ret
= -1;
445 ret_value
->u
.open
.fd
= -1;
447 ret_value
->u
.ret
= 0;
448 ret_value
->u
.open
.fd
= fd
;
451 ret_value
->_errno
= errno
;
452 ret_value
->_error
= fd
< 0;
453 lttng_directory_handle_put(handle
);
455 return ret_value
->u
.ret
;
459 int _unlink(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
461 struct lttng_directory_handle
*handle
;
463 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.unlink
.dirfd
);
465 ret_value
->u
.ret
= -1;
466 ret_value
->_errno
= errno
;
467 ret_value
->_error
= true;
471 /* Ownership of dirfd is transferred to the handle. */
472 data
->u
.unlink
.dirfd
= -1;
474 ret_value
->u
.ret
= lttng_directory_handle_unlink_file(handle
,
475 data
->u
.unlink
.path
);
476 ret_value
->_errno
= errno
;
477 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
478 lttng_directory_handle_put(handle
);
480 return ret_value
->u
.ret
;
484 int _rmdir(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
486 struct lttng_directory_handle
*handle
;
488 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.rmdir
.dirfd
);
490 ret_value
->u
.ret
= -1;
491 ret_value
->_errno
= errno
;
492 ret_value
->_error
= true;
496 /* Ownership of dirfd is transferred to the handle. */
497 data
->u
.rmdir
.dirfd
= -1;
499 ret_value
->u
.ret
= lttng_directory_handle_remove_subdirectory(
500 handle
, data
->u
.rmdir
.path
);
501 ret_value
->_errno
= errno
;
502 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
503 lttng_directory_handle_put(handle
);
505 return ret_value
->u
.ret
;
509 int _rmdir_recursive(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
511 struct lttng_directory_handle
*handle
;
513 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.rmdir
.dirfd
);
515 ret_value
->u
.ret
= -1;
516 ret_value
->_errno
= errno
;
517 ret_value
->_error
= true;
521 /* Ownership of dirfd is transferred to the handle. */
522 data
->u
.rmdir
.dirfd
= -1;
524 ret_value
->u
.ret
= lttng_directory_handle_remove_subdirectory_recursive(
525 handle
, data
->u
.rmdir
.path
, data
->u
.rmdir
.flags
);
526 ret_value
->_errno
= errno
;
527 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
528 lttng_directory_handle_put(handle
);
530 return ret_value
->u
.ret
;
534 int _rename(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
536 const char *old_path
, *new_path
;
537 struct lttng_directory_handle
*old_handle
= NULL
, *new_handle
= NULL
;
539 old_path
= data
->u
.rename
.old_path
;
540 new_path
= data
->u
.rename
.new_path
;
542 old_handle
= lttng_directory_handle_create_from_dirfd(
543 data
->u
.rename
.dirfds
[0]);
545 ret_value
->u
.ret
= -1;
548 new_handle
= lttng_directory_handle_create_from_dirfd(
549 data
->u
.rename
.dirfds
[1]);
551 ret_value
->u
.ret
= -1;
555 /* Ownership of dirfds are transferred to the handles. */
556 data
->u
.rename
.dirfds
[0] = data
->u
.rename
.dirfds
[1] = -1;
558 /* Safe to call as we have transitioned to the requested uid/gid. */
559 ret_value
->u
.ret
= lttng_directory_handle_rename(
560 old_handle
, old_path
, new_handle
, new_path
);
562 lttng_directory_handle_put(old_handle
);
563 lttng_directory_handle_put(new_handle
);
564 ret_value
->_errno
= errno
;
565 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
566 return ret_value
->u
.ret
;
571 int _extract_elf_symbol_offset(struct run_as_data
*data
,
572 struct run_as_ret
*ret_value
)
577 ret_value
->_error
= false;
578 ret
= lttng_elf_get_symbol_offset(data
->u
.extract_elf_symbol_offset
.fd
,
579 data
->u
.extract_elf_symbol_offset
.function
,
582 DBG("Failed to extract ELF function offset");
583 ret_value
->_error
= true;
585 ret_value
->u
.extract_elf_symbol_offset
.offset
= offset
;
591 int _extract_sdt_probe_offsets(struct run_as_data
*data
,
592 struct run_as_ret
*ret_value
)
595 uint64_t *offsets
= NULL
;
598 ret_value
->_error
= false;
600 /* On success, this call allocates the offsets paramater. */
601 ret
= lttng_elf_get_sdt_probe_offsets(
602 data
->u
.extract_sdt_probe_offsets
.fd
,
603 data
->u
.extract_sdt_probe_offsets
.provider_name
,
604 data
->u
.extract_sdt_probe_offsets
.probe_name
,
605 &offsets
, &num_offset
);
608 DBG("Failed to extract SDT probe offsets");
609 ret_value
->_error
= true;
613 if (num_offset
<= 0 || num_offset
> LTTNG_KERNEL_ABI_MAX_UPROBE_NUM
) {
614 DBG("Wrong number of probes.");
616 ret_value
->_error
= true;
620 /* Copy the content of the offsets array to the ret struct. */
621 memcpy(ret_value
->u
.extract_sdt_probe_offsets
.offsets
,
622 offsets
, num_offset
* sizeof(uint64_t));
624 ret_value
->u
.extract_sdt_probe_offsets
.num_offset
= num_offset
;
633 int _extract_elf_symbol_offset(struct run_as_data
*data
,
634 struct run_as_ret
*ret_value
)
636 ERR("Unimplemented runas command RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET");
641 int _extract_sdt_probe_offsets(struct run_as_data
*data
,
642 struct run_as_ret
*ret_value
)
644 ERR("Unimplemented runas command RUN_AS_EXTRACT_SDT_PROBE_OFFSETS");
650 int _generate_filter_bytecode(struct run_as_data
*data
,
651 struct run_as_ret
*ret_value
) {
653 const char *filter_expression
= NULL
;
654 struct filter_parser_ctx
*ctx
= NULL
;
656 ret_value
->_error
= false;
658 filter_expression
= data
->u
.generate_filter_bytecode
.filter_expression
;
660 if (lttng_strnlen(filter_expression
, LTTNG_FILTER_MAX_LEN
- 1) == LTTNG_FILTER_MAX_LEN
- 1) {
661 ret_value
->_error
= true;
666 ret
= filter_parser_ctx_create_from_filter_expression(filter_expression
, &ctx
);
668 ret_value
->_error
= true;
673 DBG("Size of bytecode generated: %u bytes.",
674 bytecode_get_len(&ctx
->bytecode
->b
));
676 /* Copy the lttng_bytecode_filter object to the return structure. */
677 memcpy(ret_value
->u
.generate_filter_bytecode
.bytecode
,
679 sizeof(ctx
->bytecode
->b
) +
680 bytecode_get_len(&ctx
->bytecode
->b
));
684 filter_bytecode_free(ctx
);
686 filter_parser_ctx_free(ctx
);
692 run_as_fct
run_as_enum_to_fct(enum run_as_cmd cmd
)
698 case RUN_AS_MKDIR_RECURSIVE
:
699 case RUN_AS_MKDIRAT_RECURSIVE
:
700 return _mkdirat_recursive
;
705 case RUN_AS_UNLINKAT
:
710 case RUN_AS_RMDIR_RECURSIVE
:
711 case RUN_AS_RMDIRAT_RECURSIVE
:
712 return _rmdir_recursive
;
714 case RUN_AS_RENAMEAT
:
716 case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
:
717 return _extract_elf_symbol_offset
;
718 case RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
:
719 return _extract_sdt_probe_offsets
;
720 case RUN_AS_GENERATE_FILTER_BYTECODE
:
721 return _generate_filter_bytecode
;
723 ERR("Unknown command %d", (int) cmd
);
729 int do_send_fds(int sock
, const int *fds
, unsigned int fd_count
)
734 for (i
= 0; i
< fd_count
; i
++) {
736 DBG("Attempt to send invalid file descriptor (fd = %i)",
738 /* Return 0 as this is not a fatal error. */
743 len
= lttcomm_send_fds_unix_sock(sock
, fds
, fd_count
);
744 return len
< 0 ? -1 : 0;
748 int do_recv_fds(int sock
, int *fds
, unsigned int fd_count
)
754 len
= lttcomm_recv_fds_unix_sock(sock
, fds
, fd_count
);
758 } else if (len
< 0) {
759 PERROR("Failed to receive file descriptors from socket");
764 for (i
= 0; i
< fd_count
; i
++) {
766 ERR("Invalid file descriptor received from worker (fd = %i)", fds
[i
]);
767 /* Return 0 as this is not a fatal error. */
775 int send_fds_to_worker(const struct run_as_worker
*worker
,
776 const struct run_as_data
*data
)
781 if (COMMAND_USE_CWD_FD(data
) || COMMAND_IN_FD_COUNT(data
) == 0) {
785 for (i
= 0; i
< COMMAND_IN_FD_COUNT(data
); i
++) {
786 if (COMMAND_IN_FDS(data
)[i
] < 0) {
787 ERR("Refusing to send invalid fd to worker (fd = %i)",
788 COMMAND_IN_FDS(data
)[i
]);
794 ret
= do_send_fds(worker
->sockpair
[0], COMMAND_IN_FDS(data
),
795 COMMAND_IN_FD_COUNT(data
));
797 PERROR("Failed to send file descriptor to run-as worker");
806 int send_fds_to_master(struct run_as_worker
*worker
, enum run_as_cmd cmd
,
807 struct run_as_ret
*run_as_ret
)
812 if (COMMAND_OUT_FD_COUNT(cmd
) == 0) {
816 ret
= do_send_fds(worker
->sockpair
[1], COMMAND_OUT_FDS(cmd
, run_as_ret
),
817 COMMAND_OUT_FD_COUNT(cmd
));
819 PERROR("Failed to send file descriptor to master process");
823 for (i
= 0; i
< COMMAND_OUT_FD_COUNT(cmd
); i
++) {
824 int fd
= COMMAND_OUT_FDS(cmd
, run_as_ret
)[i
];
826 int ret_close
= close(fd
);
829 PERROR("Failed to close result file descriptor (fd = %i)",
839 int recv_fds_from_worker(const struct run_as_worker
*worker
, enum run_as_cmd cmd
,
840 struct run_as_ret
*run_as_ret
)
844 if (COMMAND_OUT_FD_COUNT(cmd
) == 0) {
848 ret
= do_recv_fds(worker
->sockpair
[0], COMMAND_OUT_FDS(cmd
, run_as_ret
),
849 COMMAND_OUT_FD_COUNT(cmd
));
851 PERROR("Failed to receive file descriptor from run-as worker");
859 int recv_fds_from_master(struct run_as_worker
*worker
, struct run_as_data
*data
)
863 if (COMMAND_USE_CWD_FD(data
)) {
866 for (i
= 0; i
< COMMAND_IN_FD_COUNT(data
); i
++) {
867 COMMAND_IN_FDS(data
)[i
] = AT_FDCWD
;
872 if (COMMAND_IN_FD_COUNT(data
) == 0) {
876 ret
= do_recv_fds(worker
->sockpair
[1], COMMAND_IN_FDS(data
),
877 COMMAND_IN_FD_COUNT(data
));
879 PERROR("Failed to receive file descriptors from master process");
887 int cleanup_received_fds(struct run_as_data
*data
)
891 for (i
= 0; i
< COMMAND_IN_FD_COUNT(data
); i
++) {
892 if (COMMAND_IN_FDS(data
)[i
] == -1) {
895 ret
= close(COMMAND_IN_FDS(data
)[i
]);
897 PERROR("Failed to close file descriptor received fd in run-as worker");
905 static int get_user_infos_from_uid(
906 uid_t uid
, char **username
, gid_t
*primary_gid
)
910 long raw_get_pw_buf_size
;
911 size_t get_pw_buf_size
;
913 struct passwd
*result
= NULL
;
915 /* Fetch the max size for the temporary buffer. */
917 raw_get_pw_buf_size
= sysconf(_SC_GETPW_R_SIZE_MAX
);
918 if (raw_get_pw_buf_size
< 0) {
920 PERROR("Failed to query _SC_GETPW_R_SIZE_MAX");
924 /* Limit is indeterminate. */
925 WARN("Failed to query _SC_GETPW_R_SIZE_MAX as it is "
926 "indeterminate; falling back to default buffer size");
927 raw_get_pw_buf_size
= GETPW_BUFFER_FALLBACK_SIZE
;
930 get_pw_buf_size
= (size_t) raw_get_pw_buf_size
;
932 buf
= zmalloc(get_pw_buf_size
);
934 PERROR("Failed to allocate buffer to get password file entries");
938 ret
= getpwuid_r(uid
, &pwd
, buf
, get_pw_buf_size
, &result
);
940 PERROR("Failed to get user information for user: uid = %d",
945 if (result
== NULL
) {
946 ERR("Failed to find user information in password entries: uid = %d",
952 *username
= strdup(result
->pw_name
);
953 if (*username
== NULL
) {
954 PERROR("Failed to copy user name");
958 *primary_gid
= result
->pw_gid
;
970 static int demote_creds(
971 uid_t prev_uid
, gid_t prev_gid
, uid_t new_uid
, gid_t new_gid
)
975 char *username
= NULL
;
977 /* Change the group id. */
978 if (prev_gid
!= new_gid
) {
979 ret
= setegid(new_gid
);
981 PERROR("Failed to set effective group id: new_gid = %d",
987 /* Change the user id. */
988 if (prev_uid
!= new_uid
) {
989 ret
= get_user_infos_from_uid(new_uid
, &username
, &primary_gid
);
995 * Initialize the supplementary group access list.
997 * This is needed to handle cases where the supplementary groups
998 * of the user the process is demoting-to would give it access
999 * to a given file/folder, but not it's primary group.
1003 * Primary Group: User1
1004 * Secondary group: Disk, Network
1006 * mkdir inside the following directory must work since User1
1007 * is part of the Network group.
1009 * drwxrwx--- 2 root Network 4096 Jul 23 17:17 /tmp/my_folder/
1012 * The order of the following initgroups and seteuid calls is
1014 * Only a root process or one with CAP_SETGID capability can
1015 * call the the initgroups() function. We must initialize the
1016 * supplementary groups before we change the effective
1017 * UID to a less-privileged user.
1019 ret
= initgroups(username
, primary_gid
);
1021 PERROR("Failed to init the supplementary group access list: "
1022 "username = `%s`, primary gid = %d", username
,
1027 ret
= seteuid(new_uid
);
1029 PERROR("Failed to set effective user id: new_uid = %d",
1039 static int promote_creds(
1040 uid_t prev_uid
, gid_t prev_gid
, uid_t new_uid
, gid_t new_gid
)
1044 char *username
= NULL
;
1046 /* Change the group id. */
1047 if (prev_gid
!= new_gid
) {
1048 ret
= setegid(new_gid
);
1050 PERROR("Failed to set effective group id: new_gid = %d",
1056 /* Change the user id. */
1057 if (prev_uid
!= new_uid
) {
1058 ret
= get_user_infos_from_uid(new_uid
, &username
, &primary_gid
);
1064 * seteuid call must be done before the initgroups call because
1065 * we need to be privileged (CAP_SETGID) to call initgroups().
1067 ret
= seteuid(new_uid
);
1069 PERROR("Failed to set effective user id: new_uid = %d",
1075 * Initialize the supplementary group access list.
1077 * There is a possibility the groups we set in the following
1078 * initgroups() call are not exactly the same as the ones we
1079 * had when we originally demoted. This can happen if the
1080 * /etc/group file is modified after the runas process is
1081 * forked. This is very unlikely.
1083 ret
= initgroups(username
, primary_gid
);
1085 PERROR("Failed to init the supplementary group access "
1086 "list: username = `%s`, primary gid = %d",
1087 username
, (int) primary_gid
)
1097 * Return < 0 on error, 0 if OK, 1 on hangup.
1100 int handle_one_cmd(struct run_as_worker
*worker
)
1102 int ret
= 0, promote_ret
;
1103 struct run_as_data data
= {};
1104 ssize_t readlen
, writelen
;
1105 struct run_as_ret sendret
= {};
1107 const uid_t prev_ruid
= getuid();
1108 const gid_t prev_rgid
= getgid();
1111 * Stage 1: Receive run_as_data struct from the master.
1112 * The structure contains the command type and all the parameters needed for
1115 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[1], &data
,
1122 if (readlen
< sizeof(data
)) {
1123 PERROR("lttcomm_recv_unix_sock error");
1128 cmd
= run_as_enum_to_fct(data
.cmd
);
1135 * Stage 2: Receive file descriptor from master.
1136 * Some commands need a file descriptor as input so if it's needed we
1137 * receive the fd using the Unix socket.
1139 ret
= recv_fds_from_master(worker
, &data
);
1141 PERROR("recv_fd_from_master error");
1146 ret
= demote_creds(prev_ruid
, prev_rgid
, data
.uid
, data
.gid
);
1152 * Also set umask to 0 for mkdir executable bit.
1157 * Stage 3: Execute the command
1159 ret
= (*cmd
)(&data
, &sendret
);
1161 DBG("Execution of command returned an error");
1165 ret
= cleanup_received_fds(&data
);
1167 ERR("Error cleaning up FD");
1172 * Stage 4: Send run_as_ret structure to the master.
1173 * This structure contain the return value of the command and the errno.
1175 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[1], &sendret
,
1177 if (writelen
< sizeof(sendret
)) {
1178 PERROR("lttcomm_send_unix_sock error");
1184 * Stage 5: Send resulting file descriptors to the master.
1186 ret
= send_fds_to_master(worker
, data
.cmd
, &sendret
);
1188 DBG("Sending FD to master returned an error");
1194 /* Return to previous uid/gid. */
1195 promote_ret
= promote_creds(data
.uid
, data
.gid
, prev_ruid
, prev_rgid
);
1196 if (promote_ret
< 0) {
1197 ERR("Failed to promote back to the initial credentials");
1205 int run_as_worker(struct run_as_worker
*worker
)
1209 struct run_as_ret sendret
;
1210 size_t proc_orig_len
;
1213 * Initialize worker. Set a different process cmdline.
1215 proc_orig_len
= strlen(worker
->procname
);
1216 memset(worker
->procname
, 0, proc_orig_len
);
1217 strncpy(worker
->procname
, DEFAULT_RUN_AS_WORKER_NAME
, proc_orig_len
);
1219 ret
= lttng_thread_setname(DEFAULT_RUN_AS_WORKER_NAME
);
1220 if (ret
&& ret
!= -ENOSYS
) {
1221 /* Don't fail as this is not essential. */
1222 DBG("Failed to set pthread name attribute");
1225 memset(&sendret
, 0, sizeof(sendret
));
1227 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[1], &sendret
,
1229 if (writelen
< sizeof(sendret
)) {
1230 PERROR("lttcomm_send_unix_sock error");
1236 ret
= handle_one_cmd(worker
);
1240 } else if (ret
> 0) {
1243 continue; /* Next command. */
1252 int run_as_cmd(struct run_as_worker
*worker
,
1253 enum run_as_cmd cmd
,
1254 struct run_as_data
*data
,
1255 struct run_as_ret
*ret_value
,
1256 uid_t uid
, gid_t gid
)
1259 ssize_t readlen
, writelen
;
1262 * If we are non-root, we can only deal with our own uid.
1264 if (geteuid() != 0) {
1265 if (uid
!= geteuid()) {
1267 ret_value
->_errno
= EPERM
;
1268 ERR("Client (%d)/Server (%d) UID mismatch (and sessiond is not root)",
1269 (int) uid
, (int) geteuid());
1279 * Stage 1: Send the run_as_data struct to the worker process
1281 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[0], data
,
1283 if (writelen
< sizeof(*data
)) {
1284 PERROR("Error writing message to run_as");
1286 ret_value
->_errno
= EIO
;
1291 * Stage 2: Send file descriptor to the worker process if needed
1293 ret
= send_fds_to_worker(worker
, data
);
1295 PERROR("do_send_fd error");
1297 ret_value
->_errno
= EIO
;
1302 * Stage 3: Wait for the execution of the command
1306 * Stage 4: Receive the run_as_ret struct containing the return value and
1309 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[0], ret_value
,
1310 sizeof(*ret_value
));
1312 ERR("Run-as worker has hung-up during run_as_cmd");
1314 ret_value
->_errno
= EIO
;
1316 } else if (readlen
< sizeof(*ret_value
)) {
1317 PERROR("Error reading response from run_as");
1319 ret_value
->_errno
= errno
;
1323 if (ret_value
->_error
) {
1324 /* Skip stage 5 on error as there will be no fd to receive. */
1329 * Stage 5: Receive file descriptor if needed
1331 ret
= recv_fds_from_worker(worker
, cmd
, ret_value
);
1333 ERR("Error receiving fd");
1335 ret_value
->_errno
= EIO
;
1343 * This is for debugging ONLY and should not be considered secure.
1346 int run_as_noworker(enum run_as_cmd cmd
,
1347 struct run_as_data
*data
, struct run_as_ret
*ret_value
,
1348 uid_t uid
, gid_t gid
)
1350 int ret
, saved_errno
;
1354 fct
= run_as_enum_to_fct(cmd
);
1360 old_mask
= umask(0);
1361 ret
= fct(data
, ret_value
);
1362 saved_errno
= ret_value
->_errno
;
1364 errno
= saved_errno
;
1370 int reset_sighandler(void)
1374 DBG("Resetting run_as worker signal handlers to default");
1375 for (sig
= 1; sig
<= 31; sig
++) {
1376 (void) signal(sig
, SIG_DFL
);
1382 void worker_sighandler(int sig
)
1384 const char *signame
;
1387 * The worker will inherit its parent's signals since they are part of
1388 * the same process group. However, in the case of SIGINT and SIGTERM,
1389 * we want to give the worker a chance to teardown gracefully when its
1390 * parent closes the command socket.
1397 signame
= "SIGTERM";
1404 DBG("run_as worker received signal %s", signame
);
1406 DBG("run_as_worker received signal %d", sig
);
1411 int set_worker_sighandlers(void)
1415 struct sigaction sa
;
1417 if ((ret
= sigemptyset(&sigset
)) < 0) {
1418 PERROR("sigemptyset");
1422 sa
.sa_handler
= worker_sighandler
;
1423 sa
.sa_mask
= sigset
;
1425 if ((ret
= sigaction(SIGINT
, &sa
, NULL
)) < 0) {
1426 PERROR("sigaction SIGINT");
1430 if ((ret
= sigaction(SIGTERM
, &sa
, NULL
)) < 0) {
1431 PERROR("sigaction SIGTERM");
1435 DBG("run_as signal handler set for SIGTERM and SIGINT");
1441 int run_as_create_worker_no_lock(const char *procname
,
1442 post_fork_cleanup_cb clean_up_func
,
1443 void *clean_up_user_data
)
1448 struct run_as_ret recvret
;
1449 struct run_as_worker
*worker
;
1451 assert(!global_worker
);
1454 * Don't initialize a worker, all run_as tasks will be performed
1455 * in the current process.
1460 worker
= zmalloc(sizeof(*worker
));
1465 worker
->procname
= strdup(procname
);
1466 if (!worker
->procname
) {
1468 goto error_procname_alloc
;
1470 /* Create unix socket. */
1471 if (lttcomm_create_anon_unix_socketpair(worker
->sockpair
) < 0) {
1482 } else if (pid
== 0) {
1487 set_worker_sighandlers();
1489 logger_set_thread_name("Run-as worker", true);
1491 if (clean_up_func
) {
1492 if (clean_up_func(clean_up_user_data
) < 0) {
1493 ERR("Run-as post-fork clean-up failed, exiting.");
1498 /* Just close, no shutdown. */
1499 if (close(worker
->sockpair
[0])) {
1505 * Close all FDs aside from STDIN, STDOUT, STDERR and sockpair[1]
1506 * Sockpair[1] is used as a control channel with the master
1508 for (i
= 3; i
< sysconf(_SC_OPEN_MAX
); i
++) {
1509 if (i
!= worker
->sockpair
[1]) {
1514 worker
->sockpair
[0] = -1;
1515 ret
= run_as_worker(worker
);
1516 if (lttcomm_close_unix_sock(worker
->sockpair
[1])) {
1520 worker
->sockpair
[1] = -1;
1521 free(worker
->procname
);
1523 LOG(ret
? PRINT_ERR
: PRINT_DBG
, "run_as worker exiting (ret = %d)", ret
);
1524 exit(ret
? EXIT_FAILURE
: EXIT_SUCCESS
);
1528 /* Just close, no shutdown. */
1529 if (close(worker
->sockpair
[1])) {
1534 worker
->sockpair
[1] = -1;
1536 /* Wait for worker to become ready. */
1537 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[0],
1538 &recvret
, sizeof(recvret
));
1539 if (readlen
< sizeof(recvret
)) {
1540 ERR("readlen: %zd", readlen
);
1541 PERROR("Error reading response from run_as at creation");
1545 global_worker
= worker
;
1550 /* Error handling. */
1552 for (i
= 0; i
< 2; i
++) {
1553 if (worker
->sockpair
[i
] < 0) {
1556 if (lttcomm_close_unix_sock(worker
->sockpair
[i
])) {
1559 worker
->sockpair
[i
] = -1;
1562 free(worker
->procname
);
1563 error_procname_alloc
:
1569 void run_as_destroy_worker_no_lock(void)
1571 struct run_as_worker
*worker
= global_worker
;
1573 DBG("Destroying run_as worker");
1577 /* Close unix socket */
1578 DBG("Closing run_as worker socket");
1579 if (lttcomm_close_unix_sock(worker
->sockpair
[0])) {
1582 worker
->sockpair
[0] = -1;
1583 /* Wait for worker. */
1588 wait_ret
= waitpid(worker
->pid
, &status
, 0);
1590 if (errno
== EINTR
) {
1597 if (WIFEXITED(status
)) {
1598 LOG(WEXITSTATUS(status
) == 0 ? PRINT_DBG
: PRINT_ERR
,
1599 DEFAULT_RUN_AS_WORKER_NAME
" terminated with status code %d",
1600 WEXITSTATUS(status
));
1602 } else if (WIFSIGNALED(status
)) {
1603 ERR(DEFAULT_RUN_AS_WORKER_NAME
" was killed by signal %d",
1608 free(worker
->procname
);
1610 global_worker
= NULL
;
1614 int run_as_restart_worker(struct run_as_worker
*worker
)
1617 char *procname
= NULL
;
1619 procname
= worker
->procname
;
1621 /* Close socket to run_as worker process and clean up the zombie process */
1622 run_as_destroy_worker_no_lock();
1624 /* Create a new run_as worker process*/
1625 ret
= run_as_create_worker_no_lock(procname
, NULL
, NULL
);
1627 ERR("Restarting the worker process failed");
1636 int run_as(enum run_as_cmd cmd
, struct run_as_data
*data
,
1637 struct run_as_ret
*ret_value
, uid_t uid
, gid_t gid
)
1639 int ret
, saved_errno
;
1641 pthread_mutex_lock(&worker_lock
);
1643 DBG("Using run_as worker");
1645 assert(global_worker
);
1647 ret
= run_as_cmd(global_worker
, cmd
, data
, ret_value
, uid
, gid
);
1648 saved_errno
= ret_value
->_errno
;
1651 * If the worker thread crashed the errno is set to EIO. we log
1652 * the error and start a new worker process.
1654 if (ret
== -1 && saved_errno
== EIO
) {
1655 DBG("Socket closed unexpectedly... "
1656 "Restarting the worker process");
1657 ret
= run_as_restart_worker(global_worker
);
1659 ERR("Failed to restart worker process.");
1664 DBG("Using run_as without worker");
1665 ret
= run_as_noworker(cmd
, data
, ret_value
, uid
, gid
);
1668 pthread_mutex_unlock(&worker_lock
);
1673 int run_as_mkdir_recursive(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
1675 return run_as_mkdirat_recursive(AT_FDCWD
, path
, mode
, uid
, gid
);
1679 int run_as_mkdirat_recursive(int dirfd
, const char *path
, mode_t mode
,
1680 uid_t uid
, gid_t gid
)
1683 struct run_as_data data
= {};
1684 struct run_as_ret run_as_ret
= {};
1686 DBG3("mkdirat() recursive fd = %d%s, path = %s, mode = %d, uid = %d, gid = %d",
1687 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1688 path
, (int) mode
, (int) uid
, (int) gid
);
1689 ret
= lttng_strncpy(data
.u
.mkdir
.path
, path
,
1690 sizeof(data
.u
.mkdir
.path
));
1692 ERR("Failed to copy path argument of mkdirat recursive command");
1695 data
.u
.mkdir
.path
[sizeof(data
.u
.mkdir
.path
) - 1] = '\0';
1696 data
.u
.mkdir
.mode
= mode
;
1697 data
.u
.mkdir
.dirfd
= dirfd
;
1698 run_as(dirfd
== AT_FDCWD
? RUN_AS_MKDIR_RECURSIVE
: RUN_AS_MKDIRAT_RECURSIVE
,
1699 &data
, &run_as_ret
, uid
, gid
);
1700 errno
= run_as_ret
._errno
;
1701 ret
= run_as_ret
.u
.ret
;
1707 int run_as_mkdir(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
1709 return run_as_mkdirat(AT_FDCWD
, path
, mode
, uid
, gid
);
1713 int run_as_mkdirat(int dirfd
, const char *path
, mode_t mode
,
1714 uid_t uid
, gid_t gid
)
1717 struct run_as_data data
= {};
1718 struct run_as_ret run_as_ret
= {};
1720 DBG3("mkdirat() recursive fd = %d%s, path = %s, mode = %d, uid = %d, gid = %d",
1721 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1722 path
, (int) mode
, (int) uid
, (int) gid
);
1723 ret
= lttng_strncpy(data
.u
.mkdir
.path
, path
,
1724 sizeof(data
.u
.mkdir
.path
));
1726 ERR("Failed to copy path argument of mkdirat command");
1729 data
.u
.mkdir
.path
[sizeof(data
.u
.mkdir
.path
) - 1] = '\0';
1730 data
.u
.mkdir
.mode
= mode
;
1731 data
.u
.mkdir
.dirfd
= dirfd
;
1732 run_as(dirfd
== AT_FDCWD
? RUN_AS_MKDIR
: RUN_AS_MKDIRAT
,
1733 &data
, &run_as_ret
, uid
, gid
);
1734 errno
= run_as_ret
._errno
;
1735 ret
= run_as_ret
.u
.ret
;
1741 int run_as_open(const char *path
, int flags
, mode_t mode
, uid_t uid
,
1744 return run_as_openat(AT_FDCWD
, path
, flags
, mode
, uid
, gid
);
1748 int run_as_openat(int dirfd
, const char *path
, int flags
, mode_t mode
,
1749 uid_t uid
, gid_t gid
)
1752 struct run_as_data data
= {};
1753 struct run_as_ret run_as_ret
= {};
1755 DBG3("openat() fd = %d%s, path = %s, flags = %X, mode = %d, uid %d, gid %d",
1756 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1757 path
, flags
, (int) mode
, (int) uid
, (int) gid
);
1758 ret
= lttng_strncpy(data
.u
.open
.path
, path
, sizeof(data
.u
.open
.path
));
1760 ERR("Failed to copy path argument of open command");
1763 data
.u
.open
.flags
= flags
;
1764 data
.u
.open
.mode
= mode
;
1765 data
.u
.open
.dirfd
= dirfd
;
1766 run_as(dirfd
== AT_FDCWD
? RUN_AS_OPEN
: RUN_AS_OPENAT
,
1767 &data
, &run_as_ret
, uid
, gid
);
1768 errno
= run_as_ret
._errno
;
1769 ret
= run_as_ret
.u
.ret
< 0 ? run_as_ret
.u
.ret
:
1770 run_as_ret
.u
.open
.fd
;
1776 int run_as_unlink(const char *path
, uid_t uid
, gid_t gid
)
1778 return run_as_unlinkat(AT_FDCWD
, path
, uid
, gid
);
1782 int run_as_unlinkat(int dirfd
, const char *path
, uid_t uid
, gid_t gid
)
1785 struct run_as_data data
= {};
1786 struct run_as_ret run_as_ret
= {};
1788 DBG3("unlinkat() fd = %d%s, path = %s, uid = %d, gid = %d",
1789 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1790 path
, (int) uid
, (int) gid
);
1791 ret
= lttng_strncpy(data
.u
.unlink
.path
, path
,
1792 sizeof(data
.u
.unlink
.path
));
1796 data
.u
.unlink
.dirfd
= dirfd
;
1797 run_as(dirfd
== AT_FDCWD
? RUN_AS_UNLINK
: RUN_AS_UNLINKAT
, &data
,
1798 &run_as_ret
, uid
, gid
);
1799 errno
= run_as_ret
._errno
;
1800 ret
= run_as_ret
.u
.ret
;
1806 int run_as_rmdir(const char *path
, uid_t uid
, gid_t gid
)
1808 return run_as_rmdirat(AT_FDCWD
, path
, uid
, gid
);
1812 int run_as_rmdirat(int dirfd
, const char *path
, uid_t uid
, gid_t gid
)
1815 struct run_as_data data
= {};
1816 struct run_as_ret run_as_ret
= {};
1818 DBG3("rmdirat() fd = %d%s, path = %s, uid = %d, gid = %d",
1819 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1820 path
, (int) uid
, (int) gid
);
1821 ret
= lttng_strncpy(data
.u
.rmdir
.path
, path
,
1822 sizeof(data
.u
.rmdir
.path
));
1826 data
.u
.rmdir
.dirfd
= dirfd
;
1827 run_as(dirfd
== AT_FDCWD
? RUN_AS_RMDIR
: RUN_AS_RMDIRAT
, &data
,
1828 &run_as_ret
, uid
, gid
);
1829 errno
= run_as_ret
._errno
;
1830 ret
= run_as_ret
.u
.ret
;
1836 int run_as_rmdir_recursive(const char *path
, uid_t uid
, gid_t gid
, int flags
)
1838 return run_as_rmdirat_recursive(AT_FDCWD
, path
, uid
, gid
, flags
);
1842 int run_as_rmdirat_recursive(int dirfd
, const char *path
, uid_t uid
, gid_t gid
, int flags
)
1845 struct run_as_data data
= {};
1846 struct run_as_ret run_as_ret
= {};
1848 DBG3("rmdirat() recursive fd = %d%s, path = %s, uid = %d, gid = %d",
1849 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1850 path
, (int) uid
, (int) gid
);
1851 ret
= lttng_strncpy(data
.u
.rmdir
.path
, path
,
1852 sizeof(data
.u
.rmdir
.path
));
1856 data
.u
.rmdir
.dirfd
= dirfd
;
1857 data
.u
.rmdir
.flags
= flags
;
1858 run_as(dirfd
== AT_FDCWD
? RUN_AS_RMDIR_RECURSIVE
: RUN_AS_RMDIRAT_RECURSIVE
,
1859 &data
, &run_as_ret
, uid
, gid
);
1860 errno
= run_as_ret
._errno
;
1861 ret
= run_as_ret
.u
.ret
;
1867 int run_as_rename(const char *old
, const char *new, uid_t uid
, gid_t gid
)
1869 return run_as_renameat(AT_FDCWD
, old
, AT_FDCWD
, new, uid
, gid
);
1873 int run_as_renameat(int old_dirfd
, const char *old_name
,
1874 int new_dirfd
, const char *new_name
, uid_t uid
, gid_t gid
)
1877 struct run_as_data data
= {};
1878 struct run_as_ret run_as_ret
= {};
1880 DBG3("renameat() old_dirfd = %d%s, old_name = %s, new_dirfd = %d%s, new_name = %s, uid = %d, gid = %d",
1881 old_dirfd
, old_dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1883 new_dirfd
, new_dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1884 new_name
, (int) uid
, (int) gid
);
1885 ret
= lttng_strncpy(data
.u
.rename
.old_path
, old_name
,
1886 sizeof(data
.u
.rename
.old_path
));
1890 ret
= lttng_strncpy(data
.u
.rename
.new_path
, new_name
,
1891 sizeof(data
.u
.rename
.new_path
));
1896 data
.u
.rename
.dirfds
[0] = old_dirfd
;
1897 data
.u
.rename
.dirfds
[1] = new_dirfd
;
1898 run_as(old_dirfd
== AT_FDCWD
&& new_dirfd
== AT_FDCWD
?
1899 RUN_AS_RENAME
: RUN_AS_RENAMEAT
,
1900 &data
, &run_as_ret
, uid
, gid
);
1901 errno
= run_as_ret
._errno
;
1902 ret
= run_as_ret
.u
.ret
;
1908 int run_as_extract_elf_symbol_offset(int fd
, const char* function
,
1909 uid_t uid
, gid_t gid
, uint64_t *offset
)
1912 struct run_as_data data
= {};
1913 struct run_as_ret run_as_ret
= {};
1915 DBG3("extract_elf_symbol_offset() on fd=%d and function=%s "
1916 "with for uid %d and gid %d", fd
, function
,
1917 (int) uid
, (int) gid
);
1919 data
.u
.extract_elf_symbol_offset
.fd
= fd
;
1921 strncpy(data
.u
.extract_elf_symbol_offset
.function
, function
, LTTNG_SYMBOL_NAME_LEN
- 1);
1922 data
.u
.extract_elf_symbol_offset
.function
[LTTNG_SYMBOL_NAME_LEN
- 1] = '\0';
1923 ret
= lttng_strncpy(data
.u
.extract_elf_symbol_offset
.function
,
1925 sizeof(data
.u
.extract_elf_symbol_offset
.function
));
1930 run_as(RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
, &data
, &run_as_ret
, uid
, gid
);
1931 errno
= run_as_ret
._errno
;
1932 if (run_as_ret
._error
) {
1937 *offset
= run_as_ret
.u
.extract_elf_symbol_offset
.offset
;
1943 int run_as_extract_sdt_probe_offsets(int fd
, const char* provider_name
,
1944 const char* probe_name
, uid_t uid
, gid_t gid
,
1945 uint64_t **offsets
, uint32_t *num_offset
)
1948 struct run_as_data data
= {};
1949 struct run_as_ret run_as_ret
= {};
1951 DBG3("extract_sdt_probe_offsets() on fd=%d, probe_name=%s and "
1952 "provider_name=%s with for uid %d and gid %d", fd
,
1953 probe_name
, provider_name
, (int) uid
, (int) gid
);
1955 data
.u
.extract_sdt_probe_offsets
.fd
= fd
;
1957 ret
= lttng_strncpy(data
.u
.extract_sdt_probe_offsets
.probe_name
, probe_name
,
1958 sizeof(data
.u
.extract_sdt_probe_offsets
.probe_name
));
1962 ret
= lttng_strncpy(data
.u
.extract_sdt_probe_offsets
.provider_name
,
1964 sizeof(data
.u
.extract_sdt_probe_offsets
.provider_name
));
1969 run_as(RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
, &data
, &run_as_ret
, uid
, gid
);
1970 errno
= run_as_ret
._errno
;
1971 if (run_as_ret
._error
) {
1976 *num_offset
= run_as_ret
.u
.extract_sdt_probe_offsets
.num_offset
;
1977 *offsets
= zmalloc(*num_offset
* sizeof(uint64_t));
1983 memcpy(*offsets
, run_as_ret
.u
.extract_sdt_probe_offsets
.offsets
,
1984 *num_offset
* sizeof(uint64_t));
1990 int run_as_generate_filter_bytecode(const char *filter_expression
,
1991 const struct lttng_credentials
*creds
,
1992 struct lttng_bytecode
**bytecode
)
1995 struct run_as_data data
= {};
1996 struct run_as_ret run_as_ret
= {};
1997 const struct lttng_bytecode
*view_bytecode
= NULL
;
1998 struct lttng_bytecode
*local_bytecode
= NULL
;
1999 const uid_t uid
= lttng_credentials_get_uid(creds
);
2000 const gid_t gid
= lttng_credentials_get_gid(creds
);
2002 DBG3("generate_filter_bytecode() from expression=\"%s\" for uid %d and gid %d",
2003 filter_expression
, (int) uid
, (int) gid
);
2005 ret
= lttng_strncpy(data
.u
.generate_filter_bytecode
.filter_expression
, filter_expression
,
2006 sizeof(data
.u
.generate_filter_bytecode
.filter_expression
));
2011 run_as(RUN_AS_GENERATE_FILTER_BYTECODE
, &data
, &run_as_ret
, uid
, gid
);
2012 errno
= run_as_ret
._errno
;
2013 if (run_as_ret
._error
) {
2018 view_bytecode
= (const struct lttng_bytecode
*) run_as_ret
.u
.generate_filter_bytecode
.bytecode
;
2020 local_bytecode
= zmalloc(sizeof(*local_bytecode
) + view_bytecode
->len
);
2021 if (!local_bytecode
) {
2026 memcpy(local_bytecode
, run_as_ret
.u
.generate_filter_bytecode
.bytecode
,
2027 sizeof(*local_bytecode
) + view_bytecode
->len
);
2028 *bytecode
= local_bytecode
;
2034 int run_as_create_worker(const char *procname
,
2035 post_fork_cleanup_cb clean_up_func
,
2036 void *clean_up_user_data
)
2040 pthread_mutex_lock(&worker_lock
);
2041 ret
= run_as_create_worker_no_lock(procname
, clean_up_func
,
2042 clean_up_user_data
);
2043 pthread_mutex_unlock(&worker_lock
);
2048 void run_as_destroy_worker(void)
2050 pthread_mutex_lock(&worker_lock
);
2051 run_as_destroy_worker_no_lock();
2052 pthread_mutex_unlock(&worker_lock
);