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/lttng-kernel.h>
27 #include <common/common.h>
28 #include <common/utils.h>
29 #include <common/compat/getenv.h>
30 #include <common/compat/prctl.h>
31 #include <common/unix.h>
32 #include <common/defaults.h>
33 #include <common/lttng-elf.h>
35 #include <lttng/constant.h>
39 #define GETPW_BUFFER_FALLBACK_SIZE 4096
43 typedef int (*run_as_fct
)(struct run_as_data
*data
, struct run_as_ret
*ret_value
);
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
,
64 struct run_as_mkdir_data
{
66 char path
[LTTNG_PATH_MAX
];
70 struct run_as_open_data
{
72 char path
[LTTNG_PATH_MAX
];
77 struct run_as_unlink_data
{
79 char path
[LTTNG_PATH_MAX
];
82 struct run_as_rmdir_data
{
84 char path
[LTTNG_PATH_MAX
];
85 int flags
; /* enum lttng_directory_handle_rmdir_recursive_flags */
88 struct run_as_extract_elf_symbol_offset_data
{
90 char function
[LTTNG_SYMBOL_NAME_LEN
];
93 struct run_as_extract_sdt_probe_offsets_data
{
95 char probe_name
[LTTNG_SYMBOL_NAME_LEN
];
96 char provider_name
[LTTNG_SYMBOL_NAME_LEN
];
99 struct run_as_rename_data
{
105 char old_path
[LTTNG_PATH_MAX
];
106 char new_path
[LTTNG_PATH_MAX
];
109 struct run_as_open_ret
{
113 struct run_as_extract_elf_symbol_offset_ret
{
117 struct run_as_extract_sdt_probe_offsets_ret
{
119 uint64_t offsets
[LTTNG_KERNEL_MAX_UPROBE_NUM
];
125 struct run_as_mkdir_data mkdir
;
126 struct run_as_open_data open
;
127 struct run_as_unlink_data unlink
;
128 struct run_as_rmdir_data rmdir
;
129 struct run_as_rename_data rename
;
130 struct run_as_extract_elf_symbol_offset_data extract_elf_symbol_offset
;
131 struct run_as_extract_sdt_probe_offsets_data extract_sdt_probe_offsets
;
138 * The run_as_ret structure holds the returned value and status of the command.
140 * The `u` union field holds the return value of the command; in most cases it
141 * represents the success or the failure of the command. In more complex
142 * commands, it holds a computed value.
144 * The _errno field is the errno recorded after the execution of the command.
146 * The _error fields is used the signify that return status of the command. For
147 * simple commands returning `int` the _error field will be the same as the
148 * ret_int field. In complex commands, it signify the success or failure of the
155 struct run_as_open_ret open
;
156 struct run_as_extract_elf_symbol_offset_ret extract_elf_symbol_offset
;
157 struct run_as_extract_sdt_probe_offsets_ret extract_sdt_probe_offsets
;
163 #define COMMAND_IN_FDS(data_ptr) ({ \
165 if (command_properties[data_ptr->cmd].in_fds_offset != -1) { \
166 fds = (int *) ((char *) data_ptr + command_properties[data_ptr->cmd].in_fds_offset); \
171 #define COMMAND_OUT_FDS(cmd, ret_ptr) ({ \
173 if (command_properties[cmd].out_fds_offset != -1) { \
174 fds = (int *) ((char *) ret_ptr + command_properties[cmd].out_fds_offset); \
179 #define COMMAND_IN_FD_COUNT(data_ptr) ({ \
180 command_properties[data_ptr->cmd].in_fd_count; \
183 #define COMMAND_OUT_FD_COUNT(cmd) ({ \
184 command_properties[cmd].out_fd_count; \
187 #define COMMAND_USE_CWD_FD(data_ptr) command_properties[data_ptr->cmd].use_cwd_fd
189 struct run_as_command_properties
{
190 /* Set to -1 when not applicable. */
191 ptrdiff_t in_fds_offset
, out_fds_offset
;
192 unsigned int in_fd_count
, out_fd_count
;
196 static const struct run_as_command_properties command_properties
[] = {
198 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
200 .out_fds_offset
= -1,
205 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
207 .out_fds_offset
= -1,
211 [RUN_AS_MKDIR_RECURSIVE
] = {
212 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
214 .out_fds_offset
= -1,
218 [RUN_AS_MKDIRAT_RECURSIVE
] = {
219 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
221 .out_fds_offset
= -1,
226 .in_fds_offset
= offsetof(struct run_as_data
, u
.open
.dirfd
),
228 .out_fds_offset
= offsetof(struct run_as_ret
, u
.open
.fd
),
233 .in_fds_offset
= offsetof(struct run_as_data
, u
.open
.dirfd
),
235 .out_fds_offset
= offsetof(struct run_as_ret
, u
.open
.fd
),
240 .in_fds_offset
= offsetof(struct run_as_data
, u
.unlink
.dirfd
),
242 .out_fds_offset
= -1,
246 [RUN_AS_UNLINKAT
] = {
247 .in_fds_offset
= offsetof(struct run_as_data
, u
.unlink
.dirfd
),
249 .out_fds_offset
= -1,
253 [RUN_AS_RMDIR_RECURSIVE
] = {
254 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
256 .out_fds_offset
= -1,
260 [RUN_AS_RMDIRAT_RECURSIVE
] = {
261 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
263 .out_fds_offset
= -1,
268 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
270 .out_fds_offset
= -1,
275 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
277 .out_fds_offset
= -1,
282 .in_fds_offset
= offsetof(struct run_as_data
, u
.rename
.dirfds
),
284 .out_fds_offset
= -1,
288 [RUN_AS_RENAMEAT
] = {
289 .in_fds_offset
= offsetof(struct run_as_data
, u
.rename
.dirfds
),
291 .out_fds_offset
= -1,
295 [RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
] = {
296 .in_fds_offset
= offsetof(struct run_as_data
,
297 u
.extract_elf_symbol_offset
.fd
),
299 .out_fds_offset
= -1,
303 [RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
] = {
304 .in_fds_offset
= offsetof(struct run_as_data
,
305 u
.extract_sdt_probe_offsets
.fd
),
307 .out_fds_offset
= -1,
313 struct run_as_worker
{
314 pid_t pid
; /* Worker PID. */
319 /* Single global worker per process (for now). */
320 static struct run_as_worker
*global_worker
;
321 /* Lock protecting the worker. */
322 static pthread_mutex_t worker_lock
= PTHREAD_MUTEX_INITIALIZER
;
334 return !lttng_secure_getenv("LTTNG_DEBUG_NOCLONE");
339 * Create recursively directory using the FULL path.
342 int _mkdirat_recursive(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
346 struct lttng_directory_handle
*handle
;
348 path
= data
->u
.mkdir
.path
;
349 mode
= data
->u
.mkdir
.mode
;
351 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.mkdir
.dirfd
);
353 ret_value
->_errno
= errno
;
354 ret_value
->_error
= true;
355 ret_value
->u
.ret
= -1;
358 /* Ownership of dirfd is transferred to the handle. */
359 data
->u
.mkdir
.dirfd
= -1;
360 /* Safe to call as we have transitioned to the requested uid/gid. */
361 ret_value
->u
.ret
= lttng_directory_handle_create_subdirectory_recursive(
363 ret_value
->_errno
= errno
;
364 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
365 lttng_directory_handle_put(handle
);
367 return ret_value
->u
.ret
;
371 int _mkdirat(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
375 struct lttng_directory_handle
*handle
;
377 path
= data
->u
.mkdir
.path
;
378 mode
= data
->u
.mkdir
.mode
;
380 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.mkdir
.dirfd
);
382 ret_value
->u
.ret
= -1;
383 ret_value
->_errno
= errno
;
384 ret_value
->_error
= true;
387 /* Ownership of dirfd is transferred to the handle. */
388 data
->u
.mkdir
.dirfd
= -1;
389 /* Safe to call as we have transitioned to the requested uid/gid. */
390 ret_value
->u
.ret
= lttng_directory_handle_create_subdirectory(
392 ret_value
->_errno
= errno
;
393 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
394 lttng_directory_handle_put(handle
);
396 return ret_value
->u
.ret
;
400 int _open(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
403 struct lttng_directory_handle
*handle
;
405 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.open
.dirfd
);
407 ret_value
->_errno
= errno
;
408 ret_value
->_error
= true;
409 ret_value
->u
.ret
= -1;
412 /* Ownership of dirfd is transferred to the handle. */
413 data
->u
.open
.dirfd
= -1;
415 fd
= lttng_directory_handle_open_file(handle
,
416 data
->u
.open
.path
, data
->u
.open
.flags
,
419 ret_value
->u
.ret
= -1;
420 ret_value
->u
.open
.fd
= -1;
422 ret_value
->u
.ret
= 0;
423 ret_value
->u
.open
.fd
= fd
;
426 ret_value
->_errno
= errno
;
427 ret_value
->_error
= fd
< 0;
428 lttng_directory_handle_put(handle
);
430 return ret_value
->u
.ret
;
434 int _unlink(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
436 struct lttng_directory_handle
*handle
;
438 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.unlink
.dirfd
);
440 ret_value
->u
.ret
= -1;
441 ret_value
->_errno
= errno
;
442 ret_value
->_error
= true;
446 /* Ownership of dirfd is transferred to the handle. */
447 data
->u
.unlink
.dirfd
= -1;
449 ret_value
->u
.ret
= lttng_directory_handle_unlink_file(handle
,
450 data
->u
.unlink
.path
);
451 ret_value
->_errno
= errno
;
452 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
453 lttng_directory_handle_put(handle
);
455 return ret_value
->u
.ret
;
459 int _rmdir(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
.rmdir
.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
.rmdir
.dirfd
= -1;
474 ret_value
->u
.ret
= lttng_directory_handle_remove_subdirectory(
475 handle
, data
->u
.rmdir
.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_recursive(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_recursive(
500 handle
, data
->u
.rmdir
.path
, data
->u
.rmdir
.flags
);
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 _rename(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
511 const char *old_path
, *new_path
;
512 struct lttng_directory_handle
*old_handle
= NULL
, *new_handle
= NULL
;
514 old_path
= data
->u
.rename
.old_path
;
515 new_path
= data
->u
.rename
.new_path
;
517 old_handle
= lttng_directory_handle_create_from_dirfd(
518 data
->u
.rename
.dirfds
[0]);
520 ret_value
->u
.ret
= -1;
523 new_handle
= lttng_directory_handle_create_from_dirfd(
524 data
->u
.rename
.dirfds
[1]);
526 ret_value
->u
.ret
= -1;
530 /* Ownership of dirfds are transferred to the handles. */
531 data
->u
.rename
.dirfds
[0] = data
->u
.rename
.dirfds
[1] = -1;
533 /* Safe to call as we have transitioned to the requested uid/gid. */
534 ret_value
->u
.ret
= lttng_directory_handle_rename(
535 old_handle
, old_path
, new_handle
, new_path
);
537 lttng_directory_handle_put(old_handle
);
538 lttng_directory_handle_put(new_handle
);
539 ret_value
->_errno
= errno
;
540 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
541 return ret_value
->u
.ret
;
546 int _extract_elf_symbol_offset(struct run_as_data
*data
,
547 struct run_as_ret
*ret_value
)
552 ret_value
->_error
= false;
553 ret
= lttng_elf_get_symbol_offset(data
->u
.extract_elf_symbol_offset
.fd
,
554 data
->u
.extract_elf_symbol_offset
.function
,
557 DBG("Failed to extract ELF function offset");
558 ret_value
->_error
= true;
560 ret_value
->u
.extract_elf_symbol_offset
.offset
= offset
;
566 int _extract_sdt_probe_offsets(struct run_as_data
*data
,
567 struct run_as_ret
*ret_value
)
570 uint64_t *offsets
= NULL
;
573 ret_value
->_error
= false;
575 /* On success, this call allocates the offsets paramater. */
576 ret
= lttng_elf_get_sdt_probe_offsets(
577 data
->u
.extract_sdt_probe_offsets
.fd
,
578 data
->u
.extract_sdt_probe_offsets
.provider_name
,
579 data
->u
.extract_sdt_probe_offsets
.probe_name
,
580 &offsets
, &num_offset
);
583 DBG("Failed to extract SDT probe offsets");
584 ret_value
->_error
= true;
588 if (num_offset
<= 0 || num_offset
> LTTNG_KERNEL_MAX_UPROBE_NUM
) {
589 DBG("Wrong number of probes.");
591 ret_value
->_error
= true;
595 /* Copy the content of the offsets array to the ret struct. */
596 memcpy(ret_value
->u
.extract_sdt_probe_offsets
.offsets
,
597 offsets
, num_offset
* sizeof(uint64_t));
599 ret_value
->u
.extract_sdt_probe_offsets
.num_offset
= num_offset
;
608 int _extract_elf_symbol_offset(struct run_as_data
*data
,
609 struct run_as_ret
*ret_value
)
611 ERR("Unimplemented runas command RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET");
616 int _extract_sdt_probe_offsets(struct run_as_data
*data
,
617 struct run_as_ret
*ret_value
)
619 ERR("Unimplemented runas command RUN_AS_EXTRACT_SDT_PROBE_OFFSETS");
625 run_as_fct
run_as_enum_to_fct(enum run_as_cmd cmd
)
631 case RUN_AS_MKDIR_RECURSIVE
:
632 case RUN_AS_MKDIRAT_RECURSIVE
:
633 return _mkdirat_recursive
;
638 case RUN_AS_UNLINKAT
:
643 case RUN_AS_RMDIR_RECURSIVE
:
644 case RUN_AS_RMDIRAT_RECURSIVE
:
645 return _rmdir_recursive
;
647 case RUN_AS_RENAMEAT
:
649 case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
:
650 return _extract_elf_symbol_offset
;
651 case RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
:
652 return _extract_sdt_probe_offsets
;
654 ERR("Unknown command %d", (int) cmd
);
660 int do_send_fds(int sock
, const int *fds
, unsigned int fd_count
)
665 for (i
= 0; i
< fd_count
; i
++) {
667 ERR("Attempt to send invalid file descriptor to master (fd = %i)",
669 /* Return 0 as this is not a fatal error. */
674 len
= lttcomm_send_fds_unix_sock(sock
, fds
, fd_count
);
675 return len
< 0 ? -1 : 0;
679 int do_recv_fds(int sock
, int *fds
, unsigned int fd_count
)
685 len
= lttcomm_recv_fds_unix_sock(sock
, fds
, fd_count
);
689 } else if (len
< 0) {
690 PERROR("Failed to receive file descriptors from socket");
695 for (i
= 0; i
< fd_count
; i
++) {
697 ERR("Invalid file descriptor received from worker (fd = %i)", fds
[i
]);
698 /* Return 0 as this is not a fatal error. */
706 int send_fds_to_worker(const struct run_as_worker
*worker
,
707 const struct run_as_data
*data
)
712 if (COMMAND_USE_CWD_FD(data
) || COMMAND_IN_FD_COUNT(data
) == 0) {
716 for (i
= 0; i
< COMMAND_IN_FD_COUNT(data
); i
++) {
717 if (COMMAND_IN_FDS(data
)[i
] < 0) {
718 ERR("Refusing to send invalid fd to worker (fd = %i)",
719 COMMAND_IN_FDS(data
)[i
]);
725 ret
= do_send_fds(worker
->sockpair
[0], COMMAND_IN_FDS(data
),
726 COMMAND_IN_FD_COUNT(data
));
728 PERROR("Failed to send file descriptor to run-as worker");
737 int send_fds_to_master(struct run_as_worker
*worker
, enum run_as_cmd cmd
,
738 struct run_as_ret
*run_as_ret
)
743 if (COMMAND_OUT_FD_COUNT(cmd
) == 0) {
747 ret
= do_send_fds(worker
->sockpair
[1], COMMAND_OUT_FDS(cmd
, run_as_ret
),
748 COMMAND_OUT_FD_COUNT(cmd
));
750 PERROR("Failed to send file descriptor to master process");
754 for (i
= 0; i
< COMMAND_OUT_FD_COUNT(cmd
); i
++) {
755 int ret_close
= close(COMMAND_OUT_FDS(cmd
, run_as_ret
)[i
]);
758 PERROR("Failed to close result file descriptor");
766 int recv_fds_from_worker(const struct run_as_worker
*worker
, enum run_as_cmd cmd
,
767 struct run_as_ret
*run_as_ret
)
771 if (COMMAND_OUT_FD_COUNT(cmd
) == 0) {
775 ret
= do_recv_fds(worker
->sockpair
[0], COMMAND_OUT_FDS(cmd
, run_as_ret
),
776 COMMAND_OUT_FD_COUNT(cmd
));
778 PERROR("Failed to receive file descriptor from run-as worker");
786 int recv_fds_from_master(struct run_as_worker
*worker
, struct run_as_data
*data
)
790 if (COMMAND_USE_CWD_FD(data
)) {
793 for (i
= 0; i
< COMMAND_IN_FD_COUNT(data
); i
++) {
794 COMMAND_IN_FDS(data
)[i
] = AT_FDCWD
;
799 ret
= do_recv_fds(worker
->sockpair
[1], COMMAND_IN_FDS(data
),
800 COMMAND_IN_FD_COUNT(data
));
802 PERROR("Failed to receive file descriptors from master process");
810 int cleanup_received_fds(struct run_as_data
*data
)
814 for (i
= 0; i
< COMMAND_IN_FD_COUNT(data
); i
++) {
815 if (COMMAND_IN_FDS(data
)[i
] == -1) {
818 ret
= close(COMMAND_IN_FDS(data
)[i
]);
820 PERROR("Failed to close file descriptor received fd in run-as worker");
828 static int get_user_infos_from_uid(
829 uid_t uid
, char **username
, gid_t
*primary_gid
)
833 long raw_get_pw_buf_size
;
834 size_t get_pw_buf_size
;
836 struct passwd
*result
= NULL
;
838 /* Fetch the max size for the temporary buffer. */
840 raw_get_pw_buf_size
= sysconf(_SC_GETPW_R_SIZE_MAX
);
841 if (raw_get_pw_buf_size
< 0) {
843 PERROR("Failed to query _SC_GETPW_R_SIZE_MAX");
847 /* Limit is indeterminate. */
848 WARN("Failed to query _SC_GETPW_R_SIZE_MAX as it is "
849 "indeterminate; falling back to default buffer size");
850 raw_get_pw_buf_size
= GETPW_BUFFER_FALLBACK_SIZE
;
853 get_pw_buf_size
= (size_t) raw_get_pw_buf_size
;
855 buf
= zmalloc(get_pw_buf_size
);
857 PERROR("Failed to allocate buffer to get password file entries");
861 ret
= getpwuid_r(uid
, &pwd
, buf
, get_pw_buf_size
, &result
);
863 PERROR("Failed to get user information for user: uid = %d",
868 if (result
== NULL
) {
869 ERR("Failed to find user information in password entries: uid = %d",
875 *username
= strdup(result
->pw_name
);
876 if (*username
== NULL
) {
877 PERROR("Failed to copy user name");
881 *primary_gid
= result
->pw_gid
;
893 static int demote_creds(
894 uid_t prev_uid
, gid_t prev_gid
, uid_t new_uid
, gid_t new_gid
)
898 char *username
= NULL
;
900 /* Change the group id. */
901 if (prev_gid
!= new_gid
) {
902 ret
= setegid(new_gid
);
904 PERROR("Failed to set effective group id: new_gid = %d",
910 /* Change the user id. */
911 if (prev_uid
!= new_uid
) {
912 ret
= get_user_infos_from_uid(new_uid
, &username
, &primary_gid
);
918 * Initialize the supplementary group access list.
920 * This is needed to handle cases where the supplementary groups
921 * of the user the process is demoting-to would give it access
922 * to a given file/folder, but not it's primary group.
926 * Primary Group: User1
927 * Secondary group: Disk, Network
929 * mkdir inside the following directory must work since User1
930 * is part of the Network group.
932 * drwxrwx--- 2 root Network 4096 Jul 23 17:17 /tmp/my_folder/
935 * The order of the following initgroups and seteuid calls is
937 * Only a root process or one with CAP_SETGID capability can
938 * call the the initgroups() function. We must initialize the
939 * supplementary groups before we change the effective
940 * UID to a less-privileged user.
942 ret
= initgroups(username
, primary_gid
);
944 PERROR("Failed to init the supplementary group access list: "
945 "username = `%s`, primary gid = %d", username
,
950 ret
= seteuid(new_uid
);
952 PERROR("Failed to set effective user id: new_uid = %d",
962 static int promote_creds(
963 uid_t prev_uid
, gid_t prev_gid
, uid_t new_uid
, gid_t new_gid
)
967 char *username
= NULL
;
969 /* Change the group id. */
970 if (prev_gid
!= new_gid
) {
971 ret
= setegid(new_gid
);
973 PERROR("Failed to set effective group id: new_gid = %d",
979 /* Change the user id. */
980 if (prev_uid
!= new_uid
) {
981 ret
= get_user_infos_from_uid(new_uid
, &username
, &primary_gid
);
987 * seteuid call must be done before the initgroups call because
988 * we need to be privileged (CAP_SETGID) to call initgroups().
990 ret
= seteuid(new_uid
);
992 PERROR("Failed to set effective user id: new_uid = %d",
998 * Initialize the supplementary group access list.
1000 * There is a possibility the groups we set in the following
1001 * initgroups() call are not exactly the same as the ones we
1002 * had when we originally demoted. This can happen if the
1003 * /etc/group file is modified after the runas process is
1004 * forked. This is very unlikely.
1006 ret
= initgroups(username
, primary_gid
);
1008 PERROR("Failed to init the supplementary group access "
1009 "list: username = `%s`, primary gid = %d",
1010 username
, (int) primary_gid
)
1020 * Return < 0 on error, 0 if OK, 1 on hangup.
1023 int handle_one_cmd(struct run_as_worker
*worker
)
1025 int ret
= 0, promote_ret
;
1026 struct run_as_data data
= {};
1027 ssize_t readlen
, writelen
;
1028 struct run_as_ret sendret
= {};
1034 * Stage 1: Receive run_as_data struct from the master.
1035 * The structure contains the command type and all the parameters needed for
1038 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[1], &data
,
1045 if (readlen
< sizeof(data
)) {
1046 PERROR("lttcomm_recv_unix_sock error");
1051 cmd
= run_as_enum_to_fct(data
.cmd
);
1058 * Stage 2: Receive file descriptor from master.
1059 * Some commands need a file descriptor as input so if it's needed we
1060 * receive the fd using the Unix socket.
1062 ret
= recv_fds_from_master(worker
, &data
);
1064 PERROR("recv_fd_from_master error");
1069 prev_ruid
= getuid();
1070 prev_rgid
= getgid();
1072 ret
= demote_creds(prev_ruid
, prev_rgid
, data
.uid
, data
.gid
);
1078 * Also set umask to 0 for mkdir executable bit.
1083 * Stage 3: Execute the command
1085 ret
= (*cmd
)(&data
, &sendret
);
1087 DBG("Execution of command returned an error");
1091 ret
= cleanup_received_fds(&data
);
1093 ERR("Error cleaning up FD");
1098 * Stage 4: Send run_as_ret structure to the master.
1099 * This structure contain the return value of the command and the errno.
1101 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[1], &sendret
,
1103 if (writelen
< sizeof(sendret
)) {
1104 PERROR("lttcomm_send_unix_sock error");
1110 * Stage 5: Send resulting file descriptors to the master.
1112 ret
= send_fds_to_master(worker
, data
.cmd
, &sendret
);
1114 DBG("Sending FD to master returned an error");
1120 /* Return to previous uid/gid. */
1121 promote_ret
= promote_creds(data
.uid
, data
.gid
, prev_ruid
, prev_rgid
);
1122 if (promote_ret
< 0) {
1123 ERR("Failed to promote back to the initial credentials");
1131 int run_as_worker(struct run_as_worker
*worker
)
1135 struct run_as_ret sendret
;
1136 size_t proc_orig_len
;
1139 * Initialize worker. Set a different process cmdline.
1141 proc_orig_len
= strlen(worker
->procname
);
1142 memset(worker
->procname
, 0, proc_orig_len
);
1143 strncpy(worker
->procname
, DEFAULT_RUN_AS_WORKER_NAME
, proc_orig_len
);
1145 ret
= lttng_prctl(PR_SET_NAME
,
1146 (unsigned long) DEFAULT_RUN_AS_WORKER_NAME
, 0, 0, 0);
1147 if (ret
&& ret
!= -ENOSYS
) {
1148 /* Don't fail as this is not essential. */
1149 PERROR("prctl PR_SET_NAME");
1152 memset(&sendret
, 0, sizeof(sendret
));
1154 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[1], &sendret
,
1156 if (writelen
< sizeof(sendret
)) {
1157 PERROR("lttcomm_send_unix_sock error");
1163 ret
= handle_one_cmd(worker
);
1167 } else if (ret
> 0) {
1170 continue; /* Next command. */
1179 int run_as_cmd(struct run_as_worker
*worker
,
1180 enum run_as_cmd cmd
,
1181 struct run_as_data
*data
,
1182 struct run_as_ret
*ret_value
,
1183 uid_t uid
, gid_t gid
)
1186 ssize_t readlen
, writelen
;
1189 * If we are non-root, we can only deal with our own uid.
1191 if (geteuid() != 0) {
1192 if (uid
!= geteuid()) {
1194 ret_value
->_errno
= EPERM
;
1195 ERR("Client (%d)/Server (%d) UID mismatch (and sessiond is not root)",
1196 (int) uid
, (int) geteuid());
1206 * Stage 1: Send the run_as_data struct to the worker process
1208 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[0], data
,
1210 if (writelen
< sizeof(*data
)) {
1211 PERROR("Error writing message to run_as");
1213 ret_value
->_errno
= EIO
;
1218 * Stage 2: Send file descriptor to the worker process if needed
1220 ret
= send_fds_to_worker(worker
, data
);
1222 PERROR("do_send_fd error");
1224 ret_value
->_errno
= EIO
;
1229 * Stage 3: Wait for the execution of the command
1233 * Stage 4: Receive the run_as_ret struct containing the return value and
1236 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[0], ret_value
,
1237 sizeof(*ret_value
));
1239 ERR("Run-as worker has hung-up during run_as_cmd");
1241 ret_value
->_errno
= EIO
;
1243 } else if (readlen
< sizeof(*ret_value
)) {
1244 PERROR("Error reading response from run_as");
1246 ret_value
->_errno
= errno
;
1250 if (ret_value
->_error
) {
1251 /* Skip stage 5 on error as there will be no fd to receive. */
1256 * Stage 5: Receive file descriptor if needed
1258 ret
= recv_fds_from_worker(worker
, cmd
, ret_value
);
1260 ERR("Error receiving fd");
1262 ret_value
->_errno
= EIO
;
1270 * This is for debugging ONLY and should not be considered secure.
1273 int run_as_noworker(enum run_as_cmd cmd
,
1274 struct run_as_data
*data
, struct run_as_ret
*ret_value
,
1275 uid_t uid
, gid_t gid
)
1277 int ret
, saved_errno
;
1281 fct
= run_as_enum_to_fct(cmd
);
1287 old_mask
= umask(0);
1288 ret
= fct(data
, ret_value
);
1289 saved_errno
= ret_value
->_errno
;
1291 errno
= saved_errno
;
1297 int reset_sighandler(void)
1301 DBG("Resetting run_as worker signal handlers to default");
1302 for (sig
= 1; sig
<= 31; sig
++) {
1303 (void) signal(sig
, SIG_DFL
);
1309 void worker_sighandler(int sig
)
1311 const char *signame
;
1314 * The worker will inherit its parent's signals since they are part of
1315 * the same process group. However, in the case of SIGINT and SIGTERM,
1316 * we want to give the worker a chance to teardown gracefully when its
1317 * parent closes the command socket.
1324 signame
= "SIGTERM";
1331 DBG("run_as worker received signal %s", signame
);
1333 DBG("run_as_worker received signal %d", sig
);
1338 int set_worker_sighandlers(void)
1342 struct sigaction sa
;
1344 if ((ret
= sigemptyset(&sigset
)) < 0) {
1345 PERROR("sigemptyset");
1349 sa
.sa_handler
= worker_sighandler
;
1350 sa
.sa_mask
= sigset
;
1352 if ((ret
= sigaction(SIGINT
, &sa
, NULL
)) < 0) {
1353 PERROR("sigaction SIGINT");
1357 if ((ret
= sigaction(SIGTERM
, &sa
, NULL
)) < 0) {
1358 PERROR("sigaction SIGTERM");
1362 DBG("run_as signal handler set for SIGTERM and SIGINT");
1368 int run_as_create_worker_no_lock(const char *procname
,
1369 post_fork_cleanup_cb clean_up_func
,
1370 void *clean_up_user_data
)
1375 struct run_as_ret recvret
;
1376 struct run_as_worker
*worker
;
1378 assert(!global_worker
);
1381 * Don't initialize a worker, all run_as tasks will be performed
1382 * in the current process.
1387 worker
= zmalloc(sizeof(*worker
));
1392 worker
->procname
= strdup(procname
);
1393 if (!worker
->procname
) {
1395 goto error_procname_alloc
;
1397 /* Create unix socket. */
1398 if (lttcomm_create_anon_unix_socketpair(worker
->sockpair
) < 0) {
1409 } else if (pid
== 0) {
1414 set_worker_sighandlers();
1415 if (clean_up_func
) {
1416 if (clean_up_func(clean_up_user_data
) < 0) {
1417 ERR("Run-as post-fork clean-up failed, exiting.");
1422 /* Just close, no shutdown. */
1423 if (close(worker
->sockpair
[0])) {
1429 * Close all FDs aside from STDIN, STDOUT, STDERR and sockpair[1]
1430 * Sockpair[1] is used as a control channel with the master
1432 for (i
= 3; i
< sysconf(_SC_OPEN_MAX
); i
++) {
1433 if (i
!= worker
->sockpair
[1]) {
1438 worker
->sockpair
[0] = -1;
1439 ret
= run_as_worker(worker
);
1440 if (lttcomm_close_unix_sock(worker
->sockpair
[1])) {
1444 worker
->sockpair
[1] = -1;
1445 free(worker
->procname
);
1447 LOG(ret
? PRINT_ERR
: PRINT_DBG
, "run_as worker exiting (ret = %d)", ret
);
1448 exit(ret
? EXIT_FAILURE
: EXIT_SUCCESS
);
1452 /* Just close, no shutdown. */
1453 if (close(worker
->sockpair
[1])) {
1458 worker
->sockpair
[1] = -1;
1460 /* Wait for worker to become ready. */
1461 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[0],
1462 &recvret
, sizeof(recvret
));
1463 if (readlen
< sizeof(recvret
)) {
1464 ERR("readlen: %zd", readlen
);
1465 PERROR("Error reading response from run_as at creation");
1469 global_worker
= worker
;
1474 /* Error handling. */
1476 for (i
= 0; i
< 2; i
++) {
1477 if (worker
->sockpair
[i
] < 0) {
1480 if (lttcomm_close_unix_sock(worker
->sockpair
[i
])) {
1483 worker
->sockpair
[i
] = -1;
1486 free(worker
->procname
);
1487 error_procname_alloc
:
1493 void run_as_destroy_worker_no_lock(void)
1495 struct run_as_worker
*worker
= global_worker
;
1497 DBG("Destroying run_as worker");
1501 /* Close unix socket */
1502 DBG("Closing run_as worker socket");
1503 if (lttcomm_close_unix_sock(worker
->sockpair
[0])) {
1506 worker
->sockpair
[0] = -1;
1507 /* Wait for worker. */
1512 wait_ret
= waitpid(worker
->pid
, &status
, 0);
1514 if (errno
== EINTR
) {
1521 if (WIFEXITED(status
)) {
1522 LOG(WEXITSTATUS(status
) == 0 ? PRINT_DBG
: PRINT_ERR
,
1523 DEFAULT_RUN_AS_WORKER_NAME
" terminated with status code %d",
1524 WEXITSTATUS(status
));
1526 } else if (WIFSIGNALED(status
)) {
1527 ERR(DEFAULT_RUN_AS_WORKER_NAME
" was killed by signal %d",
1532 free(worker
->procname
);
1534 global_worker
= NULL
;
1538 int run_as_restart_worker(struct run_as_worker
*worker
)
1541 char *procname
= NULL
;
1543 procname
= worker
->procname
;
1545 /* Close socket to run_as worker process and clean up the zombie process */
1546 run_as_destroy_worker_no_lock();
1548 /* Create a new run_as worker process*/
1549 ret
= run_as_create_worker_no_lock(procname
, NULL
, NULL
);
1551 ERR("Restarting the worker process failed");
1560 int run_as(enum run_as_cmd cmd
, struct run_as_data
*data
,
1561 struct run_as_ret
*ret_value
, uid_t uid
, gid_t gid
)
1563 int ret
, saved_errno
;
1565 pthread_mutex_lock(&worker_lock
);
1567 DBG("Using run_as worker");
1569 assert(global_worker
);
1571 ret
= run_as_cmd(global_worker
, cmd
, data
, ret_value
, uid
, gid
);
1572 saved_errno
= ret_value
->_errno
;
1575 * If the worker thread crashed the errno is set to EIO. we log
1576 * the error and start a new worker process.
1578 if (ret
== -1 && saved_errno
== EIO
) {
1579 DBG("Socket closed unexpectedly... "
1580 "Restarting the worker process");
1581 ret
= run_as_restart_worker(global_worker
);
1583 ERR("Failed to restart worker process.");
1588 DBG("Using run_as without worker");
1589 ret
= run_as_noworker(cmd
, data
, ret_value
, uid
, gid
);
1592 pthread_mutex_unlock(&worker_lock
);
1597 int run_as_mkdir_recursive(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
1599 return run_as_mkdirat_recursive(AT_FDCWD
, path
, mode
, uid
, gid
);
1603 int run_as_mkdirat_recursive(int dirfd
, const char *path
, mode_t mode
,
1604 uid_t uid
, gid_t gid
)
1607 struct run_as_data data
= {};
1608 struct run_as_ret run_as_ret
= {};
1610 DBG3("mkdirat() recursive fd = %d%s, path = %s, mode = %d, uid = %d, gid = %d",
1611 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1612 path
, (int) mode
, (int) uid
, (int) gid
);
1613 ret
= lttng_strncpy(data
.u
.mkdir
.path
, path
,
1614 sizeof(data
.u
.mkdir
.path
));
1616 ERR("Failed to copy path argument of mkdirat recursive command");
1619 data
.u
.mkdir
.path
[sizeof(data
.u
.mkdir
.path
) - 1] = '\0';
1620 data
.u
.mkdir
.mode
= mode
;
1621 data
.u
.mkdir
.dirfd
= dirfd
;
1622 run_as(dirfd
== AT_FDCWD
? RUN_AS_MKDIR_RECURSIVE
: RUN_AS_MKDIRAT_RECURSIVE
,
1623 &data
, &run_as_ret
, uid
, gid
);
1624 errno
= run_as_ret
._errno
;
1625 ret
= run_as_ret
.u
.ret
;
1631 int run_as_mkdir(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
1633 return run_as_mkdirat(AT_FDCWD
, path
, mode
, uid
, gid
);
1637 int run_as_mkdirat(int dirfd
, const char *path
, mode_t mode
,
1638 uid_t uid
, gid_t gid
)
1641 struct run_as_data data
= {};
1642 struct run_as_ret run_as_ret
= {};
1644 DBG3("mkdirat() recursive fd = %d%s, path = %s, mode = %d, uid = %d, gid = %d",
1645 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1646 path
, (int) mode
, (int) uid
, (int) gid
);
1647 ret
= lttng_strncpy(data
.u
.mkdir
.path
, path
,
1648 sizeof(data
.u
.mkdir
.path
));
1650 ERR("Failed to copy path argument of mkdirat command");
1653 data
.u
.mkdir
.path
[sizeof(data
.u
.mkdir
.path
) - 1] = '\0';
1654 data
.u
.mkdir
.mode
= mode
;
1655 data
.u
.mkdir
.dirfd
= dirfd
;
1656 run_as(dirfd
== AT_FDCWD
? RUN_AS_MKDIR
: RUN_AS_MKDIRAT
,
1657 &data
, &run_as_ret
, uid
, gid
);
1658 errno
= run_as_ret
._errno
;
1659 ret
= run_as_ret
.u
.ret
;
1665 int run_as_open(const char *path
, int flags
, mode_t mode
, uid_t uid
,
1668 return run_as_openat(AT_FDCWD
, path
, flags
, mode
, uid
, gid
);
1672 int run_as_openat(int dirfd
, const char *path
, int flags
, mode_t mode
,
1673 uid_t uid
, gid_t gid
)
1676 struct run_as_data data
= {};
1677 struct run_as_ret run_as_ret
= {};
1679 DBG3("openat() fd = %d%s, path = %s, flags = %X, mode = %d, uid %d, gid %d",
1680 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1681 path
, flags
, (int) mode
, (int) uid
, (int) gid
);
1682 ret
= lttng_strncpy(data
.u
.open
.path
, path
, sizeof(data
.u
.open
.path
));
1684 ERR("Failed to copy path argument of open command");
1687 data
.u
.open
.flags
= flags
;
1688 data
.u
.open
.mode
= mode
;
1689 data
.u
.open
.dirfd
= dirfd
;
1690 run_as(dirfd
== AT_FDCWD
? RUN_AS_OPEN
: RUN_AS_OPENAT
,
1691 &data
, &run_as_ret
, uid
, gid
);
1692 errno
= run_as_ret
._errno
;
1693 ret
= run_as_ret
.u
.ret
< 0 ? run_as_ret
.u
.ret
:
1694 run_as_ret
.u
.open
.fd
;
1700 int run_as_unlink(const char *path
, uid_t uid
, gid_t gid
)
1702 return run_as_unlinkat(AT_FDCWD
, path
, uid
, gid
);
1706 int run_as_unlinkat(int dirfd
, const char *path
, uid_t uid
, gid_t gid
)
1709 struct run_as_data data
= {};
1710 struct run_as_ret run_as_ret
= {};
1712 DBG3("unlinkat() fd = %d%s, path = %s, uid = %d, gid = %d",
1713 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1714 path
, (int) uid
, (int) gid
);
1715 ret
= lttng_strncpy(data
.u
.unlink
.path
, path
,
1716 sizeof(data
.u
.unlink
.path
));
1720 data
.u
.unlink
.dirfd
= dirfd
;
1721 run_as(dirfd
== AT_FDCWD
? RUN_AS_UNLINK
: RUN_AS_UNLINKAT
, &data
,
1722 &run_as_ret
, uid
, gid
);
1723 errno
= run_as_ret
._errno
;
1724 ret
= run_as_ret
.u
.ret
;
1730 int run_as_rmdir(const char *path
, uid_t uid
, gid_t gid
)
1732 return run_as_rmdirat(AT_FDCWD
, path
, uid
, gid
);
1736 int run_as_rmdirat(int dirfd
, const char *path
, uid_t uid
, gid_t gid
)
1739 struct run_as_data data
= {};
1740 struct run_as_ret run_as_ret
= {};
1742 DBG3("rmdirat() fd = %d%s, path = %s, uid = %d, gid = %d",
1743 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1744 path
, (int) uid
, (int) gid
);
1745 ret
= lttng_strncpy(data
.u
.rmdir
.path
, path
,
1746 sizeof(data
.u
.rmdir
.path
));
1750 data
.u
.rmdir
.dirfd
= dirfd
;
1751 run_as(dirfd
== AT_FDCWD
? RUN_AS_RMDIR
: RUN_AS_RMDIRAT
, &data
,
1752 &run_as_ret
, uid
, gid
);
1753 errno
= run_as_ret
._errno
;
1754 ret
= run_as_ret
.u
.ret
;
1760 int run_as_rmdir_recursive(const char *path
, uid_t uid
, gid_t gid
, int flags
)
1762 return run_as_rmdirat_recursive(AT_FDCWD
, path
, uid
, gid
, flags
);
1766 int run_as_rmdirat_recursive(int dirfd
, const char *path
, uid_t uid
, gid_t gid
, int flags
)
1769 struct run_as_data data
= {};
1770 struct run_as_ret run_as_ret
= {};
1772 DBG3("rmdirat() recursive fd = %d%s, path = %s, uid = %d, gid = %d",
1773 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1774 path
, (int) uid
, (int) gid
);
1775 ret
= lttng_strncpy(data
.u
.rmdir
.path
, path
,
1776 sizeof(data
.u
.rmdir
.path
));
1780 data
.u
.rmdir
.dirfd
= dirfd
;
1781 data
.u
.rmdir
.flags
= flags
;
1782 run_as(dirfd
== AT_FDCWD
? RUN_AS_RMDIR_RECURSIVE
: RUN_AS_RMDIRAT_RECURSIVE
,
1783 &data
, &run_as_ret
, uid
, gid
);
1784 errno
= run_as_ret
._errno
;
1785 ret
= run_as_ret
.u
.ret
;
1791 int run_as_rename(const char *old
, const char *new, uid_t uid
, gid_t gid
)
1793 return run_as_renameat(AT_FDCWD
, old
, AT_FDCWD
, new, uid
, gid
);
1797 int run_as_renameat(int old_dirfd
, const char *old_name
,
1798 int new_dirfd
, const char *new_name
, uid_t uid
, gid_t gid
)
1801 struct run_as_data data
= {};
1802 struct run_as_ret run_as_ret
= {};
1804 DBG3("renameat() old_dirfd = %d%s, old_name = %s, new_dirfd = %d%s, new_name = %s, uid = %d, gid = %d",
1805 old_dirfd
, old_dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1807 new_dirfd
, new_dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1808 new_name
, (int) uid
, (int) gid
);
1809 ret
= lttng_strncpy(data
.u
.rename
.old_path
, old_name
,
1810 sizeof(data
.u
.rename
.old_path
));
1814 ret
= lttng_strncpy(data
.u
.rename
.new_path
, new_name
,
1815 sizeof(data
.u
.rename
.new_path
));
1820 data
.u
.rename
.dirfds
[0] = old_dirfd
;
1821 data
.u
.rename
.dirfds
[1] = new_dirfd
;
1822 run_as(old_dirfd
== AT_FDCWD
&& new_dirfd
== AT_FDCWD
?
1823 RUN_AS_RENAME
: RUN_AS_RENAMEAT
,
1824 &data
, &run_as_ret
, uid
, gid
);
1825 errno
= run_as_ret
._errno
;
1826 ret
= run_as_ret
.u
.ret
;
1832 int run_as_extract_elf_symbol_offset(int fd
, const char* function
,
1833 uid_t uid
, gid_t gid
, uint64_t *offset
)
1836 struct run_as_data data
= {};
1837 struct run_as_ret run_as_ret
= {};
1839 DBG3("extract_elf_symbol_offset() on fd=%d and function=%s "
1840 "with for uid %d and gid %d", fd
, function
,
1841 (int) uid
, (int) gid
);
1843 data
.u
.extract_elf_symbol_offset
.fd
= fd
;
1845 strncpy(data
.u
.extract_elf_symbol_offset
.function
, function
, LTTNG_SYMBOL_NAME_LEN
- 1);
1846 data
.u
.extract_elf_symbol_offset
.function
[LTTNG_SYMBOL_NAME_LEN
- 1] = '\0';
1847 ret
= lttng_strncpy(data
.u
.extract_elf_symbol_offset
.function
,
1849 sizeof(data
.u
.extract_elf_symbol_offset
.function
));
1854 run_as(RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
, &data
, &run_as_ret
, uid
, gid
);
1855 errno
= run_as_ret
._errno
;
1856 if (run_as_ret
._error
) {
1861 *offset
= run_as_ret
.u
.extract_elf_symbol_offset
.offset
;
1867 int run_as_extract_sdt_probe_offsets(int fd
, const char* provider_name
,
1868 const char* probe_name
, uid_t uid
, gid_t gid
,
1869 uint64_t **offsets
, uint32_t *num_offset
)
1872 struct run_as_data data
= {};
1873 struct run_as_ret run_as_ret
= {};
1875 DBG3("extract_sdt_probe_offsets() on fd=%d, probe_name=%s and "
1876 "provider_name=%s with for uid %d and gid %d", fd
,
1877 probe_name
, provider_name
, (int) uid
, (int) gid
);
1879 data
.u
.extract_sdt_probe_offsets
.fd
= fd
;
1881 ret
= lttng_strncpy(data
.u
.extract_sdt_probe_offsets
.probe_name
, probe_name
,
1882 sizeof(data
.u
.extract_sdt_probe_offsets
.probe_name
));
1886 ret
= lttng_strncpy(data
.u
.extract_sdt_probe_offsets
.provider_name
,
1888 sizeof(data
.u
.extract_sdt_probe_offsets
.provider_name
));
1893 run_as(RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
, &data
, &run_as_ret
, uid
, gid
);
1894 errno
= run_as_ret
._errno
;
1895 if (run_as_ret
._error
) {
1900 *num_offset
= run_as_ret
.u
.extract_sdt_probe_offsets
.num_offset
;
1901 *offsets
= zmalloc(*num_offset
* sizeof(uint64_t));
1907 memcpy(*offsets
, run_as_ret
.u
.extract_sdt_probe_offsets
.offsets
,
1908 *num_offset
* sizeof(uint64_t));
1914 int run_as_create_worker(const char *procname
,
1915 post_fork_cleanup_cb clean_up_func
,
1916 void *clean_up_user_data
)
1920 pthread_mutex_lock(&worker_lock
);
1921 ret
= run_as_create_worker_no_lock(procname
, clean_up_func
,
1922 clean_up_user_data
);
1923 pthread_mutex_unlock(&worker_lock
);
1928 void run_as_destroy_worker(void)
1930 pthread_mutex_lock(&worker_lock
);
1931 run_as_destroy_worker_no_lock();
1932 pthread_mutex_unlock(&worker_lock
);