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
21 #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>
44 #define GETPW_BUFFER_FALLBACK_SIZE 4096
48 typedef int (*run_as_fct
)(struct run_as_data
*data
, struct run_as_ret
*ret_value
);
53 RUN_AS_MKDIR_RECURSIVE
,
54 RUN_AS_MKDIRAT_RECURSIVE
,
61 RUN_AS_RMDIR_RECURSIVE
,
62 RUN_AS_RMDIRAT_RECURSIVE
,
65 RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
,
66 RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
,
67 RUN_AS_GENERATE_FILTER_BYTECODE
,
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) ({ \
182 if (command_properties[data_ptr->cmd].in_fds_offset != -1) { \
183 fds = (int *) ((char *) data_ptr + command_properties[data_ptr->cmd].in_fds_offset); \
188 #define COMMAND_OUT_FDS(cmd, ret_ptr) ({ \
190 if (command_properties[cmd].out_fds_offset != -1) { \
191 fds = (int *) ((char *) ret_ptr + command_properties[cmd].out_fds_offset); \
196 #define COMMAND_IN_FD_COUNT(data_ptr) ({ \
197 command_properties[data_ptr->cmd].in_fd_count; \
200 #define COMMAND_OUT_FD_COUNT(cmd) ({ \
201 command_properties[cmd].out_fd_count; \
204 #define COMMAND_USE_CWD_FD(data_ptr) command_properties[data_ptr->cmd].use_cwd_fd
206 struct run_as_command_properties
{
207 /* Set to -1 when not applicable. */
208 ptrdiff_t in_fds_offset
, out_fds_offset
;
209 unsigned int in_fd_count
, out_fd_count
;
213 static const struct run_as_command_properties command_properties
[] = {
215 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
216 .out_fds_offset
= -1,
222 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
223 .out_fds_offset
= -1,
229 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
230 .out_fds_offset
= -1,
236 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
237 .out_fds_offset
= -1,
243 .in_fds_offset
= offsetof(struct run_as_data
, u
.open
.dirfd
),
244 .out_fds_offset
= offsetof(struct run_as_ret
, u
.open
.fd
),
250 .in_fds_offset
= offsetof(struct run_as_data
, u
.open
.dirfd
),
251 .out_fds_offset
= offsetof(struct run_as_ret
, u
.open
.fd
),
257 .in_fds_offset
= offsetof(struct run_as_data
, u
.unlink
.dirfd
),
258 .out_fds_offset
= -1,
264 .in_fds_offset
= offsetof(struct run_as_data
, u
.unlink
.dirfd
),
265 .out_fds_offset
= -1,
271 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
272 .out_fds_offset
= -1,
278 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
279 .out_fds_offset
= -1,
285 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
286 .out_fds_offset
= -1,
292 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
293 .out_fds_offset
= -1,
299 .in_fds_offset
= offsetof(struct run_as_data
, u
.rename
.dirfds
),
300 .out_fds_offset
= -1,
306 .in_fds_offset
= offsetof(struct run_as_data
, u
.rename
.dirfds
),
307 .out_fds_offset
= -1,
313 .in_fds_offset
= offsetof(struct run_as_data
,
314 u
.extract_elf_symbol_offset
.fd
),
315 .out_fds_offset
= -1,
321 .in_fds_offset
= offsetof(struct run_as_data
,
322 u
.extract_sdt_probe_offsets
.fd
),
323 .out_fds_offset
= -1,
330 .out_fds_offset
= -1,
337 struct run_as_worker_data
{
338 pid_t pid
; /* Worker PID. */
343 /* Single global worker per process (for now). */
344 static run_as_worker_data
*global_worker
;
345 /* Lock protecting the worker. */
346 static pthread_mutex_t worker_lock
= PTHREAD_MUTEX_INITIALIZER
;
358 return !lttng_secure_getenv("LTTNG_DEBUG_NOCLONE");
363 * Create recursively directory using the FULL path.
366 int _mkdirat_recursive(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
370 struct lttng_directory_handle
*handle
;
372 path
= data
->u
.mkdir
.path
;
373 mode
= data
->u
.mkdir
.mode
;
375 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.mkdir
.dirfd
);
377 ret_value
->_errno
= errno
;
378 ret_value
->_error
= true;
379 ret_value
->u
.ret
= -1;
382 /* Ownership of dirfd is transferred to the handle. */
383 data
->u
.mkdir
.dirfd
= -1;
384 /* Safe to call as we have transitioned to the requested uid/gid. */
385 ret_value
->u
.ret
= lttng_directory_handle_create_subdirectory_recursive(
387 ret_value
->_errno
= errno
;
388 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
389 lttng_directory_handle_put(handle
);
391 return ret_value
->u
.ret
;
395 int _mkdirat(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
399 struct lttng_directory_handle
*handle
;
401 path
= data
->u
.mkdir
.path
;
402 mode
= data
->u
.mkdir
.mode
;
404 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.mkdir
.dirfd
);
406 ret_value
->u
.ret
= -1;
407 ret_value
->_errno
= errno
;
408 ret_value
->_error
= true;
411 /* Ownership of dirfd is transferred to the handle. */
412 data
->u
.mkdir
.dirfd
= -1;
413 /* Safe to call as we have transitioned to the requested uid/gid. */
414 ret_value
->u
.ret
= lttng_directory_handle_create_subdirectory(
416 ret_value
->_errno
= errno
;
417 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
418 lttng_directory_handle_put(handle
);
420 return ret_value
->u
.ret
;
424 int _open(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
427 struct lttng_directory_handle
*handle
;
429 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.open
.dirfd
);
431 ret_value
->_errno
= errno
;
432 ret_value
->_error
= true;
433 ret_value
->u
.ret
= -1;
436 /* Ownership of dirfd is transferred to the handle. */
437 data
->u
.open
.dirfd
= -1;
439 fd
= lttng_directory_handle_open_file(handle
,
440 data
->u
.open
.path
, data
->u
.open
.flags
,
443 ret_value
->u
.ret
= -1;
444 ret_value
->u
.open
.fd
= -1;
446 ret_value
->u
.ret
= 0;
447 ret_value
->u
.open
.fd
= fd
;
450 ret_value
->_errno
= errno
;
451 ret_value
->_error
= fd
< 0;
452 lttng_directory_handle_put(handle
);
454 return ret_value
->u
.ret
;
458 int _unlink(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
460 struct lttng_directory_handle
*handle
;
462 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.unlink
.dirfd
);
464 ret_value
->u
.ret
= -1;
465 ret_value
->_errno
= errno
;
466 ret_value
->_error
= true;
470 /* Ownership of dirfd is transferred to the handle. */
471 data
->u
.unlink
.dirfd
= -1;
473 ret_value
->u
.ret
= lttng_directory_handle_unlink_file(handle
,
474 data
->u
.unlink
.path
);
475 ret_value
->_errno
= errno
;
476 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
477 lttng_directory_handle_put(handle
);
479 return ret_value
->u
.ret
;
483 int _rmdir(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
485 struct lttng_directory_handle
*handle
;
487 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.rmdir
.dirfd
);
489 ret_value
->u
.ret
= -1;
490 ret_value
->_errno
= errno
;
491 ret_value
->_error
= true;
495 /* Ownership of dirfd is transferred to the handle. */
496 data
->u
.rmdir
.dirfd
= -1;
498 ret_value
->u
.ret
= lttng_directory_handle_remove_subdirectory(
499 handle
, data
->u
.rmdir
.path
);
500 ret_value
->_errno
= errno
;
501 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
502 lttng_directory_handle_put(handle
);
504 return ret_value
->u
.ret
;
508 int _rmdir_recursive(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
510 struct lttng_directory_handle
*handle
;
512 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.rmdir
.dirfd
);
514 ret_value
->u
.ret
= -1;
515 ret_value
->_errno
= errno
;
516 ret_value
->_error
= true;
520 /* Ownership of dirfd is transferred to the handle. */
521 data
->u
.rmdir
.dirfd
= -1;
523 ret_value
->u
.ret
= lttng_directory_handle_remove_subdirectory_recursive(
524 handle
, data
->u
.rmdir
.path
, data
->u
.rmdir
.flags
);
525 ret_value
->_errno
= errno
;
526 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
527 lttng_directory_handle_put(handle
);
529 return ret_value
->u
.ret
;
533 int _rename(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
535 const char *old_path
, *new_path
;
536 struct lttng_directory_handle
*old_handle
= NULL
, *new_handle
= NULL
;
538 old_path
= data
->u
.rename
.old_path
;
539 new_path
= data
->u
.rename
.new_path
;
541 old_handle
= lttng_directory_handle_create_from_dirfd(
542 data
->u
.rename
.dirfds
[0]);
544 ret_value
->u
.ret
= -1;
547 new_handle
= lttng_directory_handle_create_from_dirfd(
548 data
->u
.rename
.dirfds
[1]);
550 ret_value
->u
.ret
= -1;
554 /* Ownership of dirfds are transferred to the handles. */
555 data
->u
.rename
.dirfds
[0] = data
->u
.rename
.dirfds
[1] = -1;
557 /* Safe to call as we have transitioned to the requested uid/gid. */
558 ret_value
->u
.ret
= lttng_directory_handle_rename(
559 old_handle
, old_path
, new_handle
, new_path
);
561 lttng_directory_handle_put(old_handle
);
562 lttng_directory_handle_put(new_handle
);
563 ret_value
->_errno
= errno
;
564 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
565 return ret_value
->u
.ret
;
570 int _extract_elf_symbol_offset(struct run_as_data
*data
,
571 struct run_as_ret
*ret_value
)
576 ret_value
->_error
= false;
577 ret
= lttng_elf_get_symbol_offset(data
->u
.extract_elf_symbol_offset
.fd
,
578 data
->u
.extract_elf_symbol_offset
.function
,
581 DBG("Failed to extract ELF function offset");
582 ret_value
->_error
= true;
584 ret_value
->u
.extract_elf_symbol_offset
.offset
= offset
;
590 int _extract_sdt_probe_offsets(struct run_as_data
*data
,
591 struct run_as_ret
*ret_value
)
594 uint64_t *offsets
= NULL
;
597 ret_value
->_error
= false;
599 /* On success, this call allocates the offsets paramater. */
600 ret
= lttng_elf_get_sdt_probe_offsets(
601 data
->u
.extract_sdt_probe_offsets
.fd
,
602 data
->u
.extract_sdt_probe_offsets
.provider_name
,
603 data
->u
.extract_sdt_probe_offsets
.probe_name
,
604 &offsets
, &num_offset
);
607 DBG("Failed to extract SDT probe offsets");
608 ret_value
->_error
= true;
612 if (num_offset
<= 0 || num_offset
> LTTNG_KERNEL_ABI_MAX_UPROBE_NUM
) {
613 DBG("Wrong number of probes.");
615 ret_value
->_error
= true;
619 /* Copy the content of the offsets array to the ret struct. */
620 memcpy(ret_value
->u
.extract_sdt_probe_offsets
.offsets
,
621 offsets
, num_offset
* sizeof(uint64_t));
623 ret_value
->u
.extract_sdt_probe_offsets
.num_offset
= num_offset
;
632 int _extract_elf_symbol_offset(struct run_as_data
*data
,
633 struct run_as_ret
*ret_value
)
635 ERR("Unimplemented runas command RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET");
640 int _extract_sdt_probe_offsets(struct run_as_data
*data
,
641 struct run_as_ret
*ret_value
)
643 ERR("Unimplemented runas command RUN_AS_EXTRACT_SDT_PROBE_OFFSETS");
649 int _generate_filter_bytecode(struct run_as_data
*data
,
650 struct run_as_ret
*ret_value
) {
652 const char *filter_expression
= NULL
;
653 struct filter_parser_ctx
*ctx
= NULL
;
655 ret_value
->_error
= false;
657 filter_expression
= data
->u
.generate_filter_bytecode
.filter_expression
;
659 if (lttng_strnlen(filter_expression
, LTTNG_FILTER_MAX_LEN
- 1) == LTTNG_FILTER_MAX_LEN
- 1) {
660 ret_value
->_error
= true;
665 ret
= filter_parser_ctx_create_from_filter_expression(filter_expression
, &ctx
);
667 ret_value
->_error
= true;
672 DBG("Size of bytecode generated: %u bytes.",
673 bytecode_get_len(&ctx
->bytecode
->b
));
675 /* Copy the lttng_bytecode_filter object to the return structure. */
676 memcpy(ret_value
->u
.generate_filter_bytecode
.bytecode
,
678 sizeof(ctx
->bytecode
->b
) +
679 bytecode_get_len(&ctx
->bytecode
->b
));
683 filter_bytecode_free(ctx
);
685 filter_parser_ctx_free(ctx
);
691 run_as_fct
run_as_enum_to_fct(enum run_as_cmd cmd
)
697 case RUN_AS_MKDIR_RECURSIVE
:
698 case RUN_AS_MKDIRAT_RECURSIVE
:
699 return _mkdirat_recursive
;
704 case RUN_AS_UNLINKAT
:
709 case RUN_AS_RMDIR_RECURSIVE
:
710 case RUN_AS_RMDIRAT_RECURSIVE
:
711 return _rmdir_recursive
;
713 case RUN_AS_RENAMEAT
:
715 case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
:
716 return _extract_elf_symbol_offset
;
717 case RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
:
718 return _extract_sdt_probe_offsets
;
719 case RUN_AS_GENERATE_FILTER_BYTECODE
:
720 return _generate_filter_bytecode
;
722 ERR("Unknown command %d", (int) cmd
);
728 int do_send_fds(int sock
, const int *fds
, unsigned int fd_count
)
733 for (i
= 0; i
< fd_count
; i
++) {
735 DBG("Attempt to send invalid file descriptor (fd = %i)",
737 /* Return 0 as this is not a fatal error. */
742 len
= lttcomm_send_fds_unix_sock(sock
, fds
, fd_count
);
743 return len
< 0 ? -1 : 0;
747 int do_recv_fds(int sock
, int *fds
, unsigned int fd_count
)
753 len
= lttcomm_recv_fds_unix_sock(sock
, fds
, fd_count
);
757 } else if (len
< 0) {
758 PERROR("Failed to receive file descriptors from socket");
763 for (i
= 0; i
< fd_count
; i
++) {
765 ERR("Invalid file descriptor received from worker (fd = %i)", fds
[i
]);
766 /* Return 0 as this is not a fatal error. */
774 int send_fds_to_worker(const run_as_worker_data
*worker
,
775 const struct run_as_data
*data
)
780 if (COMMAND_USE_CWD_FD(data
) || COMMAND_IN_FD_COUNT(data
) == 0) {
784 for (i
= 0; i
< COMMAND_IN_FD_COUNT(data
); i
++) {
785 if (COMMAND_IN_FDS(data
)[i
] < 0) {
786 ERR("Refusing to send invalid fd to worker (fd = %i)",
787 COMMAND_IN_FDS(data
)[i
]);
793 ret
= do_send_fds(worker
->sockpair
[0], COMMAND_IN_FDS(data
),
794 COMMAND_IN_FD_COUNT(data
));
796 PERROR("Failed to send file descriptor to run-as worker");
805 int send_fds_to_master(run_as_worker_data
*worker
, enum run_as_cmd cmd
,
806 struct run_as_ret
*run_as_ret
)
811 if (COMMAND_OUT_FD_COUNT(cmd
) == 0) {
815 ret
= do_send_fds(worker
->sockpair
[1], COMMAND_OUT_FDS(cmd
, run_as_ret
),
816 COMMAND_OUT_FD_COUNT(cmd
));
818 PERROR("Failed to send file descriptor to master process");
822 for (i
= 0; i
< COMMAND_OUT_FD_COUNT(cmd
); i
++) {
823 int fd
= COMMAND_OUT_FDS(cmd
, run_as_ret
)[i
];
825 int ret_close
= close(fd
);
828 PERROR("Failed to close result file descriptor (fd = %i)",
838 int recv_fds_from_worker(const run_as_worker_data
*worker
, enum run_as_cmd cmd
,
839 struct run_as_ret
*run_as_ret
)
843 if (COMMAND_OUT_FD_COUNT(cmd
) == 0) {
847 ret
= do_recv_fds(worker
->sockpair
[0], COMMAND_OUT_FDS(cmd
, run_as_ret
),
848 COMMAND_OUT_FD_COUNT(cmd
));
850 PERROR("Failed to receive file descriptor from run-as worker");
858 int recv_fds_from_master(run_as_worker_data
*worker
, struct run_as_data
*data
)
862 if (COMMAND_USE_CWD_FD(data
)) {
865 for (i
= 0; i
< COMMAND_IN_FD_COUNT(data
); i
++) {
866 COMMAND_IN_FDS(data
)[i
] = AT_FDCWD
;
871 if (COMMAND_IN_FD_COUNT(data
) == 0) {
875 ret
= do_recv_fds(worker
->sockpair
[1], COMMAND_IN_FDS(data
),
876 COMMAND_IN_FD_COUNT(data
));
878 PERROR("Failed to receive file descriptors from master process");
886 int cleanup_received_fds(struct run_as_data
*data
)
890 for (i
= 0; i
< COMMAND_IN_FD_COUNT(data
); i
++) {
891 if (COMMAND_IN_FDS(data
)[i
] == -1) {
894 ret
= close(COMMAND_IN_FDS(data
)[i
]);
896 PERROR("Failed to close file descriptor received fd in run-as worker");
904 static int get_user_infos_from_uid(
905 uid_t uid
, char **username
, gid_t
*primary_gid
)
909 long raw_get_pw_buf_size
;
910 size_t get_pw_buf_size
;
912 struct passwd
*result
= NULL
;
914 /* Fetch the max size for the temporary buffer. */
916 raw_get_pw_buf_size
= sysconf(_SC_GETPW_R_SIZE_MAX
);
917 if (raw_get_pw_buf_size
< 0) {
919 PERROR("Failed to query _SC_GETPW_R_SIZE_MAX");
923 /* Limit is indeterminate. */
924 WARN("Failed to query _SC_GETPW_R_SIZE_MAX as it is "
925 "indeterminate; falling back to default buffer size");
926 raw_get_pw_buf_size
= GETPW_BUFFER_FALLBACK_SIZE
;
929 get_pw_buf_size
= (size_t) raw_get_pw_buf_size
;
931 buf
= (char *) zmalloc(get_pw_buf_size
);
933 PERROR("Failed to allocate buffer to get password file entries");
937 ret
= getpwuid_r(uid
, &pwd
, buf
, get_pw_buf_size
, &result
);
939 PERROR("Failed to get user information for user: uid = %d",
944 if (result
== NULL
) {
945 ERR("Failed to find user information in password entries: uid = %d",
951 *username
= strdup(result
->pw_name
);
952 if (*username
== NULL
) {
953 PERROR("Failed to copy user name");
957 *primary_gid
= result
->pw_gid
;
969 static int demote_creds(
970 uid_t prev_uid
, gid_t prev_gid
, uid_t new_uid
, gid_t new_gid
)
974 char *username
= NULL
;
976 /* Change the group id. */
977 if (prev_gid
!= new_gid
) {
978 ret
= setegid(new_gid
);
980 PERROR("Failed to set effective group id: new_gid = %d",
986 /* Change the user id. */
987 if (prev_uid
!= new_uid
) {
988 ret
= get_user_infos_from_uid(new_uid
, &username
, &primary_gid
);
994 * Initialize the supplementary group access list.
996 * This is needed to handle cases where the supplementary groups
997 * of the user the process is demoting-to would give it access
998 * to a given file/folder, but not it's primary group.
1002 * Primary Group: User1
1003 * Secondary group: Disk, Network
1005 * mkdir inside the following directory must work since User1
1006 * is part of the Network group.
1008 * drwxrwx--- 2 root Network 4096 Jul 23 17:17 /tmp/my_folder/
1011 * The order of the following initgroups and seteuid calls is
1013 * Only a root process or one with CAP_SETGID capability can
1014 * call the the initgroups() function. We must initialize the
1015 * supplementary groups before we change the effective
1016 * UID to a less-privileged user.
1018 ret
= initgroups(username
, primary_gid
);
1020 PERROR("Failed to init the supplementary group access list: "
1021 "username = `%s`, primary gid = %d", username
,
1026 ret
= seteuid(new_uid
);
1028 PERROR("Failed to set effective user id: new_uid = %d",
1038 static int promote_creds(
1039 uid_t prev_uid
, gid_t prev_gid
, uid_t new_uid
, gid_t new_gid
)
1043 char *username
= NULL
;
1045 /* Change the group id. */
1046 if (prev_gid
!= new_gid
) {
1047 ret
= setegid(new_gid
);
1049 PERROR("Failed to set effective group id: new_gid = %d",
1055 /* Change the user id. */
1056 if (prev_uid
!= new_uid
) {
1057 ret
= get_user_infos_from_uid(new_uid
, &username
, &primary_gid
);
1063 * seteuid call must be done before the initgroups call because
1064 * we need to be privileged (CAP_SETGID) to call initgroups().
1066 ret
= seteuid(new_uid
);
1068 PERROR("Failed to set effective user id: new_uid = %d",
1074 * Initialize the supplementary group access list.
1076 * There is a possibility the groups we set in the following
1077 * initgroups() call are not exactly the same as the ones we
1078 * had when we originally demoted. This can happen if the
1079 * /etc/group file is modified after the runas process is
1080 * forked. This is very unlikely.
1082 ret
= initgroups(username
, primary_gid
);
1084 PERROR("Failed to init the supplementary group access "
1085 "list: username = `%s`, primary gid = %d",
1086 username
, (int) primary_gid
)
1096 * Return < 0 on error, 0 if OK, 1 on hangup.
1099 int handle_one_cmd(run_as_worker_data
*worker
)
1101 int ret
= 0, promote_ret
;
1102 struct run_as_data data
= {};
1103 ssize_t readlen
, writelen
;
1104 struct run_as_ret sendret
= {};
1106 const uid_t prev_ruid
= getuid();
1107 const gid_t prev_rgid
= getgid();
1110 * Stage 1: Receive run_as_data struct from the master.
1111 * The structure contains the command type and all the parameters needed for
1114 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[1], &data
,
1121 if (readlen
< sizeof(data
)) {
1122 PERROR("lttcomm_recv_unix_sock error");
1127 cmd
= run_as_enum_to_fct(data
.cmd
);
1134 * Stage 2: Receive file descriptor from master.
1135 * Some commands need a file descriptor as input so if it's needed we
1136 * receive the fd using the Unix socket.
1138 ret
= recv_fds_from_master(worker
, &data
);
1140 PERROR("recv_fd_from_master error");
1145 ret
= demote_creds(prev_ruid
, prev_rgid
, data
.uid
, data
.gid
);
1151 * Also set umask to 0 for mkdir executable bit.
1156 * Stage 3: Execute the command
1158 ret
= (*cmd
)(&data
, &sendret
);
1160 DBG("Execution of command returned an error");
1164 ret
= cleanup_received_fds(&data
);
1166 ERR("Error cleaning up FD");
1171 * Stage 4: Send run_as_ret structure to the master.
1172 * This structure contain the return value of the command and the errno.
1174 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[1], &sendret
,
1176 if (writelen
< sizeof(sendret
)) {
1177 PERROR("lttcomm_send_unix_sock error");
1183 * Stage 5: Send resulting file descriptors to the master.
1185 ret
= send_fds_to_master(worker
, data
.cmd
, &sendret
);
1187 DBG("Sending FD to master returned an error");
1193 /* Return to previous uid/gid. */
1194 promote_ret
= promote_creds(data
.uid
, data
.gid
, prev_ruid
, prev_rgid
);
1195 if (promote_ret
< 0) {
1196 ERR("Failed to promote back to the initial credentials");
1204 int run_as_worker(run_as_worker_data
*worker
)
1208 struct run_as_ret sendret
;
1209 size_t proc_orig_len
;
1212 * Initialize worker. Set a different process cmdline.
1214 proc_orig_len
= strlen(worker
->procname
);
1215 memset(worker
->procname
, 0, proc_orig_len
);
1216 strncpy(worker
->procname
, DEFAULT_RUN_AS_WORKER_NAME
, proc_orig_len
);
1218 ret
= lttng_thread_setname(DEFAULT_RUN_AS_WORKER_NAME
);
1219 if (ret
&& ret
!= -ENOSYS
) {
1220 /* Don't fail as this is not essential. */
1221 DBG("Failed to set pthread name attribute");
1224 memset(&sendret
, 0, sizeof(sendret
));
1226 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[1], &sendret
,
1228 if (writelen
< sizeof(sendret
)) {
1229 PERROR("lttcomm_send_unix_sock error");
1235 ret
= handle_one_cmd(worker
);
1239 } else if (ret
> 0) {
1242 continue; /* Next command. */
1251 int run_as_cmd(run_as_worker_data
*worker
,
1252 enum run_as_cmd cmd
,
1253 struct run_as_data
*data
,
1254 struct run_as_ret
*ret_value
,
1255 uid_t uid
, gid_t gid
)
1258 ssize_t readlen
, writelen
;
1261 * If we are non-root, we can only deal with our own uid.
1263 if (geteuid() != 0) {
1264 if (uid
!= geteuid()) {
1266 ret_value
->_errno
= EPERM
;
1267 ERR("Client (%d)/Server (%d) UID mismatch (and sessiond is not root)",
1268 (int) uid
, (int) geteuid());
1278 * Stage 1: Send the run_as_data struct to the worker process
1280 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[0], data
,
1282 if (writelen
< sizeof(*data
)) {
1283 PERROR("Error writing message to run_as");
1285 ret_value
->_errno
= EIO
;
1290 * Stage 2: Send file descriptor to the worker process if needed
1292 ret
= send_fds_to_worker(worker
, data
);
1294 PERROR("do_send_fd error");
1296 ret_value
->_errno
= EIO
;
1301 * Stage 3: Wait for the execution of the command
1305 * Stage 4: Receive the run_as_ret struct containing the return value and
1308 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[0], ret_value
,
1309 sizeof(*ret_value
));
1311 ERR("Run-as worker has hung-up during run_as_cmd");
1313 ret_value
->_errno
= EIO
;
1315 } else if (readlen
< sizeof(*ret_value
)) {
1316 PERROR("Error reading response from run_as");
1318 ret_value
->_errno
= errno
;
1322 if (ret_value
->_error
) {
1323 /* Skip stage 5 on error as there will be no fd to receive. */
1328 * Stage 5: Receive file descriptor if needed
1330 ret
= recv_fds_from_worker(worker
, cmd
, ret_value
);
1332 ERR("Error receiving fd");
1334 ret_value
->_errno
= EIO
;
1342 * This is for debugging ONLY and should not be considered secure.
1345 int run_as_noworker(enum run_as_cmd cmd
,
1346 struct run_as_data
*data
, struct run_as_ret
*ret_value
,
1347 uid_t uid
, gid_t gid
)
1349 int ret
, saved_errno
;
1353 fct
= run_as_enum_to_fct(cmd
);
1359 old_mask
= umask(0);
1360 ret
= fct(data
, ret_value
);
1361 saved_errno
= ret_value
->_errno
;
1363 errno
= saved_errno
;
1369 int reset_sighandler(void)
1373 DBG("Resetting run_as worker signal handlers to default");
1374 for (sig
= 1; sig
<= 31; sig
++) {
1375 (void) signal(sig
, SIG_DFL
);
1381 void worker_sighandler(int sig
)
1383 const char *signame
;
1386 * The worker will inherit its parent's signals since they are part of
1387 * the same process group. However, in the case of SIGINT and SIGTERM,
1388 * we want to give the worker a chance to teardown gracefully when its
1389 * parent closes the command socket.
1396 signame
= "SIGTERM";
1403 DBG("run_as worker received signal %s", signame
);
1405 DBG("run_as_worker received signal %d", sig
);
1410 int set_worker_sighandlers(void)
1414 struct sigaction sa
;
1416 if ((ret
= sigemptyset(&sigset
)) < 0) {
1417 PERROR("sigemptyset");
1421 sa
.sa_handler
= worker_sighandler
;
1422 sa
.sa_mask
= sigset
;
1424 if ((ret
= sigaction(SIGINT
, &sa
, NULL
)) < 0) {
1425 PERROR("sigaction SIGINT");
1429 if ((ret
= sigaction(SIGTERM
, &sa
, NULL
)) < 0) {
1430 PERROR("sigaction SIGTERM");
1434 DBG("run_as signal handler set for SIGTERM and SIGINT");
1440 int run_as_create_worker_no_lock(const char *procname
,
1441 post_fork_cleanup_cb clean_up_func
,
1442 void *clean_up_user_data
)
1447 struct run_as_ret recvret
;
1448 run_as_worker_data
*worker
;
1450 LTTNG_ASSERT(!global_worker
);
1453 * Don't initialize a worker, all run_as tasks will be performed
1454 * in the current process.
1459 worker
= (run_as_worker_data
*) zmalloc(sizeof(*worker
));
1464 worker
->procname
= strdup(procname
);
1465 if (!worker
->procname
) {
1467 goto error_procname_alloc
;
1469 /* Create unix socket. */
1470 if (lttcomm_create_anon_unix_socketpair(worker
->sockpair
) < 0) {
1481 } else if (pid
== 0) {
1486 set_worker_sighandlers();
1488 logger_set_thread_name("Run-as worker", true);
1490 if (clean_up_func
) {
1491 if (clean_up_func(clean_up_user_data
) < 0) {
1492 ERR("Run-as post-fork clean-up failed, exiting.");
1497 /* Just close, no shutdown. */
1498 if (close(worker
->sockpair
[0])) {
1504 * Close all FDs aside from STDIN, STDOUT, STDERR and sockpair[1]
1505 * Sockpair[1] is used as a control channel with the master
1507 for (i
= 3; i
< sysconf(_SC_OPEN_MAX
); i
++) {
1508 if (i
!= worker
->sockpair
[1]) {
1513 worker
->sockpair
[0] = -1;
1514 ret
= run_as_worker(worker
);
1515 if (lttcomm_close_unix_sock(worker
->sockpair
[1])) {
1519 worker
->sockpair
[1] = -1;
1520 free(worker
->procname
);
1522 LOG(ret
? PRINT_ERR
: PRINT_DBG
, "run_as worker exiting (ret = %d)", ret
);
1523 exit(ret
? EXIT_FAILURE
: EXIT_SUCCESS
);
1527 /* Just close, no shutdown. */
1528 if (close(worker
->sockpair
[1])) {
1533 worker
->sockpair
[1] = -1;
1535 /* Wait for worker to become ready. */
1536 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[0],
1537 &recvret
, sizeof(recvret
));
1538 if (readlen
< sizeof(recvret
)) {
1539 ERR("readlen: %zd", readlen
);
1540 PERROR("Error reading response from run_as at creation");
1544 global_worker
= worker
;
1549 /* Error handling. */
1551 for (i
= 0; i
< 2; i
++) {
1552 if (worker
->sockpair
[i
] < 0) {
1555 if (lttcomm_close_unix_sock(worker
->sockpair
[i
])) {
1558 worker
->sockpair
[i
] = -1;
1561 free(worker
->procname
);
1562 error_procname_alloc
:
1568 void run_as_destroy_worker_no_lock(void)
1570 run_as_worker_data
*worker
= global_worker
;
1572 DBG("Destroying run_as worker");
1576 /* Close unix socket */
1577 DBG("Closing run_as worker socket");
1578 if (lttcomm_close_unix_sock(worker
->sockpair
[0])) {
1581 worker
->sockpair
[0] = -1;
1582 /* Wait for worker. */
1587 wait_ret
= waitpid(worker
->pid
, &status
, 0);
1589 if (errno
== EINTR
) {
1596 if (WIFEXITED(status
)) {
1597 LOG(WEXITSTATUS(status
) == 0 ? PRINT_DBG
: PRINT_ERR
,
1598 DEFAULT_RUN_AS_WORKER_NAME
" terminated with status code %d",
1599 WEXITSTATUS(status
));
1601 } else if (WIFSIGNALED(status
)) {
1602 ERR(DEFAULT_RUN_AS_WORKER_NAME
" was killed by signal %d",
1607 free(worker
->procname
);
1609 global_worker
= NULL
;
1613 int run_as_restart_worker(run_as_worker_data
*worker
)
1616 char *procname
= NULL
;
1618 procname
= worker
->procname
;
1620 /* Close socket to run_as worker process and clean up the zombie process */
1621 run_as_destroy_worker_no_lock();
1623 /* Create a new run_as worker process*/
1624 ret
= run_as_create_worker_no_lock(procname
, NULL
, NULL
);
1626 ERR("Restarting the worker process failed");
1635 int run_as(enum run_as_cmd cmd
, struct run_as_data
*data
,
1636 struct run_as_ret
*ret_value
, uid_t uid
, gid_t gid
)
1638 int ret
, saved_errno
;
1640 pthread_mutex_lock(&worker_lock
);
1642 DBG("Using run_as worker");
1644 LTTNG_ASSERT(global_worker
);
1646 ret
= run_as_cmd(global_worker
, cmd
, data
, ret_value
, uid
, gid
);
1647 saved_errno
= ret_value
->_errno
;
1650 * If the worker thread crashed the errno is set to EIO. we log
1651 * the error and start a new worker process.
1653 if (ret
== -1 && saved_errno
== EIO
) {
1654 DBG("Socket closed unexpectedly... "
1655 "Restarting the worker process");
1656 ret
= run_as_restart_worker(global_worker
);
1658 ERR("Failed to restart worker process.");
1663 DBG("Using run_as without worker");
1664 ret
= run_as_noworker(cmd
, data
, ret_value
, uid
, gid
);
1667 pthread_mutex_unlock(&worker_lock
);
1671 int run_as_mkdir_recursive(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
1673 return run_as_mkdirat_recursive(AT_FDCWD
, path
, mode
, uid
, gid
);
1676 int run_as_mkdirat_recursive(int dirfd
, const char *path
, mode_t mode
,
1677 uid_t uid
, gid_t gid
)
1680 struct run_as_data data
= {};
1681 struct run_as_ret run_as_ret
= {};
1683 DBG3("mkdirat() recursive fd = %d%s, path = %s, mode = %d, uid = %d, gid = %d",
1684 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1685 path
, (int) mode
, (int) uid
, (int) gid
);
1686 ret
= lttng_strncpy(data
.u
.mkdir
.path
, path
,
1687 sizeof(data
.u
.mkdir
.path
));
1689 ERR("Failed to copy path argument of mkdirat recursive command");
1692 data
.u
.mkdir
.path
[sizeof(data
.u
.mkdir
.path
) - 1] = '\0';
1693 data
.u
.mkdir
.mode
= mode
;
1694 data
.u
.mkdir
.dirfd
= dirfd
;
1695 run_as(dirfd
== AT_FDCWD
? RUN_AS_MKDIR_RECURSIVE
: RUN_AS_MKDIRAT_RECURSIVE
,
1696 &data
, &run_as_ret
, uid
, gid
);
1697 errno
= run_as_ret
._errno
;
1698 ret
= run_as_ret
.u
.ret
;
1703 int run_as_mkdir(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
1705 return run_as_mkdirat(AT_FDCWD
, path
, mode
, uid
, gid
);
1708 int run_as_mkdirat(int dirfd
, const char *path
, mode_t mode
,
1709 uid_t uid
, gid_t gid
)
1712 struct run_as_data data
= {};
1713 struct run_as_ret run_as_ret
= {};
1715 DBG3("mkdirat() recursive fd = %d%s, path = %s, mode = %d, uid = %d, gid = %d",
1716 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1717 path
, (int) mode
, (int) uid
, (int) gid
);
1718 ret
= lttng_strncpy(data
.u
.mkdir
.path
, path
,
1719 sizeof(data
.u
.mkdir
.path
));
1721 ERR("Failed to copy path argument of mkdirat command");
1724 data
.u
.mkdir
.path
[sizeof(data
.u
.mkdir
.path
) - 1] = '\0';
1725 data
.u
.mkdir
.mode
= mode
;
1726 data
.u
.mkdir
.dirfd
= dirfd
;
1727 run_as(dirfd
== AT_FDCWD
? RUN_AS_MKDIR
: RUN_AS_MKDIRAT
,
1728 &data
, &run_as_ret
, uid
, gid
);
1729 errno
= run_as_ret
._errno
;
1730 ret
= run_as_ret
.u
.ret
;
1735 int run_as_open(const char *path
, int flags
, mode_t mode
, uid_t uid
,
1738 return run_as_openat(AT_FDCWD
, path
, flags
, mode
, uid
, gid
);
1741 int run_as_openat(int dirfd
, const char *path
, int flags
, mode_t mode
,
1742 uid_t uid
, gid_t gid
)
1745 struct run_as_data data
= {};
1746 struct run_as_ret run_as_ret
= {};
1748 DBG3("openat() fd = %d%s, path = %s, flags = %X, mode = %d, uid %d, gid %d",
1749 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1750 path
, flags
, (int) mode
, (int) uid
, (int) gid
);
1751 ret
= lttng_strncpy(data
.u
.open
.path
, path
, sizeof(data
.u
.open
.path
));
1753 ERR("Failed to copy path argument of open command");
1756 data
.u
.open
.flags
= flags
;
1757 data
.u
.open
.mode
= mode
;
1758 data
.u
.open
.dirfd
= dirfd
;
1759 run_as(dirfd
== AT_FDCWD
? RUN_AS_OPEN
: RUN_AS_OPENAT
,
1760 &data
, &run_as_ret
, uid
, gid
);
1761 errno
= run_as_ret
._errno
;
1762 ret
= run_as_ret
.u
.ret
< 0 ? run_as_ret
.u
.ret
:
1763 run_as_ret
.u
.open
.fd
;
1768 int run_as_unlink(const char *path
, uid_t uid
, gid_t gid
)
1770 return run_as_unlinkat(AT_FDCWD
, path
, uid
, gid
);
1773 int run_as_unlinkat(int dirfd
, const char *path
, uid_t uid
, gid_t gid
)
1776 struct run_as_data data
= {};
1777 struct run_as_ret run_as_ret
= {};
1779 DBG3("unlinkat() fd = %d%s, path = %s, uid = %d, gid = %d",
1780 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1781 path
, (int) uid
, (int) gid
);
1782 ret
= lttng_strncpy(data
.u
.unlink
.path
, path
,
1783 sizeof(data
.u
.unlink
.path
));
1787 data
.u
.unlink
.dirfd
= dirfd
;
1788 run_as(dirfd
== AT_FDCWD
? RUN_AS_UNLINK
: RUN_AS_UNLINKAT
, &data
,
1789 &run_as_ret
, uid
, gid
);
1790 errno
= run_as_ret
._errno
;
1791 ret
= run_as_ret
.u
.ret
;
1796 int run_as_rmdir(const char *path
, uid_t uid
, gid_t gid
)
1798 return run_as_rmdirat(AT_FDCWD
, path
, uid
, gid
);
1801 int run_as_rmdirat(int dirfd
, const char *path
, uid_t uid
, gid_t gid
)
1804 struct run_as_data data
= {};
1805 struct run_as_ret run_as_ret
= {};
1807 DBG3("rmdirat() fd = %d%s, path = %s, uid = %d, gid = %d",
1808 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1809 path
, (int) uid
, (int) gid
);
1810 ret
= lttng_strncpy(data
.u
.rmdir
.path
, path
,
1811 sizeof(data
.u
.rmdir
.path
));
1815 data
.u
.rmdir
.dirfd
= dirfd
;
1816 run_as(dirfd
== AT_FDCWD
? RUN_AS_RMDIR
: RUN_AS_RMDIRAT
, &data
,
1817 &run_as_ret
, uid
, gid
);
1818 errno
= run_as_ret
._errno
;
1819 ret
= run_as_ret
.u
.ret
;
1824 int run_as_rmdir_recursive(const char *path
, uid_t uid
, gid_t gid
, int flags
)
1826 return run_as_rmdirat_recursive(AT_FDCWD
, path
, uid
, gid
, flags
);
1829 int run_as_rmdirat_recursive(int dirfd
, const char *path
, uid_t uid
, gid_t gid
, int flags
)
1832 struct run_as_data data
= {};
1833 struct run_as_ret run_as_ret
= {};
1835 DBG3("rmdirat() recursive fd = %d%s, path = %s, uid = %d, gid = %d",
1836 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1837 path
, (int) uid
, (int) gid
);
1838 ret
= lttng_strncpy(data
.u
.rmdir
.path
, path
,
1839 sizeof(data
.u
.rmdir
.path
));
1843 data
.u
.rmdir
.dirfd
= dirfd
;
1844 data
.u
.rmdir
.flags
= flags
;
1845 run_as(dirfd
== AT_FDCWD
? RUN_AS_RMDIR_RECURSIVE
: RUN_AS_RMDIRAT_RECURSIVE
,
1846 &data
, &run_as_ret
, uid
, gid
);
1847 errno
= run_as_ret
._errno
;
1848 ret
= run_as_ret
.u
.ret
;
1853 int run_as_rename(const char *old_name
, const char *new_name
, uid_t uid
, gid_t gid
)
1855 return run_as_renameat(AT_FDCWD
, old_name
, AT_FDCWD
, new_name
, uid
, gid
);
1858 int run_as_renameat(int old_dirfd
, const char *old_name
,
1859 int new_dirfd
, const char *new_name
, uid_t uid
, gid_t gid
)
1862 struct run_as_data data
= {};
1863 struct run_as_ret run_as_ret
= {};
1865 DBG3("renameat() old_dirfd = %d%s, old_name = %s, new_dirfd = %d%s, new_name = %s, uid = %d, gid = %d",
1866 old_dirfd
, old_dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1868 new_dirfd
, new_dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1869 new_name
, (int) uid
, (int) gid
);
1870 ret
= lttng_strncpy(data
.u
.rename
.old_path
, old_name
,
1871 sizeof(data
.u
.rename
.old_path
));
1875 ret
= lttng_strncpy(data
.u
.rename
.new_path
, new_name
,
1876 sizeof(data
.u
.rename
.new_path
));
1881 data
.u
.rename
.dirfds
[0] = old_dirfd
;
1882 data
.u
.rename
.dirfds
[1] = new_dirfd
;
1883 run_as(old_dirfd
== AT_FDCWD
&& new_dirfd
== AT_FDCWD
?
1884 RUN_AS_RENAME
: RUN_AS_RENAMEAT
,
1885 &data
, &run_as_ret
, uid
, gid
);
1886 errno
= run_as_ret
._errno
;
1887 ret
= run_as_ret
.u
.ret
;
1892 int run_as_extract_elf_symbol_offset(int fd
, const char* function
,
1893 uid_t uid
, gid_t gid
, uint64_t *offset
)
1896 struct run_as_data data
= {};
1897 struct run_as_ret run_as_ret
= {};
1899 DBG3("extract_elf_symbol_offset() on fd=%d and function=%s "
1900 "with for uid %d and gid %d", fd
, function
,
1901 (int) uid
, (int) gid
);
1903 data
.u
.extract_elf_symbol_offset
.fd
= fd
;
1905 strncpy(data
.u
.extract_elf_symbol_offset
.function
, function
, LTTNG_SYMBOL_NAME_LEN
- 1);
1906 data
.u
.extract_elf_symbol_offset
.function
[LTTNG_SYMBOL_NAME_LEN
- 1] = '\0';
1907 ret
= lttng_strncpy(data
.u
.extract_elf_symbol_offset
.function
,
1909 sizeof(data
.u
.extract_elf_symbol_offset
.function
));
1914 run_as(RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
, &data
, &run_as_ret
, uid
, gid
);
1915 errno
= run_as_ret
._errno
;
1916 if (run_as_ret
._error
) {
1921 *offset
= run_as_ret
.u
.extract_elf_symbol_offset
.offset
;
1926 int run_as_extract_sdt_probe_offsets(int fd
, const char* provider_name
,
1927 const char* probe_name
, uid_t uid
, gid_t gid
,
1928 uint64_t **offsets
, uint32_t *num_offset
)
1931 struct run_as_data data
= {};
1932 struct run_as_ret run_as_ret
= {};
1934 DBG3("extract_sdt_probe_offsets() on fd=%d, probe_name=%s and "
1935 "provider_name=%s with for uid %d and gid %d", fd
,
1936 probe_name
, provider_name
, (int) uid
, (int) gid
);
1938 data
.u
.extract_sdt_probe_offsets
.fd
= fd
;
1940 ret
= lttng_strncpy(data
.u
.extract_sdt_probe_offsets
.probe_name
, probe_name
,
1941 sizeof(data
.u
.extract_sdt_probe_offsets
.probe_name
));
1945 ret
= lttng_strncpy(data
.u
.extract_sdt_probe_offsets
.provider_name
,
1947 sizeof(data
.u
.extract_sdt_probe_offsets
.provider_name
));
1952 run_as(RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
, &data
, &run_as_ret
, uid
, gid
);
1953 errno
= run_as_ret
._errno
;
1954 if (run_as_ret
._error
) {
1959 *num_offset
= run_as_ret
.u
.extract_sdt_probe_offsets
.num_offset
;
1960 *offsets
= (uint64_t *) zmalloc(*num_offset
* sizeof(uint64_t));
1966 memcpy(*offsets
, run_as_ret
.u
.extract_sdt_probe_offsets
.offsets
,
1967 *num_offset
* sizeof(uint64_t));
1972 int run_as_generate_filter_bytecode(const char *filter_expression
,
1973 const struct lttng_credentials
*creds
,
1974 struct lttng_bytecode
**bytecode
)
1977 struct run_as_data data
= {};
1978 struct run_as_ret run_as_ret
= {};
1979 const struct lttng_bytecode
*view_bytecode
= NULL
;
1980 struct lttng_bytecode
*local_bytecode
= NULL
;
1981 const uid_t uid
= lttng_credentials_get_uid(creds
);
1982 const gid_t gid
= lttng_credentials_get_gid(creds
);
1984 DBG3("generate_filter_bytecode() from expression=\"%s\" for uid %d and gid %d",
1985 filter_expression
, (int) uid
, (int) gid
);
1987 ret
= lttng_strncpy(data
.u
.generate_filter_bytecode
.filter_expression
, filter_expression
,
1988 sizeof(data
.u
.generate_filter_bytecode
.filter_expression
));
1993 run_as(RUN_AS_GENERATE_FILTER_BYTECODE
, &data
, &run_as_ret
, uid
, gid
);
1994 errno
= run_as_ret
._errno
;
1995 if (run_as_ret
._error
) {
2000 view_bytecode
= (const struct lttng_bytecode
*) run_as_ret
.u
.generate_filter_bytecode
.bytecode
;
2002 local_bytecode
= (lttng_bytecode
*) zmalloc(sizeof(*local_bytecode
) + view_bytecode
->len
);
2003 if (!local_bytecode
) {
2008 memcpy(local_bytecode
, run_as_ret
.u
.generate_filter_bytecode
.bytecode
,
2009 sizeof(*local_bytecode
) + view_bytecode
->len
);
2010 *bytecode
= local_bytecode
;
2015 int run_as_create_worker(const char *procname
,
2016 post_fork_cleanup_cb clean_up_func
,
2017 void *clean_up_user_data
)
2021 pthread_mutex_lock(&worker_lock
);
2022 ret
= run_as_create_worker_no_lock(procname
, clean_up_func
,
2023 clean_up_user_data
);
2024 pthread_mutex_unlock(&worker_lock
);
2028 void run_as_destroy_worker(void)
2030 pthread_mutex_lock(&worker_lock
);
2031 run_as_destroy_worker_no_lock();
2032 pthread_mutex_unlock(&worker_lock
);