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
17 #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>
41 typedef int (*run_as_fct
)(struct run_as_data
*data
, struct run_as_ret
*ret_value
);
46 RUN_AS_MKDIR_RECURSIVE
,
47 RUN_AS_MKDIRAT_RECURSIVE
,
54 RUN_AS_RMDIR_RECURSIVE
,
55 RUN_AS_RMDIRAT_RECURSIVE
,
58 RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
,
59 RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
,
62 struct run_as_mkdir_data
{
64 char path
[LTTNG_PATH_MAX
];
68 struct run_as_open_data
{
70 char path
[LTTNG_PATH_MAX
];
75 struct run_as_unlink_data
{
77 char path
[LTTNG_PATH_MAX
];
80 struct run_as_rmdir_data
{
82 char path
[LTTNG_PATH_MAX
];
83 int flags
; /* enum lttng_directory_handle_rmdir_recursive_flags */
86 struct run_as_extract_elf_symbol_offset_data
{
88 char function
[LTTNG_SYMBOL_NAME_LEN
];
91 struct run_as_extract_sdt_probe_offsets_data
{
93 char probe_name
[LTTNG_SYMBOL_NAME_LEN
];
94 char provider_name
[LTTNG_SYMBOL_NAME_LEN
];
97 struct run_as_rename_data
{
103 char old_path
[LTTNG_PATH_MAX
];
104 char new_path
[LTTNG_PATH_MAX
];
107 struct run_as_open_ret
{
111 struct run_as_extract_elf_symbol_offset_ret
{
115 struct run_as_extract_sdt_probe_offsets_ret
{
117 uint64_t offsets
[LTTNG_KERNEL_MAX_UPROBE_NUM
];
123 struct run_as_mkdir_data mkdir
;
124 struct run_as_open_data open
;
125 struct run_as_unlink_data unlink
;
126 struct run_as_rmdir_data rmdir
;
127 struct run_as_rename_data rename
;
128 struct run_as_extract_elf_symbol_offset_data extract_elf_symbol_offset
;
129 struct run_as_extract_sdt_probe_offsets_data extract_sdt_probe_offsets
;
136 * The run_as_ret structure holds the returned value and status of the command.
138 * The `u` union field holds the return value of the command; in most cases it
139 * represents the success or the failure of the command. In more complex
140 * commands, it holds a computed value.
142 * The _errno field is the errno recorded after the execution of the command.
144 * The _error fields is used the signify that return status of the command. For
145 * simple commands returning `int` the _error field will be the same as the
146 * ret_int field. In complex commands, it signify the success or failure of the
153 struct run_as_open_ret open
;
154 struct run_as_extract_elf_symbol_offset_ret extract_elf_symbol_offset
;
155 struct run_as_extract_sdt_probe_offsets_ret extract_sdt_probe_offsets
;
161 #define COMMAND_IN_FDS(data_ptr) ({ \
163 if (command_properties[data_ptr->cmd].in_fds_offset != -1) { \
164 fds = (int *) ((char *) data_ptr + command_properties[data_ptr->cmd].in_fds_offset); \
169 #define COMMAND_OUT_FDS(cmd, ret_ptr) ({ \
171 if (command_properties[cmd].out_fds_offset != -1) { \
172 fds = (int *) ((char *) ret_ptr + command_properties[cmd].out_fds_offset); \
177 #define COMMAND_IN_FD_COUNT(data_ptr) ({ \
178 command_properties[data_ptr->cmd].in_fd_count; \
181 #define COMMAND_OUT_FD_COUNT(cmd) ({ \
182 command_properties[cmd].out_fd_count; \
185 #define COMMAND_USE_CWD_FD(data_ptr) command_properties[data_ptr->cmd].use_cwd_fd
187 struct run_as_command_properties
{
188 /* Set to -1 when not applicable. */
189 ptrdiff_t in_fds_offset
, out_fds_offset
;
190 unsigned int in_fd_count
, out_fd_count
;
194 static const struct run_as_command_properties command_properties
[] = {
196 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
198 .out_fds_offset
= -1,
203 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
205 .out_fds_offset
= -1,
209 [RUN_AS_MKDIR_RECURSIVE
] = {
210 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
212 .out_fds_offset
= -1,
216 [RUN_AS_MKDIRAT_RECURSIVE
] = {
217 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
219 .out_fds_offset
= -1,
224 .in_fds_offset
= offsetof(struct run_as_data
, u
.open
.dirfd
),
226 .out_fds_offset
= offsetof(struct run_as_ret
, u
.open
.fd
),
231 .in_fds_offset
= offsetof(struct run_as_data
, u
.open
.dirfd
),
233 .out_fds_offset
= offsetof(struct run_as_ret
, u
.open
.fd
),
238 .in_fds_offset
= offsetof(struct run_as_data
, u
.unlink
.dirfd
),
240 .out_fds_offset
= -1,
244 [RUN_AS_UNLINKAT
] = {
245 .in_fds_offset
= offsetof(struct run_as_data
, u
.unlink
.dirfd
),
247 .out_fds_offset
= -1,
251 [RUN_AS_RMDIR_RECURSIVE
] = {
252 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
254 .out_fds_offset
= -1,
258 [RUN_AS_RMDIRAT_RECURSIVE
] = {
259 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
261 .out_fds_offset
= -1,
266 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
268 .out_fds_offset
= -1,
273 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
275 .out_fds_offset
= -1,
280 .in_fds_offset
= offsetof(struct run_as_data
, u
.rename
.dirfds
),
282 .out_fds_offset
= -1,
286 [RUN_AS_RENAMEAT
] = {
287 .in_fds_offset
= offsetof(struct run_as_data
, u
.rename
.dirfds
),
289 .out_fds_offset
= -1,
293 [RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
] = {
294 .in_fds_offset
= offsetof(struct run_as_data
,
295 u
.extract_elf_symbol_offset
.fd
),
297 .out_fds_offset
= -1,
301 [RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
] = {
302 .in_fds_offset
= offsetof(struct run_as_data
,
303 u
.extract_sdt_probe_offsets
.fd
),
305 .out_fds_offset
= -1,
311 struct run_as_worker
{
312 pid_t pid
; /* Worker PID. */
317 /* Single global worker per process (for now). */
318 static struct run_as_worker
*global_worker
;
319 /* Lock protecting the worker. */
320 static pthread_mutex_t worker_lock
= PTHREAD_MUTEX_INITIALIZER
;
332 return !lttng_secure_getenv("LTTNG_DEBUG_NOCLONE");
337 * Create recursively directory using the FULL path.
340 int _mkdirat_recursive(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
344 struct lttng_directory_handle
*handle
;
346 path
= data
->u
.mkdir
.path
;
347 mode
= data
->u
.mkdir
.mode
;
349 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.mkdir
.dirfd
);
351 ret_value
->_errno
= errno
;
352 ret_value
->_error
= true;
353 ret_value
->u
.ret
= -1;
356 /* Ownership of dirfd is transferred to the handle. */
357 data
->u
.mkdir
.dirfd
= -1;
358 /* Safe to call as we have transitioned to the requested uid/gid. */
359 ret_value
->u
.ret
= lttng_directory_handle_create_subdirectory_recursive(
361 ret_value
->_errno
= errno
;
362 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
363 lttng_directory_handle_put(handle
);
365 return ret_value
->u
.ret
;
369 int _mkdirat(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
373 struct lttng_directory_handle
*handle
;
375 path
= data
->u
.mkdir
.path
;
376 mode
= data
->u
.mkdir
.mode
;
378 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.mkdir
.dirfd
);
380 ret_value
->u
.ret
= -1;
381 ret_value
->_errno
= errno
;
382 ret_value
->_error
= true;
385 /* Ownership of dirfd is transferred to the handle. */
386 data
->u
.mkdir
.dirfd
= -1;
387 /* Safe to call as we have transitioned to the requested uid/gid. */
388 ret_value
->u
.ret
= lttng_directory_handle_create_subdirectory(
390 ret_value
->_errno
= errno
;
391 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
392 lttng_directory_handle_put(handle
);
394 return ret_value
->u
.ret
;
398 int _open(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
401 struct lttng_directory_handle
*handle
;
403 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.open
.dirfd
);
405 ret_value
->_errno
= errno
;
406 ret_value
->_error
= true;
407 ret_value
->u
.ret
= -1;
410 /* Ownership of dirfd is transferred to the handle. */
411 data
->u
.open
.dirfd
= -1;
413 fd
= lttng_directory_handle_open_file(handle
,
414 data
->u
.open
.path
, data
->u
.open
.flags
,
417 ret_value
->u
.ret
= -1;
418 ret_value
->u
.open
.fd
= -1;
420 ret_value
->u
.ret
= 0;
421 ret_value
->u
.open
.fd
= fd
;
424 ret_value
->_errno
= errno
;
425 ret_value
->_error
= fd
< 0;
426 lttng_directory_handle_put(handle
);
428 return ret_value
->u
.ret
;
432 int _unlink(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
434 struct lttng_directory_handle
*handle
;
436 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.unlink
.dirfd
);
438 ret_value
->u
.ret
= -1;
439 ret_value
->_errno
= errno
;
440 ret_value
->_error
= true;
444 /* Ownership of dirfd is transferred to the handle. */
445 data
->u
.unlink
.dirfd
= -1;
447 ret_value
->u
.ret
= lttng_directory_handle_unlink_file(handle
,
448 data
->u
.unlink
.path
);
449 ret_value
->_errno
= errno
;
450 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
451 lttng_directory_handle_put(handle
);
453 return ret_value
->u
.ret
;
457 int _rmdir(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
459 struct lttng_directory_handle
*handle
;
461 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.rmdir
.dirfd
);
463 ret_value
->u
.ret
= -1;
464 ret_value
->_errno
= errno
;
465 ret_value
->_error
= true;
469 /* Ownership of dirfd is transferred to the handle. */
470 data
->u
.rmdir
.dirfd
= -1;
472 ret_value
->u
.ret
= lttng_directory_handle_remove_subdirectory(
473 handle
, data
->u
.rmdir
.path
);
474 ret_value
->_errno
= errno
;
475 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
476 lttng_directory_handle_put(handle
);
478 return ret_value
->u
.ret
;
482 int _rmdir_recursive(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
484 struct lttng_directory_handle
*handle
;
486 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.rmdir
.dirfd
);
488 ret_value
->u
.ret
= -1;
489 ret_value
->_errno
= errno
;
490 ret_value
->_error
= true;
494 /* Ownership of dirfd is transferred to the handle. */
495 data
->u
.rmdir
.dirfd
= -1;
497 ret_value
->u
.ret
= lttng_directory_handle_remove_subdirectory_recursive(
498 handle
, data
->u
.rmdir
.path
, data
->u
.rmdir
.flags
);
499 ret_value
->_errno
= errno
;
500 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
501 lttng_directory_handle_put(handle
);
503 return ret_value
->u
.ret
;
507 int _rename(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
509 const char *old_path
, *new_path
;
510 struct lttng_directory_handle
*old_handle
= NULL
, *new_handle
= NULL
;
512 old_path
= data
->u
.rename
.old_path
;
513 new_path
= data
->u
.rename
.new_path
;
515 old_handle
= lttng_directory_handle_create_from_dirfd(
516 data
->u
.rename
.dirfds
[0]);
518 ret_value
->u
.ret
= -1;
521 new_handle
= lttng_directory_handle_create_from_dirfd(
522 data
->u
.rename
.dirfds
[1]);
524 ret_value
->u
.ret
= -1;
528 /* Ownership of dirfds are transferred to the handles. */
529 data
->u
.rename
.dirfds
[0] = data
->u
.rename
.dirfds
[1] = -1;
531 /* Safe to call as we have transitioned to the requested uid/gid. */
532 ret_value
->u
.ret
= lttng_directory_handle_rename(
533 old_handle
, old_path
, new_handle
, new_path
);
535 lttng_directory_handle_put(old_handle
);
536 lttng_directory_handle_put(new_handle
);
537 ret_value
->_errno
= errno
;
538 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
539 return ret_value
->u
.ret
;
544 int _extract_elf_symbol_offset(struct run_as_data
*data
,
545 struct run_as_ret
*ret_value
)
550 ret_value
->_error
= false;
551 ret
= lttng_elf_get_symbol_offset(data
->u
.extract_elf_symbol_offset
.fd
,
552 data
->u
.extract_elf_symbol_offset
.function
,
555 DBG("Failed to extract ELF function offset");
556 ret_value
->_error
= true;
558 ret_value
->u
.extract_elf_symbol_offset
.offset
= offset
;
564 int _extract_sdt_probe_offsets(struct run_as_data
*data
,
565 struct run_as_ret
*ret_value
)
568 uint64_t *offsets
= NULL
;
571 ret_value
->_error
= false;
573 /* On success, this call allocates the offsets paramater. */
574 ret
= lttng_elf_get_sdt_probe_offsets(
575 data
->u
.extract_sdt_probe_offsets
.fd
,
576 data
->u
.extract_sdt_probe_offsets
.provider_name
,
577 data
->u
.extract_sdt_probe_offsets
.probe_name
,
578 &offsets
, &num_offset
);
581 DBG("Failed to extract SDT probe offsets");
582 ret_value
->_error
= true;
586 if (num_offset
<= 0 || num_offset
> LTTNG_KERNEL_MAX_UPROBE_NUM
) {
587 DBG("Wrong number of probes.");
589 ret_value
->_error
= true;
593 /* Copy the content of the offsets array to the ret struct. */
594 memcpy(ret_value
->u
.extract_sdt_probe_offsets
.offsets
,
595 offsets
, num_offset
* sizeof(uint64_t));
597 ret_value
->u
.extract_sdt_probe_offsets
.num_offset
= num_offset
;
606 int _extract_elf_symbol_offset(struct run_as_data
*data
,
607 struct run_as_ret
*ret_value
)
609 ERR("Unimplemented runas command RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET");
614 int _extract_sdt_probe_offsets(struct run_as_data
*data
,
615 struct run_as_ret
*ret_value
)
617 ERR("Unimplemented runas command RUN_AS_EXTRACT_SDT_PROBE_OFFSETS");
623 run_as_fct
run_as_enum_to_fct(enum run_as_cmd cmd
)
629 case RUN_AS_MKDIR_RECURSIVE
:
630 case RUN_AS_MKDIRAT_RECURSIVE
:
631 return _mkdirat_recursive
;
636 case RUN_AS_UNLINKAT
:
641 case RUN_AS_RMDIR_RECURSIVE
:
642 case RUN_AS_RMDIRAT_RECURSIVE
:
643 return _rmdir_recursive
;
645 case RUN_AS_RENAMEAT
:
647 case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
:
648 return _extract_elf_symbol_offset
;
649 case RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
:
650 return _extract_sdt_probe_offsets
;
652 ERR("Unknown command %d", (int) cmd
);
658 int do_send_fds(int sock
, const int *fds
, unsigned int fd_count
)
663 for (i
= 0; i
< fd_count
; i
++) {
665 ERR("Attempt to send invalid file descriptor to master (fd = %i)",
667 /* Return 0 as this is not a fatal error. */
672 len
= lttcomm_send_fds_unix_sock(sock
, fds
, fd_count
);
673 return len
< 0 ? -1 : 0;
677 int do_recv_fds(int sock
, int *fds
, unsigned int fd_count
)
683 len
= lttcomm_recv_fds_unix_sock(sock
, fds
, fd_count
);
687 } else if (len
< 0) {
688 PERROR("Failed to receive file descriptors from socket");
693 for (i
= 0; i
< fd_count
; i
++) {
695 ERR("Invalid file descriptor received from worker (fd = %i)", fds
[i
]);
696 /* Return 0 as this is not a fatal error. */
704 int send_fds_to_worker(const struct run_as_worker
*worker
,
705 const struct run_as_data
*data
)
710 if (COMMAND_USE_CWD_FD(data
) || COMMAND_IN_FD_COUNT(data
) == 0) {
714 for (i
= 0; i
< COMMAND_IN_FD_COUNT(data
); i
++) {
715 if (COMMAND_IN_FDS(data
)[i
] < 0) {
716 ERR("Refusing to send invalid fd to worker (fd = %i)",
717 COMMAND_IN_FDS(data
)[i
]);
723 ret
= do_send_fds(worker
->sockpair
[0], COMMAND_IN_FDS(data
),
724 COMMAND_IN_FD_COUNT(data
));
726 PERROR("Failed to send file descriptor to run-as worker");
735 int send_fds_to_master(struct run_as_worker
*worker
, enum run_as_cmd cmd
,
736 struct run_as_ret
*run_as_ret
)
741 if (COMMAND_OUT_FD_COUNT(cmd
) == 0) {
745 ret
= do_send_fds(worker
->sockpair
[1], COMMAND_OUT_FDS(cmd
, run_as_ret
),
746 COMMAND_OUT_FD_COUNT(cmd
));
748 PERROR("Failed to send file descriptor to master process");
752 for (i
= 0; i
< COMMAND_OUT_FD_COUNT(cmd
); i
++) {
753 int ret_close
= close(COMMAND_OUT_FDS(cmd
, run_as_ret
)[i
]);
756 PERROR("Failed to close result file descriptor");
764 int recv_fds_from_worker(const struct run_as_worker
*worker
, enum run_as_cmd cmd
,
765 struct run_as_ret
*run_as_ret
)
769 if (COMMAND_OUT_FD_COUNT(cmd
) == 0) {
773 ret
= do_recv_fds(worker
->sockpair
[0], COMMAND_OUT_FDS(cmd
, run_as_ret
),
774 COMMAND_OUT_FD_COUNT(cmd
));
776 PERROR("Failed to receive file descriptor from run-as worker");
784 int recv_fds_from_master(struct run_as_worker
*worker
, struct run_as_data
*data
)
788 if (COMMAND_USE_CWD_FD(data
)) {
791 for (i
= 0; i
< COMMAND_IN_FD_COUNT(data
); i
++) {
792 COMMAND_IN_FDS(data
)[i
] = AT_FDCWD
;
797 ret
= do_recv_fds(worker
->sockpair
[1], COMMAND_IN_FDS(data
),
798 COMMAND_IN_FD_COUNT(data
));
800 PERROR("Failed to receive file descriptors from master process");
808 int cleanup_received_fds(struct run_as_data
*data
)
812 for (i
= 0; i
< COMMAND_IN_FD_COUNT(data
); i
++) {
813 if (COMMAND_IN_FDS(data
)[i
] == -1) {
816 ret
= close(COMMAND_IN_FDS(data
)[i
]);
818 PERROR("Failed to close file descriptor received fd in run-as worker");
827 * Return < 0 on error, 0 if OK, 1 on hangup.
830 int handle_one_cmd(struct run_as_worker
*worker
)
833 struct run_as_data data
= {};
834 ssize_t readlen
, writelen
;
835 struct run_as_ret sendret
= {};
840 * Stage 1: Receive run_as_data struct from the master.
841 * The structure contains the command type and all the parameters needed for
844 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[1], &data
,
851 if (readlen
< sizeof(data
)) {
852 PERROR("lttcomm_recv_unix_sock error");
857 cmd
= run_as_enum_to_fct(data
.cmd
);
864 * Stage 2: Receive file descriptor from master.
865 * Some commands need a file descriptor as input so if it's needed we
866 * receive the fd using the Unix socket.
868 ret
= recv_fds_from_master(worker
, &data
);
870 PERROR("recv_fd_from_master error");
875 prev_euid
= getuid();
876 if (data
.gid
!= getegid()) {
877 ret
= setegid(data
.gid
);
879 sendret
._error
= true;
880 sendret
._errno
= errno
;
885 if (data
.uid
!= prev_euid
) {
886 ret
= seteuid(data
.uid
);
888 sendret
._error
= true;
889 sendret
._errno
= errno
;
896 * Also set umask to 0 for mkdir executable bit.
901 * Stage 3: Execute the command
903 ret
= (*cmd
)(&data
, &sendret
);
905 DBG("Execution of command returned an error");
909 ret
= cleanup_received_fds(&data
);
911 ERR("Error cleaning up FD");
916 * Stage 4: Send run_as_ret structure to the master.
917 * This structure contain the return value of the command and the errno.
919 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[1], &sendret
,
921 if (writelen
< sizeof(sendret
)) {
922 PERROR("lttcomm_send_unix_sock error");
928 * Stage 5: Send resulting file descriptors to the master.
930 ret
= send_fds_to_master(worker
, data
.cmd
, &sendret
);
932 DBG("Sending FD to master returned an error");
936 if (seteuid(prev_euid
) < 0) {
947 int run_as_worker(struct run_as_worker
*worker
)
951 struct run_as_ret sendret
;
952 size_t proc_orig_len
;
955 * Initialize worker. Set a different process cmdline.
957 proc_orig_len
= strlen(worker
->procname
);
958 memset(worker
->procname
, 0, proc_orig_len
);
959 strncpy(worker
->procname
, DEFAULT_RUN_AS_WORKER_NAME
, proc_orig_len
);
961 ret
= lttng_prctl(PR_SET_NAME
,
962 (unsigned long) DEFAULT_RUN_AS_WORKER_NAME
, 0, 0, 0);
963 if (ret
&& ret
!= -ENOSYS
) {
964 /* Don't fail as this is not essential. */
965 PERROR("prctl PR_SET_NAME");
968 memset(&sendret
, 0, sizeof(sendret
));
970 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[1], &sendret
,
972 if (writelen
< sizeof(sendret
)) {
973 PERROR("lttcomm_send_unix_sock error");
979 ret
= handle_one_cmd(worker
);
983 } else if (ret
> 0) {
986 continue; /* Next command. */
995 int run_as_cmd(struct run_as_worker
*worker
,
997 struct run_as_data
*data
,
998 struct run_as_ret
*ret_value
,
999 uid_t uid
, gid_t gid
)
1002 ssize_t readlen
, writelen
;
1005 * If we are non-root, we can only deal with our own uid.
1007 if (geteuid() != 0) {
1008 if (uid
!= geteuid()) {
1010 ret_value
->_errno
= EPERM
;
1011 ERR("Client (%d)/Server (%d) UID mismatch (and sessiond is not root)",
1012 (int) uid
, (int) geteuid());
1022 * Stage 1: Send the run_as_data struct to the worker process
1024 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[0], data
,
1026 if (writelen
< sizeof(*data
)) {
1027 PERROR("Error writing message to run_as");
1029 ret_value
->_errno
= EIO
;
1034 * Stage 2: Send file descriptor to the worker process if needed
1036 ret
= send_fds_to_worker(worker
, data
);
1038 PERROR("do_send_fd error");
1040 ret_value
->_errno
= EIO
;
1045 * Stage 3: Wait for the execution of the command
1049 * Stage 4: Receive the run_as_ret struct containing the return value and
1052 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[0], ret_value
,
1053 sizeof(*ret_value
));
1055 ERR("Run-as worker has hung-up during run_as_cmd");
1057 ret_value
->_errno
= EIO
;
1059 } else if (readlen
< sizeof(*ret_value
)) {
1060 PERROR("Error reading response from run_as");
1062 ret_value
->_errno
= errno
;
1066 if (ret_value
->_error
) {
1067 /* Skip stage 5 on error as there will be no fd to receive. */
1072 * Stage 5: Receive file descriptor if needed
1074 ret
= recv_fds_from_worker(worker
, cmd
, ret_value
);
1076 ERR("Error receiving fd");
1078 ret_value
->_errno
= EIO
;
1086 * This is for debugging ONLY and should not be considered secure.
1089 int run_as_noworker(enum run_as_cmd cmd
,
1090 struct run_as_data
*data
, struct run_as_ret
*ret_value
,
1091 uid_t uid
, gid_t gid
)
1093 int ret
, saved_errno
;
1097 fct
= run_as_enum_to_fct(cmd
);
1103 old_mask
= umask(0);
1104 ret
= fct(data
, ret_value
);
1105 saved_errno
= ret_value
->_errno
;
1107 errno
= saved_errno
;
1113 int reset_sighandler(void)
1117 DBG("Resetting run_as worker signal handlers to default");
1118 for (sig
= 1; sig
<= 31; sig
++) {
1119 (void) signal(sig
, SIG_DFL
);
1125 void worker_sighandler(int sig
)
1127 const char *signame
;
1130 * The worker will inherit its parent's signals since they are part of
1131 * the same process group. However, in the case of SIGINT and SIGTERM,
1132 * we want to give the worker a chance to teardown gracefully when its
1133 * parent closes the command socket.
1140 signame
= "SIGTERM";
1147 DBG("run_as worker received signal %s", signame
);
1149 DBG("run_as_worker received signal %d", sig
);
1154 int set_worker_sighandlers(void)
1158 struct sigaction sa
;
1160 if ((ret
= sigemptyset(&sigset
)) < 0) {
1161 PERROR("sigemptyset");
1165 sa
.sa_handler
= worker_sighandler
;
1166 sa
.sa_mask
= sigset
;
1168 if ((ret
= sigaction(SIGINT
, &sa
, NULL
)) < 0) {
1169 PERROR("sigaction SIGINT");
1173 if ((ret
= sigaction(SIGTERM
, &sa
, NULL
)) < 0) {
1174 PERROR("sigaction SIGTERM");
1178 DBG("run_as signal handler set for SIGTERM and SIGINT");
1184 int run_as_create_worker_no_lock(const char *procname
,
1185 post_fork_cleanup_cb clean_up_func
,
1186 void *clean_up_user_data
)
1191 struct run_as_ret recvret
;
1192 struct run_as_worker
*worker
;
1194 assert(!global_worker
);
1197 * Don't initialize a worker, all run_as tasks will be performed
1198 * in the current process.
1203 worker
= zmalloc(sizeof(*worker
));
1208 worker
->procname
= strdup(procname
);
1209 if (!worker
->procname
) {
1211 goto error_procname_alloc
;
1213 /* Create unix socket. */
1214 if (lttcomm_create_anon_unix_socketpair(worker
->sockpair
) < 0) {
1225 } else if (pid
== 0) {
1230 set_worker_sighandlers();
1231 if (clean_up_func
) {
1232 if (clean_up_func(clean_up_user_data
) < 0) {
1233 ERR("Run-as post-fork clean-up failed, exiting.");
1238 /* Just close, no shutdown. */
1239 if (close(worker
->sockpair
[0])) {
1245 * Close all FDs aside from STDIN, STDOUT, STDERR and sockpair[1]
1246 * Sockpair[1] is used as a control channel with the master
1248 for (i
= 3; i
< sysconf(_SC_OPEN_MAX
); i
++) {
1249 if (i
!= worker
->sockpair
[1]) {
1254 worker
->sockpair
[0] = -1;
1255 ret
= run_as_worker(worker
);
1256 if (lttcomm_close_unix_sock(worker
->sockpair
[1])) {
1260 worker
->sockpair
[1] = -1;
1261 free(worker
->procname
);
1263 LOG(ret
? PRINT_ERR
: PRINT_DBG
, "run_as worker exiting (ret = %d)", ret
);
1264 exit(ret
? EXIT_FAILURE
: EXIT_SUCCESS
);
1268 /* Just close, no shutdown. */
1269 if (close(worker
->sockpair
[1])) {
1274 worker
->sockpair
[1] = -1;
1276 /* Wait for worker to become ready. */
1277 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[0],
1278 &recvret
, sizeof(recvret
));
1279 if (readlen
< sizeof(recvret
)) {
1280 ERR("readlen: %zd", readlen
);
1281 PERROR("Error reading response from run_as at creation");
1285 global_worker
= worker
;
1290 /* Error handling. */
1292 for (i
= 0; i
< 2; i
++) {
1293 if (worker
->sockpair
[i
] < 0) {
1296 if (lttcomm_close_unix_sock(worker
->sockpair
[i
])) {
1299 worker
->sockpair
[i
] = -1;
1302 free(worker
->procname
);
1303 error_procname_alloc
:
1309 void run_as_destroy_worker_no_lock(void)
1311 struct run_as_worker
*worker
= global_worker
;
1313 DBG("Destroying run_as worker");
1317 /* Close unix socket */
1318 DBG("Closing run_as worker socket");
1319 if (lttcomm_close_unix_sock(worker
->sockpair
[0])) {
1322 worker
->sockpair
[0] = -1;
1323 /* Wait for worker. */
1328 wait_ret
= waitpid(worker
->pid
, &status
, 0);
1330 if (errno
== EINTR
) {
1337 if (WIFEXITED(status
)) {
1338 LOG(WEXITSTATUS(status
) == 0 ? PRINT_DBG
: PRINT_ERR
,
1339 DEFAULT_RUN_AS_WORKER_NAME
" terminated with status code %d",
1340 WEXITSTATUS(status
));
1342 } else if (WIFSIGNALED(status
)) {
1343 ERR(DEFAULT_RUN_AS_WORKER_NAME
" was killed by signal %d",
1348 free(worker
->procname
);
1350 global_worker
= NULL
;
1354 int run_as_restart_worker(struct run_as_worker
*worker
)
1357 char *procname
= NULL
;
1359 procname
= worker
->procname
;
1361 /* Close socket to run_as worker process and clean up the zombie process */
1362 run_as_destroy_worker_no_lock();
1364 /* Create a new run_as worker process*/
1365 ret
= run_as_create_worker_no_lock(procname
, NULL
, NULL
);
1367 ERR("Restarting the worker process failed");
1376 int run_as(enum run_as_cmd cmd
, struct run_as_data
*data
,
1377 struct run_as_ret
*ret_value
, uid_t uid
, gid_t gid
)
1379 int ret
, saved_errno
;
1381 pthread_mutex_lock(&worker_lock
);
1383 DBG("Using run_as worker");
1385 assert(global_worker
);
1387 ret
= run_as_cmd(global_worker
, cmd
, data
, ret_value
, uid
, gid
);
1388 saved_errno
= ret_value
->_errno
;
1391 * If the worker thread crashed the errno is set to EIO. we log
1392 * the error and start a new worker process.
1394 if (ret
== -1 && saved_errno
== EIO
) {
1395 DBG("Socket closed unexpectedly... "
1396 "Restarting the worker process");
1397 ret
= run_as_restart_worker(global_worker
);
1399 ERR("Failed to restart worker process.");
1404 DBG("Using run_as without worker");
1405 ret
= run_as_noworker(cmd
, data
, ret_value
, uid
, gid
);
1408 pthread_mutex_unlock(&worker_lock
);
1413 int run_as_mkdir_recursive(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
1415 return run_as_mkdirat_recursive(AT_FDCWD
, path
, mode
, uid
, gid
);
1419 int run_as_mkdirat_recursive(int dirfd
, const char *path
, mode_t mode
,
1420 uid_t uid
, gid_t gid
)
1423 struct run_as_data data
= {};
1424 struct run_as_ret run_as_ret
= {};
1426 DBG3("mkdirat() recursive fd = %d%s, path = %s, mode = %d, uid = %d, gid = %d",
1427 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1428 path
, (int) mode
, (int) uid
, (int) gid
);
1429 ret
= lttng_strncpy(data
.u
.mkdir
.path
, path
,
1430 sizeof(data
.u
.mkdir
.path
));
1432 ERR("Failed to copy path argument of mkdirat recursive command");
1435 data
.u
.mkdir
.path
[sizeof(data
.u
.mkdir
.path
) - 1] = '\0';
1436 data
.u
.mkdir
.mode
= mode
;
1437 data
.u
.mkdir
.dirfd
= dirfd
;
1438 run_as(dirfd
== AT_FDCWD
? RUN_AS_MKDIR_RECURSIVE
: RUN_AS_MKDIRAT_RECURSIVE
,
1439 &data
, &run_as_ret
, uid
, gid
);
1440 errno
= run_as_ret
._errno
;
1441 ret
= run_as_ret
.u
.ret
;
1447 int run_as_mkdir(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
1449 return run_as_mkdirat(AT_FDCWD
, path
, mode
, uid
, gid
);
1453 int run_as_mkdirat(int dirfd
, const char *path
, mode_t mode
,
1454 uid_t uid
, gid_t gid
)
1457 struct run_as_data data
= {};
1458 struct run_as_ret run_as_ret
= {};
1460 DBG3("mkdirat() recursive fd = %d%s, path = %s, mode = %d, uid = %d, gid = %d",
1461 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1462 path
, (int) mode
, (int) uid
, (int) gid
);
1463 ret
= lttng_strncpy(data
.u
.mkdir
.path
, path
,
1464 sizeof(data
.u
.mkdir
.path
));
1466 ERR("Failed to copy path argument of mkdirat command");
1469 data
.u
.mkdir
.path
[sizeof(data
.u
.mkdir
.path
) - 1] = '\0';
1470 data
.u
.mkdir
.mode
= mode
;
1471 data
.u
.mkdir
.dirfd
= dirfd
;
1472 run_as(dirfd
== AT_FDCWD
? RUN_AS_MKDIR
: RUN_AS_MKDIRAT
,
1473 &data
, &run_as_ret
, uid
, gid
);
1474 errno
= run_as_ret
._errno
;
1475 ret
= run_as_ret
.u
.ret
;
1481 int run_as_open(const char *path
, int flags
, mode_t mode
, uid_t uid
,
1484 return run_as_openat(AT_FDCWD
, path
, flags
, mode
, uid
, gid
);
1488 int run_as_openat(int dirfd
, const char *path
, int flags
, mode_t mode
,
1489 uid_t uid
, gid_t gid
)
1492 struct run_as_data data
= {};
1493 struct run_as_ret run_as_ret
= {};
1495 DBG3("openat() fd = %d%s, path = %s, flags = %X, mode = %d, uid %d, gid %d",
1496 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1497 path
, flags
, (int) mode
, (int) uid
, (int) gid
);
1498 ret
= lttng_strncpy(data
.u
.open
.path
, path
, sizeof(data
.u
.open
.path
));
1500 ERR("Failed to copy path argument of open command");
1503 data
.u
.open
.flags
= flags
;
1504 data
.u
.open
.mode
= mode
;
1505 data
.u
.open
.dirfd
= dirfd
;
1506 run_as(dirfd
== AT_FDCWD
? RUN_AS_OPEN
: RUN_AS_OPENAT
,
1507 &data
, &run_as_ret
, uid
, gid
);
1508 errno
= run_as_ret
._errno
;
1509 ret
= run_as_ret
.u
.ret
< 0 ? run_as_ret
.u
.ret
:
1510 run_as_ret
.u
.open
.fd
;
1516 int run_as_unlink(const char *path
, uid_t uid
, gid_t gid
)
1518 return run_as_unlinkat(AT_FDCWD
, path
, uid
, gid
);
1522 int run_as_unlinkat(int dirfd
, const char *path
, uid_t uid
, gid_t gid
)
1525 struct run_as_data data
= {};
1526 struct run_as_ret run_as_ret
= {};
1528 DBG3("unlinkat() fd = %d%s, path = %s, uid = %d, gid = %d",
1529 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1530 path
, (int) uid
, (int) gid
);
1531 ret
= lttng_strncpy(data
.u
.unlink
.path
, path
,
1532 sizeof(data
.u
.unlink
.path
));
1536 data
.u
.unlink
.dirfd
= dirfd
;
1537 run_as(dirfd
== AT_FDCWD
? RUN_AS_UNLINK
: RUN_AS_UNLINKAT
, &data
,
1538 &run_as_ret
, uid
, gid
);
1539 errno
= run_as_ret
._errno
;
1540 ret
= run_as_ret
.u
.ret
;
1546 int run_as_rmdir(const char *path
, uid_t uid
, gid_t gid
)
1548 return run_as_rmdirat(AT_FDCWD
, path
, uid
, gid
);
1552 int run_as_rmdirat(int dirfd
, const char *path
, uid_t uid
, gid_t gid
)
1555 struct run_as_data data
= {};
1556 struct run_as_ret run_as_ret
= {};
1558 DBG3("rmdirat() fd = %d%s, path = %s, uid = %d, gid = %d",
1559 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1560 path
, (int) uid
, (int) gid
);
1561 ret
= lttng_strncpy(data
.u
.rmdir
.path
, path
,
1562 sizeof(data
.u
.rmdir
.path
));
1566 data
.u
.rmdir
.dirfd
= dirfd
;
1567 run_as(dirfd
== AT_FDCWD
? RUN_AS_RMDIR
: RUN_AS_RMDIRAT
, &data
,
1568 &run_as_ret
, uid
, gid
);
1569 errno
= run_as_ret
._errno
;
1570 ret
= run_as_ret
.u
.ret
;
1576 int run_as_rmdir_recursive(const char *path
, uid_t uid
, gid_t gid
, int flags
)
1578 return run_as_rmdirat_recursive(AT_FDCWD
, path
, uid
, gid
, flags
);
1582 int run_as_rmdirat_recursive(int dirfd
, const char *path
, uid_t uid
, gid_t gid
, int flags
)
1585 struct run_as_data data
= {};
1586 struct run_as_ret run_as_ret
= {};
1588 DBG3("rmdirat() recursive fd = %d%s, path = %s, uid = %d, gid = %d",
1589 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1590 path
, (int) uid
, (int) gid
);
1591 ret
= lttng_strncpy(data
.u
.rmdir
.path
, path
,
1592 sizeof(data
.u
.rmdir
.path
));
1596 data
.u
.rmdir
.dirfd
= dirfd
;
1597 data
.u
.rmdir
.flags
= flags
;
1598 run_as(dirfd
== AT_FDCWD
? RUN_AS_RMDIR_RECURSIVE
: RUN_AS_RMDIRAT_RECURSIVE
,
1599 &data
, &run_as_ret
, uid
, gid
);
1600 errno
= run_as_ret
._errno
;
1601 ret
= run_as_ret
.u
.ret
;
1607 int run_as_rename(const char *old
, const char *new, uid_t uid
, gid_t gid
)
1609 return run_as_renameat(AT_FDCWD
, old
, AT_FDCWD
, new, uid
, gid
);
1613 int run_as_renameat(int old_dirfd
, const char *old_name
,
1614 int new_dirfd
, const char *new_name
, uid_t uid
, gid_t gid
)
1617 struct run_as_data data
= {};
1618 struct run_as_ret run_as_ret
= {};
1620 DBG3("renameat() old_dirfd = %d%s, old_name = %s, new_dirfd = %d%s, new_name = %s, uid = %d, gid = %d",
1621 old_dirfd
, old_dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1623 new_dirfd
, new_dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1624 new_name
, (int) uid
, (int) gid
);
1625 ret
= lttng_strncpy(data
.u
.rename
.old_path
, old_name
,
1626 sizeof(data
.u
.rename
.old_path
));
1630 ret
= lttng_strncpy(data
.u
.rename
.new_path
, new_name
,
1631 sizeof(data
.u
.rename
.new_path
));
1636 data
.u
.rename
.dirfds
[0] = old_dirfd
;
1637 data
.u
.rename
.dirfds
[1] = new_dirfd
;
1638 run_as(old_dirfd
== AT_FDCWD
&& new_dirfd
== AT_FDCWD
?
1639 RUN_AS_RENAME
: RUN_AS_RENAMEAT
,
1640 &data
, &run_as_ret
, uid
, gid
);
1641 errno
= run_as_ret
._errno
;
1642 ret
= run_as_ret
.u
.ret
;
1648 int run_as_extract_elf_symbol_offset(int fd
, const char* function
,
1649 uid_t uid
, gid_t gid
, uint64_t *offset
)
1652 struct run_as_data data
= {};
1653 struct run_as_ret run_as_ret
= {};
1655 DBG3("extract_elf_symbol_offset() on fd=%d and function=%s "
1656 "with for uid %d and gid %d", fd
, function
,
1657 (int) uid
, (int) gid
);
1659 data
.u
.extract_elf_symbol_offset
.fd
= fd
;
1661 strncpy(data
.u
.extract_elf_symbol_offset
.function
, function
, LTTNG_SYMBOL_NAME_LEN
- 1);
1662 data
.u
.extract_elf_symbol_offset
.function
[LTTNG_SYMBOL_NAME_LEN
- 1] = '\0';
1663 ret
= lttng_strncpy(data
.u
.extract_elf_symbol_offset
.function
,
1665 sizeof(data
.u
.extract_elf_symbol_offset
.function
));
1670 run_as(RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
, &data
, &run_as_ret
, uid
, gid
);
1671 errno
= run_as_ret
._errno
;
1672 if (run_as_ret
._error
) {
1677 *offset
= run_as_ret
.u
.extract_elf_symbol_offset
.offset
;
1683 int run_as_extract_sdt_probe_offsets(int fd
, const char* provider_name
,
1684 const char* probe_name
, uid_t uid
, gid_t gid
,
1685 uint64_t **offsets
, uint32_t *num_offset
)
1688 struct run_as_data data
= {};
1689 struct run_as_ret run_as_ret
= {};
1691 DBG3("extract_sdt_probe_offsets() on fd=%d, probe_name=%s and "
1692 "provider_name=%s with for uid %d and gid %d", fd
,
1693 probe_name
, provider_name
, (int) uid
, (int) gid
);
1695 data
.u
.extract_sdt_probe_offsets
.fd
= fd
;
1697 ret
= lttng_strncpy(data
.u
.extract_sdt_probe_offsets
.probe_name
, probe_name
,
1698 sizeof(data
.u
.extract_sdt_probe_offsets
.probe_name
));
1702 ret
= lttng_strncpy(data
.u
.extract_sdt_probe_offsets
.provider_name
,
1704 sizeof(data
.u
.extract_sdt_probe_offsets
.provider_name
));
1709 run_as(RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
, &data
, &run_as_ret
, uid
, gid
);
1710 errno
= run_as_ret
._errno
;
1711 if (run_as_ret
._error
) {
1716 *num_offset
= run_as_ret
.u
.extract_sdt_probe_offsets
.num_offset
;
1717 *offsets
= zmalloc(*num_offset
* sizeof(uint64_t));
1723 memcpy(*offsets
, run_as_ret
.u
.extract_sdt_probe_offsets
.offsets
,
1724 *num_offset
* sizeof(uint64_t));
1730 int run_as_create_worker(const char *procname
,
1731 post_fork_cleanup_cb clean_up_func
,
1732 void *clean_up_user_data
)
1736 pthread_mutex_lock(&worker_lock
);
1737 ret
= run_as_create_worker_no_lock(procname
, clean_up_func
,
1738 clean_up_user_data
);
1739 pthread_mutex_unlock(&worker_lock
);
1744 void run_as_destroy_worker(void)
1746 pthread_mutex_lock(&worker_lock
);
1747 run_as_destroy_worker_no_lock();
1748 pthread_mutex_unlock(&worker_lock
);