2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 * Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 * 2019 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include <sys/types.h>
36 #include <common/lttng-kernel.h>
37 #include <common/common.h>
38 #include <common/utils.h>
39 #include <common/compat/getenv.h>
40 #include <common/compat/prctl.h>
41 #include <common/unix.h>
42 #include <common/defaults.h>
43 #include <common/lttng-elf.h>
45 #include <lttng/constant.h>
51 typedef int (*run_as_fct
)(struct run_as_data
*data
, struct run_as_ret
*ret_value
);
56 RUN_AS_MKDIR_RECURSIVE
,
57 RUN_AS_MKDIRAT_RECURSIVE
,
64 RUN_AS_RMDIR_RECURSIVE
,
65 RUN_AS_RMDIRAT_RECURSIVE
,
68 RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
,
69 RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
,
72 struct run_as_mkdir_data
{
74 char path
[LTTNG_PATH_MAX
];
78 struct run_as_open_data
{
80 char path
[LTTNG_PATH_MAX
];
85 struct run_as_unlink_data
{
87 char path
[LTTNG_PATH_MAX
];
90 struct run_as_rmdir_data
{
92 char path
[LTTNG_PATH_MAX
];
95 struct run_as_extract_elf_symbol_offset_data
{
97 char function
[LTTNG_SYMBOL_NAME_LEN
];
100 struct run_as_extract_sdt_probe_offsets_data
{
102 char probe_name
[LTTNG_SYMBOL_NAME_LEN
];
103 char provider_name
[LTTNG_SYMBOL_NAME_LEN
];
106 struct run_as_rename_data
{
112 char old_path
[LTTNG_PATH_MAX
];
113 char new_path
[LTTNG_PATH_MAX
];
116 struct run_as_open_ret
{
120 struct run_as_extract_elf_symbol_offset_ret
{
124 struct run_as_extract_sdt_probe_offsets_ret
{
126 uint64_t offsets
[LTTNG_KERNEL_MAX_UPROBE_NUM
];
132 struct run_as_mkdir_data mkdir
;
133 struct run_as_open_data open
;
134 struct run_as_unlink_data unlink
;
135 struct run_as_rmdir_data rmdir
;
136 struct run_as_rename_data rename
;
137 struct run_as_extract_elf_symbol_offset_data extract_elf_symbol_offset
;
138 struct run_as_extract_sdt_probe_offsets_data extract_sdt_probe_offsets
;
145 * The run_as_ret structure holds the returned value and status of the command.
147 * The `u` union field holds the return value of the command; in most cases it
148 * represents the success or the failure of the command. In more complex
149 * commands, it holds a computed value.
151 * The _errno field is the errno recorded after the execution of the command.
153 * The _error fields is used the signify that return status of the command. For
154 * simple commands returning `int` the _error field will be the same as the
155 * ret_int field. In complex commands, it signify the success or failure of the
162 struct run_as_open_ret open
;
163 struct run_as_extract_elf_symbol_offset_ret extract_elf_symbol_offset
;
164 struct run_as_extract_sdt_probe_offsets_ret extract_sdt_probe_offsets
;
170 #define COMMAND_IN_FDS(data_ptr) ({ \
172 if (command_properties[data_ptr->cmd].in_fds_offset != -1) { \
173 fds = (int *) ((char *) data_ptr + command_properties[data_ptr->cmd].in_fds_offset); \
178 #define COMMAND_OUT_FDS(cmd, ret_ptr) ({ \
180 if (command_properties[cmd].out_fds_offset != -1) { \
181 fds = (int *) ((char *) ret_ptr + command_properties[cmd].out_fds_offset); \
186 #define COMMAND_IN_FD_COUNT(data_ptr) ({ \
187 command_properties[data_ptr->cmd].in_fd_count; \
190 #define COMMAND_OUT_FD_COUNT(cmd) ({ \
191 command_properties[cmd].out_fd_count; \
194 #define COMMAND_USE_CWD_FD(data_ptr) command_properties[data_ptr->cmd].use_cwd_fd
196 struct run_as_command_properties
{
197 /* Set to -1 when not applicable. */
198 ptrdiff_t in_fds_offset
, out_fds_offset
;
199 unsigned int in_fd_count
, out_fd_count
;
203 static const struct run_as_command_properties command_properties
[] = {
205 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
207 .out_fds_offset
= -1,
212 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
214 .out_fds_offset
= -1,
218 [RUN_AS_MKDIR_RECURSIVE
] = {
219 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
221 .out_fds_offset
= -1,
225 [RUN_AS_MKDIRAT_RECURSIVE
] = {
226 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
228 .out_fds_offset
= -1,
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
.open
.dirfd
),
242 .out_fds_offset
= offsetof(struct run_as_ret
, u
.open
.fd
),
247 .in_fds_offset
= offsetof(struct run_as_data
, u
.unlink
.dirfd
),
249 .out_fds_offset
= -1,
253 [RUN_AS_UNLINKAT
] = {
254 .in_fds_offset
= offsetof(struct run_as_data
, u
.unlink
.dirfd
),
256 .out_fds_offset
= -1,
260 [RUN_AS_RMDIR_RECURSIVE
] = {
261 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
263 .out_fds_offset
= -1,
267 [RUN_AS_RMDIRAT_RECURSIVE
] = {
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
.rmdir
.dirfd
),
284 .out_fds_offset
= -1,
289 .in_fds_offset
= offsetof(struct run_as_data
, u
.rename
.dirfds
),
291 .out_fds_offset
= -1,
295 [RUN_AS_RENAMEAT
] = {
296 .in_fds_offset
= offsetof(struct run_as_data
, u
.rename
.dirfds
),
298 .out_fds_offset
= -1,
302 [RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
] = {
303 .in_fds_offset
= offsetof(struct run_as_data
,
304 u
.extract_elf_symbol_offset
.fd
),
306 .out_fds_offset
= -1,
310 [RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
] = {
311 .in_fds_offset
= offsetof(struct run_as_data
,
312 u
.extract_sdt_probe_offsets
.fd
),
314 .out_fds_offset
= -1,
320 struct run_as_worker
{
321 pid_t pid
; /* Worker PID. */
326 /* Single global worker per process (for now). */
327 static struct run_as_worker
*global_worker
;
328 /* Lock protecting the worker. */
329 static pthread_mutex_t worker_lock
= PTHREAD_MUTEX_INITIALIZER
;
341 return !lttng_secure_getenv("LTTNG_DEBUG_NOCLONE");
346 * Create recursively directory using the FULL path.
349 int _mkdirat_recursive(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
353 struct lttng_directory_handle handle
;
355 path
= data
->u
.mkdir
.path
;
356 mode
= data
->u
.mkdir
.mode
;
358 (void) lttng_directory_handle_init_from_dirfd(&handle
,
359 data
->u
.mkdir
.dirfd
);
360 /* Ownership of dirfd is transferred to the handle. */
361 data
->u
.mkdir
.dirfd
= -1;
362 /* Safe to call as we have transitioned to the requested uid/gid. */
364 lttng_directory_handle_create_subdirectory_recursive(
365 &handle
, path
, mode
);
366 ret_value
->_errno
= errno
;
367 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
368 lttng_directory_handle_fini(&handle
);
369 return ret_value
->u
.ret
;
373 int _mkdirat(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
377 struct lttng_directory_handle handle
;
379 path
= data
->u
.mkdir
.path
;
380 mode
= data
->u
.mkdir
.mode
;
382 (void) lttng_directory_handle_init_from_dirfd(&handle
,
383 data
->u
.mkdir
.dirfd
);
384 /* Ownership of dirfd is transferred to the handle. */
385 data
->u
.mkdir
.dirfd
= -1;
386 /* Safe to call as we have transitioned to the requested uid/gid. */
388 lttng_directory_handle_create_subdirectory(
389 &handle
, path
, mode
);
390 ret_value
->_errno
= errno
;
391 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
392 lttng_directory_handle_fini(&handle
);
393 return ret_value
->u
.ret
;
397 int _open(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
400 struct lttng_directory_handle handle
;
402 (void) lttng_directory_handle_init_from_dirfd(&handle
,
404 /* Ownership of dirfd is transferred to the handle. */
405 data
->u
.open
.dirfd
= -1;
407 fd
= lttng_directory_handle_open_file(&handle
,
408 data
->u
.open
.path
, data
->u
.open
.flags
,
411 ret_value
->u
.ret
= -1;
412 ret_value
->u
.open
.fd
= -1;
414 ret_value
->u
.ret
= 0;
415 ret_value
->u
.open
.fd
= fd
;
418 ret_value
->_errno
= errno
;
419 ret_value
->_error
= fd
< 0;
420 lttng_directory_handle_fini(&handle
);
421 return ret_value
->u
.ret
;
425 int _unlink(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
427 struct lttng_directory_handle handle
;
429 (void) lttng_directory_handle_init_from_dirfd(&handle
,
430 data
->u
.unlink
.dirfd
);
432 /* Ownership of dirfd is transferred to the handle. */
433 data
->u
.unlink
.dirfd
= -1;
435 ret_value
->u
.ret
= lttng_directory_handle_unlink_file(&handle
,
436 data
->u
.unlink
.path
);
437 ret_value
->_errno
= errno
;
438 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
439 lttng_directory_handle_fini(&handle
);
440 return ret_value
->u
.ret
;
444 int _rmdir(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
446 struct lttng_directory_handle handle
;
448 (void) lttng_directory_handle_init_from_dirfd(&handle
,
449 data
->u
.rmdir
.dirfd
);
451 /* Ownership of dirfd is transferred to the handle. */
452 data
->u
.rmdir
.dirfd
= -1;
454 ret_value
->u
.ret
= lttng_directory_handle_remove_subdirectory(
455 &handle
, data
->u
.rmdir
.path
);
456 ret_value
->_errno
= errno
;
457 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
458 lttng_directory_handle_fini(&handle
);
459 return ret_value
->u
.ret
;
463 int _rmdir_recursive(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
465 struct lttng_directory_handle handle
;
467 (void) lttng_directory_handle_init_from_dirfd(&handle
,
468 data
->u
.rmdir
.dirfd
);
470 /* Ownership of dirfd is transferred to the handle. */
471 data
->u
.rmdir
.dirfd
= -1;
473 ret_value
->u
.ret
= lttng_directory_handle_remove_subdirectory_recursive(
474 &handle
, data
->u
.rmdir
.path
);
475 ret_value
->_errno
= errno
;
476 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
477 lttng_directory_handle_fini(&handle
);
478 return ret_value
->u
.ret
;
482 int _rename(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
484 const char *old_path
, *new_path
;
485 struct lttng_directory_handle old_handle
, new_handle
;
487 old_path
= data
->u
.rename
.old_path
;
488 new_path
= data
->u
.rename
.new_path
;
490 (void) lttng_directory_handle_init_from_dirfd(&old_handle
,
491 data
->u
.rename
.dirfds
[0]);
492 (void) lttng_directory_handle_init_from_dirfd(&new_handle
,
493 data
->u
.rename
.dirfds
[1]);
495 /* Ownership of dirfds are transferred to the handles. */
496 data
->u
.rename
.dirfds
[0] = data
->u
.rename
.dirfds
[1] = -1;
498 /* Safe to call as we have transitioned to the requested uid/gid. */
499 ret_value
->u
.ret
= lttng_directory_handle_rename(
500 &old_handle
, old_path
, &new_handle
, new_path
);
501 ret_value
->_errno
= errno
;
502 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
503 lttng_directory_handle_fini(&old_handle
);
504 lttng_directory_handle_fini(&new_handle
);
505 return ret_value
->u
.ret
;
510 int _extract_elf_symbol_offset(struct run_as_data
*data
,
511 struct run_as_ret
*ret_value
)
515 ret_value
->_error
= false;
516 ret
= lttng_elf_get_symbol_offset(data
->u
.extract_elf_symbol_offset
.fd
,
517 data
->u
.extract_elf_symbol_offset
.function
,
518 &ret_value
->u
.extract_elf_symbol_offset
.offset
);
520 DBG("Failed to extract ELF function offset");
521 ret_value
->_error
= true;
528 int _extract_sdt_probe_offsets(struct run_as_data
*data
,
529 struct run_as_ret
*ret_value
)
532 uint64_t *offsets
= NULL
;
535 ret_value
->_error
= false;
537 /* On success, this call allocates the offsets paramater. */
538 ret
= lttng_elf_get_sdt_probe_offsets(
539 data
->u
.extract_sdt_probe_offsets
.fd
,
540 data
->u
.extract_sdt_probe_offsets
.provider_name
,
541 data
->u
.extract_sdt_probe_offsets
.probe_name
,
542 &offsets
, &num_offset
);
545 DBG("Failed to extract SDT probe offsets");
546 ret_value
->_error
= true;
550 if (num_offset
<= 0 || num_offset
> LTTNG_KERNEL_MAX_UPROBE_NUM
) {
551 DBG("Wrong number of probes.");
553 ret_value
->_error
= true;
557 /* Copy the content of the offsets array to the ret struct. */
558 memcpy(ret_value
->u
.extract_sdt_probe_offsets
.offsets
,
559 offsets
, num_offset
* sizeof(uint64_t));
561 ret_value
->u
.extract_sdt_probe_offsets
.num_offset
= num_offset
;
570 int _extract_elf_symbol_offset(struct run_as_data
*data
,
571 struct run_as_ret
*ret_value
)
573 ERR("Unimplemented runas command RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET");
578 int _extract_sdt_probe_offsets(struct run_as_data
*data
,
579 struct run_as_ret
*ret_value
)
581 ERR("Unimplemented runas command RUN_AS_EXTRACT_SDT_PROBE_OFFSETS");
587 run_as_fct
run_as_enum_to_fct(enum run_as_cmd cmd
)
593 case RUN_AS_MKDIR_RECURSIVE
:
594 case RUN_AS_MKDIRAT_RECURSIVE
:
595 return _mkdirat_recursive
;
600 case RUN_AS_UNLINKAT
:
605 case RUN_AS_RMDIR_RECURSIVE
:
606 case RUN_AS_RMDIRAT_RECURSIVE
:
607 return _rmdir_recursive
;
609 case RUN_AS_RENAMEAT
:
611 case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
:
612 return _extract_elf_symbol_offset
;
613 case RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
:
614 return _extract_sdt_probe_offsets
;
616 ERR("Unknown command %d", (int) cmd
);
622 int do_send_fds(int sock
, const int *fds
, unsigned int fd_count
)
627 for (i
= 0; i
< fd_count
; i
++) {
629 ERR("Attempt to send invalid file descriptor to master (fd = %i)",
631 /* Return 0 as this is not a fatal error. */
636 len
= lttcomm_send_fds_unix_sock(sock
, fds
, fd_count
);
637 return len
< 0 ? -1 : 0;
641 int do_recv_fds(int sock
, int *fds
, unsigned int fd_count
)
647 len
= lttcomm_recv_fds_unix_sock(sock
, fds
, fd_count
);
651 } else if (len
< 0) {
652 PERROR("Failed to receive file descriptors from socket");
657 for (i
= 0; i
< fd_count
; i
++) {
659 ERR("Invalid file descriptor received from worker (fd = %i)", fds
[i
]);
660 /* Return 0 as this is not a fatal error. */
668 int send_fds_to_worker(const struct run_as_worker
*worker
,
669 const struct run_as_data
*data
)
674 if (COMMAND_USE_CWD_FD(data
) || COMMAND_IN_FD_COUNT(data
) == 0) {
678 for (i
= 0; i
< COMMAND_IN_FD_COUNT(data
); i
++) {
679 if (COMMAND_IN_FDS(data
)[i
] < 0) {
680 ERR("Refusing to send invalid fd to worker (fd = %i)",
681 COMMAND_IN_FDS(data
)[i
]);
687 ret
= do_send_fds(worker
->sockpair
[0], COMMAND_IN_FDS(data
),
688 COMMAND_IN_FD_COUNT(data
));
690 PERROR("Failed to send file descriptor to run-as worker");
699 int send_fds_to_master(struct run_as_worker
*worker
, enum run_as_cmd cmd
,
700 struct run_as_ret
*run_as_ret
)
705 if (COMMAND_OUT_FD_COUNT(cmd
) == 0) {
709 ret
= do_send_fds(worker
->sockpair
[1], COMMAND_OUT_FDS(cmd
, run_as_ret
),
710 COMMAND_OUT_FD_COUNT(cmd
));
712 PERROR("Failed to send file descriptor to master process");
716 for (i
= 0; i
< COMMAND_OUT_FD_COUNT(cmd
); i
++) {
717 int ret_close
= close(COMMAND_OUT_FDS(cmd
, run_as_ret
)[i
]);
720 PERROR("Failed to close result file descriptor");
728 int recv_fds_from_worker(const struct run_as_worker
*worker
, enum run_as_cmd cmd
,
729 struct run_as_ret
*run_as_ret
)
733 if (COMMAND_OUT_FD_COUNT(cmd
) == 0) {
737 ret
= do_recv_fds(worker
->sockpair
[0], COMMAND_OUT_FDS(cmd
, run_as_ret
),
738 COMMAND_OUT_FD_COUNT(cmd
));
740 PERROR("Failed to receive file descriptor from run-as worker");
748 int recv_fds_from_master(struct run_as_worker
*worker
, struct run_as_data
*data
)
752 if (COMMAND_USE_CWD_FD(data
)) {
755 for (i
= 0; i
< COMMAND_IN_FD_COUNT(data
); i
++) {
756 COMMAND_IN_FDS(data
)[i
] = AT_FDCWD
;
761 ret
= do_recv_fds(worker
->sockpair
[1], COMMAND_IN_FDS(data
),
762 COMMAND_IN_FD_COUNT(data
));
764 PERROR("Failed to receive file descriptors from master process");
772 int cleanup_received_fds(struct run_as_data
*data
)
776 for (i
= 0; i
< COMMAND_IN_FD_COUNT(data
); i
++) {
777 if (COMMAND_IN_FDS(data
)[i
] == -1) {
780 ret
= close(COMMAND_IN_FDS(data
)[i
]);
782 PERROR("Failed to close file descriptor received fd in run-as worker");
791 * Return < 0 on error, 0 if OK, 1 on hangup.
794 int handle_one_cmd(struct run_as_worker
*worker
)
797 struct run_as_data data
= {};
798 ssize_t readlen
, writelen
;
799 struct run_as_ret sendret
= {};
804 * Stage 1: Receive run_as_data struct from the master.
805 * The structure contains the command type and all the parameters needed for
808 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[1], &data
,
815 if (readlen
< sizeof(data
)) {
816 PERROR("lttcomm_recv_unix_sock error");
821 cmd
= run_as_enum_to_fct(data
.cmd
);
828 * Stage 2: Receive file descriptor from master.
829 * Some commands need a file descriptor as input so if it's needed we
830 * receive the fd using the Unix socket.
832 ret
= recv_fds_from_master(worker
, &data
);
834 PERROR("recv_fd_from_master error");
839 prev_euid
= getuid();
840 if (data
.gid
!= getegid()) {
841 ret
= setegid(data
.gid
);
843 sendret
._error
= true;
844 sendret
._errno
= errno
;
849 if (data
.uid
!= prev_euid
) {
850 ret
= seteuid(data
.uid
);
852 sendret
._error
= true;
853 sendret
._errno
= errno
;
860 * Also set umask to 0 for mkdir executable bit.
865 * Stage 3: Execute the command
867 ret
= (*cmd
)(&data
, &sendret
);
869 DBG("Execution of command returned an error");
873 ret
= cleanup_received_fds(&data
);
875 ERR("Error cleaning up FD");
880 * Stage 4: Send run_as_ret structure to the master.
881 * This structure contain the return value of the command and the errno.
883 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[1], &sendret
,
885 if (writelen
< sizeof(sendret
)) {
886 PERROR("lttcomm_send_unix_sock error");
892 * Stage 5: Send resulting file descriptors to the master.
894 ret
= send_fds_to_master(worker
, data
.cmd
, &sendret
);
896 DBG("Sending FD to master returned an error");
900 if (seteuid(prev_euid
) < 0) {
911 int run_as_worker(struct run_as_worker
*worker
)
915 struct run_as_ret sendret
;
916 size_t proc_orig_len
;
919 * Initialize worker. Set a different process cmdline.
921 proc_orig_len
= strlen(worker
->procname
);
922 memset(worker
->procname
, 0, proc_orig_len
);
923 strncpy(worker
->procname
, DEFAULT_RUN_AS_WORKER_NAME
, proc_orig_len
);
925 ret
= lttng_prctl(PR_SET_NAME
,
926 (unsigned long) DEFAULT_RUN_AS_WORKER_NAME
, 0, 0, 0);
927 if (ret
&& ret
!= -ENOSYS
) {
928 /* Don't fail as this is not essential. */
929 PERROR("prctl PR_SET_NAME");
932 memset(&sendret
, 0, sizeof(sendret
));
934 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[1], &sendret
,
936 if (writelen
< sizeof(sendret
)) {
937 PERROR("lttcomm_send_unix_sock error");
943 ret
= handle_one_cmd(worker
);
947 } else if (ret
> 0) {
950 continue; /* Next command. */
959 int run_as_cmd(struct run_as_worker
*worker
,
961 struct run_as_data
*data
,
962 struct run_as_ret
*ret_value
,
963 uid_t uid
, gid_t gid
)
966 ssize_t readlen
, writelen
;
969 * If we are non-root, we can only deal with our own uid.
971 if (geteuid() != 0) {
972 if (uid
!= geteuid()) {
974 ret_value
->_errno
= EPERM
;
975 ERR("Client (%d)/Server (%d) UID mismatch (and sessiond is not root)",
976 (int) uid
, (int) geteuid());
986 * Stage 1: Send the run_as_data struct to the worker process
988 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[0], data
,
990 if (writelen
< sizeof(*data
)) {
991 PERROR("Error writing message to run_as");
993 ret_value
->_errno
= EIO
;
998 * Stage 2: Send file descriptor to the worker process if needed
1000 ret
= send_fds_to_worker(worker
, data
);
1002 PERROR("do_send_fd error");
1004 ret_value
->_errno
= EIO
;
1009 * Stage 3: Wait for the execution of the command
1013 * Stage 4: Receive the run_as_ret struct containing the return value and
1016 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[0], ret_value
,
1017 sizeof(*ret_value
));
1019 ERR("Run-as worker has hung-up during run_as_cmd");
1021 ret_value
->_errno
= EIO
;
1023 } else if (readlen
< sizeof(*ret_value
)) {
1024 PERROR("Error reading response from run_as");
1026 ret_value
->_errno
= errno
;
1030 if (ret_value
->_error
) {
1031 /* Skip stage 5 on error as there will be no fd to receive. */
1036 * Stage 5: Receive file descriptor if needed
1038 ret
= recv_fds_from_worker(worker
, cmd
, ret_value
);
1040 ERR("Error receiving fd");
1042 ret_value
->_errno
= EIO
;
1050 * This is for debugging ONLY and should not be considered secure.
1053 int run_as_noworker(enum run_as_cmd cmd
,
1054 struct run_as_data
*data
, struct run_as_ret
*ret_value
,
1055 uid_t uid
, gid_t gid
)
1057 int ret
, saved_errno
;
1061 fct
= run_as_enum_to_fct(cmd
);
1067 old_mask
= umask(0);
1068 ret
= fct(data
, ret_value
);
1069 saved_errno
= ret_value
->_errno
;
1071 errno
= saved_errno
;
1077 int reset_sighandler(void)
1081 DBG("Resetting run_as worker signal handlers to default");
1082 for (sig
= 1; sig
<= 31; sig
++) {
1083 (void) signal(sig
, SIG_DFL
);
1089 void worker_sighandler(int sig
)
1091 const char *signame
;
1094 * The worker will inherit its parent's signals since they are part of
1095 * the same process group. However, in the case of SIGINT and SIGTERM,
1096 * we want to give the worker a chance to teardown gracefully when its
1097 * parent closes the command socket.
1104 signame
= "SIGTERM";
1111 DBG("run_as worker received signal %s", signame
);
1113 DBG("run_as_worker received signal %d", sig
);
1118 int set_worker_sighandlers(void)
1122 struct sigaction sa
;
1124 if ((ret
= sigemptyset(&sigset
)) < 0) {
1125 PERROR("sigemptyset");
1129 sa
.sa_handler
= worker_sighandler
;
1130 sa
.sa_mask
= sigset
;
1132 if ((ret
= sigaction(SIGINT
, &sa
, NULL
)) < 0) {
1133 PERROR("sigaction SIGINT");
1137 if ((ret
= sigaction(SIGTERM
, &sa
, NULL
)) < 0) {
1138 PERROR("sigaction SIGTERM");
1142 DBG("run_as signal handler set for SIGTERM and SIGINT");
1148 int run_as_create_worker_no_lock(const char *procname
,
1149 post_fork_cleanup_cb clean_up_func
,
1150 void *clean_up_user_data
)
1155 struct run_as_ret recvret
;
1156 struct run_as_worker
*worker
;
1158 assert(!global_worker
);
1161 * Don't initialize a worker, all run_as tasks will be performed
1162 * in the current process.
1167 worker
= zmalloc(sizeof(*worker
));
1172 worker
->procname
= strdup(procname
);
1173 if (!worker
->procname
) {
1175 goto error_procname_alloc
;
1177 /* Create unix socket. */
1178 if (lttcomm_create_anon_unix_socketpair(worker
->sockpair
) < 0) {
1189 } else if (pid
== 0) {
1194 set_worker_sighandlers();
1195 if (clean_up_func
) {
1196 if (clean_up_func(clean_up_user_data
) < 0) {
1197 ERR("Run-as post-fork clean-up failed, exiting.");
1202 /* Just close, no shutdown. */
1203 if (close(worker
->sockpair
[0])) {
1209 * Close all FDs aside from STDIN, STDOUT, STDERR and sockpair[1]
1210 * Sockpair[1] is used as a control channel with the master
1212 for (i
= 3; i
< sysconf(_SC_OPEN_MAX
); i
++) {
1213 if (i
!= worker
->sockpair
[1]) {
1218 worker
->sockpair
[0] = -1;
1219 ret
= run_as_worker(worker
);
1220 if (lttcomm_close_unix_sock(worker
->sockpair
[1])) {
1224 worker
->sockpair
[1] = -1;
1225 free(worker
->procname
);
1227 LOG(ret
? PRINT_ERR
: PRINT_DBG
, "run_as worker exiting (ret = %d)", ret
);
1228 exit(ret
? EXIT_FAILURE
: EXIT_SUCCESS
);
1232 /* Just close, no shutdown. */
1233 if (close(worker
->sockpair
[1])) {
1238 worker
->sockpair
[1] = -1;
1240 /* Wait for worker to become ready. */
1241 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[0],
1242 &recvret
, sizeof(recvret
));
1243 if (readlen
< sizeof(recvret
)) {
1244 ERR("readlen: %zd", readlen
);
1245 PERROR("Error reading response from run_as at creation");
1249 global_worker
= worker
;
1254 /* Error handling. */
1256 for (i
= 0; i
< 2; i
++) {
1257 if (worker
->sockpair
[i
] < 0) {
1260 if (lttcomm_close_unix_sock(worker
->sockpair
[i
])) {
1263 worker
->sockpair
[i
] = -1;
1266 free(worker
->procname
);
1267 error_procname_alloc
:
1273 void run_as_destroy_worker_no_lock(void)
1275 struct run_as_worker
*worker
= global_worker
;
1277 DBG("Destroying run_as worker");
1281 /* Close unix socket */
1282 DBG("Closing run_as worker socket");
1283 if (lttcomm_close_unix_sock(worker
->sockpair
[0])) {
1286 worker
->sockpair
[0] = -1;
1287 /* Wait for worker. */
1292 wait_ret
= waitpid(worker
->pid
, &status
, 0);
1294 if (errno
== EINTR
) {
1301 if (WIFEXITED(status
)) {
1302 LOG(WEXITSTATUS(status
) == 0 ? PRINT_DBG
: PRINT_ERR
,
1303 DEFAULT_RUN_AS_WORKER_NAME
" terminated with status code %d",
1304 WEXITSTATUS(status
));
1306 } else if (WIFSIGNALED(status
)) {
1307 ERR(DEFAULT_RUN_AS_WORKER_NAME
" was killed by signal %d",
1312 free(worker
->procname
);
1314 global_worker
= NULL
;
1318 int run_as_restart_worker(struct run_as_worker
*worker
)
1321 char *procname
= NULL
;
1323 procname
= worker
->procname
;
1325 /* Close socket to run_as worker process and clean up the zombie process */
1326 run_as_destroy_worker_no_lock();
1328 /* Create a new run_as worker process*/
1329 ret
= run_as_create_worker_no_lock(procname
, NULL
, NULL
);
1331 ERR("Restarting the worker process failed");
1340 int run_as(enum run_as_cmd cmd
, struct run_as_data
*data
,
1341 struct run_as_ret
*ret_value
, uid_t uid
, gid_t gid
)
1343 int ret
, saved_errno
;
1345 pthread_mutex_lock(&worker_lock
);
1347 DBG("Using run_as worker");
1349 assert(global_worker
);
1351 ret
= run_as_cmd(global_worker
, cmd
, data
, ret_value
, uid
, gid
);
1352 saved_errno
= ret_value
->_errno
;
1355 * If the worker thread crashed the errno is set to EIO. we log
1356 * the error and start a new worker process.
1358 if (ret
== -1 && saved_errno
== EIO
) {
1359 DBG("Socket closed unexpectedly... "
1360 "Restarting the worker process");
1361 ret
= run_as_restart_worker(global_worker
);
1364 ERR("Failed to restart worker process.");
1369 DBG("Using run_as without worker");
1370 ret
= run_as_noworker(cmd
, data
, ret_value
, uid
, gid
);
1373 pthread_mutex_unlock(&worker_lock
);
1378 int run_as_mkdir_recursive(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
1380 return run_as_mkdirat_recursive(AT_FDCWD
, path
, mode
, uid
, gid
);
1384 int run_as_mkdirat_recursive(int dirfd
, const char *path
, mode_t mode
,
1385 uid_t uid
, gid_t gid
)
1388 struct run_as_data data
= {};
1389 struct run_as_ret run_as_ret
= {};
1391 DBG3("mkdirat() recursive fd = %d%s, path = %s, mode = %d, uid = %d, gid = %d",
1392 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1393 path
, (int) mode
, (int) uid
, (int) gid
);
1394 ret
= lttng_strncpy(data
.u
.mkdir
.path
, path
,
1395 sizeof(data
.u
.mkdir
.path
));
1397 ERR("Failed to copy path argument of mkdirat recursive command");
1400 data
.u
.mkdir
.path
[sizeof(data
.u
.mkdir
.path
) - 1] = '\0';
1401 data
.u
.mkdir
.mode
= mode
;
1402 data
.u
.mkdir
.dirfd
= dirfd
;
1403 run_as(dirfd
== AT_FDCWD
? RUN_AS_MKDIR_RECURSIVE
: RUN_AS_MKDIRAT_RECURSIVE
,
1404 &data
, &run_as_ret
, uid
, gid
);
1405 errno
= run_as_ret
._errno
;
1406 ret
= run_as_ret
.u
.ret
;
1412 int run_as_mkdir(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
1414 return run_as_mkdirat(AT_FDCWD
, path
, mode
, uid
, gid
);
1418 int run_as_mkdirat(int dirfd
, const char *path
, mode_t mode
,
1419 uid_t uid
, gid_t gid
)
1422 struct run_as_data data
= {};
1423 struct run_as_ret run_as_ret
= {};
1425 DBG3("mkdirat() recursive fd = %d%s, path = %s, mode = %d, uid = %d, gid = %d",
1426 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1427 path
, (int) mode
, (int) uid
, (int) gid
);
1428 ret
= lttng_strncpy(data
.u
.mkdir
.path
, path
,
1429 sizeof(data
.u
.mkdir
.path
));
1431 ERR("Failed to copy path argument of mkdirat command");
1434 data
.u
.mkdir
.path
[sizeof(data
.u
.mkdir
.path
) - 1] = '\0';
1435 data
.u
.mkdir
.mode
= mode
;
1436 data
.u
.mkdir
.dirfd
= dirfd
;
1437 run_as(dirfd
== AT_FDCWD
? RUN_AS_MKDIR
: RUN_AS_MKDIRAT
,
1438 &data
, &run_as_ret
, uid
, gid
);
1439 errno
= run_as_ret
._errno
;
1440 ret
= run_as_ret
.u
.ret
;
1446 int run_as_open(const char *path
, int flags
, mode_t mode
, uid_t uid
,
1449 return run_as_openat(AT_FDCWD
, path
, flags
, mode
, uid
, gid
);
1453 int run_as_openat(int dirfd
, const char *path
, int flags
, 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("openat() fd = %d%s, path = %s, flags = %X, mode = %d, uid %d, gid %d",
1461 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1462 path
, flags
, (int) mode
, (int) uid
, (int) gid
);
1463 ret
= lttng_strncpy(data
.u
.open
.path
, path
, sizeof(data
.u
.open
.path
));
1465 ERR("Failed to copy path argument of open command");
1468 data
.u
.open
.flags
= flags
;
1469 data
.u
.open
.mode
= mode
;
1470 data
.u
.open
.dirfd
= dirfd
;
1471 run_as(dirfd
== AT_FDCWD
? RUN_AS_OPEN
: RUN_AS_OPENAT
,
1472 &data
, &run_as_ret
, uid
, gid
);
1473 errno
= run_as_ret
._errno
;
1474 ret
= run_as_ret
.u
.ret
< 0 ? run_as_ret
.u
.ret
:
1475 run_as_ret
.u
.open
.fd
;
1481 int run_as_unlink(const char *path
, uid_t uid
, gid_t gid
)
1483 return run_as_unlinkat(AT_FDCWD
, path
, uid
, gid
);
1487 int run_as_unlinkat(int dirfd
, const char *path
, uid_t uid
, gid_t gid
)
1490 struct run_as_data data
= {};
1491 struct run_as_ret run_as_ret
= {};
1493 DBG3("unlinkat() fd = %d%s, path = %s, uid = %d, gid = %d",
1494 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1495 path
, (int) uid
, (int) gid
);
1496 ret
= lttng_strncpy(data
.u
.unlink
.path
, path
,
1497 sizeof(data
.u
.unlink
.path
));
1501 data
.u
.unlink
.dirfd
= dirfd
;
1502 run_as(dirfd
== AT_FDCWD
? RUN_AS_UNLINK
: RUN_AS_UNLINKAT
, &data
,
1503 &run_as_ret
, uid
, gid
);
1504 errno
= run_as_ret
._errno
;
1505 ret
= run_as_ret
.u
.ret
;
1511 int run_as_rmdir(const char *path
, uid_t uid
, gid_t gid
)
1513 return run_as_rmdirat(AT_FDCWD
, path
, uid
, gid
);
1517 int run_as_rmdirat(int dirfd
, const char *path
, uid_t uid
, gid_t gid
)
1520 struct run_as_data data
= {};
1521 struct run_as_ret run_as_ret
= {};
1523 DBG3("rmdirat() fd = %d%s, path = %s, uid = %d, gid = %d",
1524 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1525 path
, (int) uid
, (int) gid
);
1526 ret
= lttng_strncpy(data
.u
.rmdir
.path
, path
,
1527 sizeof(data
.u
.rmdir
.path
));
1531 data
.u
.rmdir
.dirfd
= dirfd
;
1532 run_as(dirfd
== AT_FDCWD
? RUN_AS_RMDIR
: RUN_AS_RMDIRAT
, &data
,
1533 &run_as_ret
, uid
, gid
);
1534 errno
= run_as_ret
._errno
;
1535 ret
= run_as_ret
.u
.ret
;
1541 int run_as_rmdir_recursive(const char *path
, uid_t uid
, gid_t gid
)
1543 return run_as_rmdirat_recursive(AT_FDCWD
, path
, uid
, gid
);
1547 int run_as_rmdirat_recursive(int dirfd
, const char *path
, uid_t uid
, gid_t gid
)
1550 struct run_as_data data
= {};
1551 struct run_as_ret run_as_ret
= {};
1553 DBG3("rmdirat() recursive fd = %d%s, path = %s, uid = %d, gid = %d",
1554 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1555 path
, (int) uid
, (int) gid
);
1556 ret
= lttng_strncpy(data
.u
.rmdir
.path
, path
,
1557 sizeof(data
.u
.rmdir
.path
));
1561 data
.u
.rmdir
.dirfd
= dirfd
;
1562 run_as(dirfd
== AT_FDCWD
? RUN_AS_RMDIR_RECURSIVE
: RUN_AS_RMDIRAT_RECURSIVE
,
1563 &data
, &run_as_ret
, uid
, gid
);
1564 errno
= run_as_ret
._errno
;
1565 ret
= run_as_ret
.u
.ret
;
1571 int run_as_rename(const char *old
, const char *new, uid_t uid
, gid_t gid
)
1573 return run_as_renameat(AT_FDCWD
, old
, AT_FDCWD
, new, uid
, gid
);
1577 int run_as_renameat(int old_dirfd
, const char *old_name
,
1578 int new_dirfd
, const char *new_name
, uid_t uid
, gid_t gid
)
1581 struct run_as_data data
= {};
1582 struct run_as_ret run_as_ret
= {};
1584 DBG3("renameat() old_dirfd = %d%s, old_name = %s, new_dirfd = %d%s, new_name = %s, uid = %d, gid = %d",
1585 old_dirfd
, old_dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1587 new_dirfd
, new_dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1588 new_name
, (int) uid
, (int) gid
);
1589 ret
= lttng_strncpy(data
.u
.rename
.old_path
, old_name
,
1590 sizeof(data
.u
.rename
.old_path
));
1594 ret
= lttng_strncpy(data
.u
.rename
.new_path
, new_name
,
1595 sizeof(data
.u
.rename
.new_path
));
1600 data
.u
.rename
.dirfds
[0] = old_dirfd
;
1601 data
.u
.rename
.dirfds
[1] = new_dirfd
;
1602 run_as(old_dirfd
== AT_FDCWD
&& new_dirfd
== AT_FDCWD
?
1603 RUN_AS_RENAME
: RUN_AS_RENAMEAT
,
1604 &data
, &run_as_ret
, uid
, gid
);
1605 errno
= run_as_ret
._errno
;
1606 ret
= run_as_ret
.u
.ret
;
1612 int run_as_extract_elf_symbol_offset(int fd
, const char* function
,
1613 uid_t uid
, gid_t gid
, uint64_t *offset
)
1616 struct run_as_data data
= {};
1617 struct run_as_ret run_as_ret
= {};
1619 DBG3("extract_elf_symbol_offset() on fd=%d and function=%s "
1620 "with for uid %d and gid %d", fd
, function
,
1621 (int) uid
, (int) gid
);
1623 data
.u
.extract_elf_symbol_offset
.fd
= fd
;
1625 strncpy(data
.u
.extract_elf_symbol_offset
.function
, function
, LTTNG_SYMBOL_NAME_LEN
- 1);
1626 data
.u
.extract_elf_symbol_offset
.function
[LTTNG_SYMBOL_NAME_LEN
- 1] = '\0';
1627 ret
= lttng_strncpy(data
.u
.extract_elf_symbol_offset
.function
,
1629 sizeof(data
.u
.extract_elf_symbol_offset
.function
));
1634 run_as(RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
, &data
, &run_as_ret
, uid
, gid
);
1635 errno
= run_as_ret
._errno
;
1636 if (run_as_ret
._error
) {
1641 *offset
= run_as_ret
.u
.extract_elf_symbol_offset
.offset
;
1647 int run_as_extract_sdt_probe_offsets(int fd
, const char* provider_name
,
1648 const char* probe_name
, uid_t uid
, gid_t gid
,
1649 uint64_t **offsets
, uint32_t *num_offset
)
1652 struct run_as_data data
= {};
1653 struct run_as_ret run_as_ret
= {};
1655 DBG3("extract_sdt_probe_offsets() on fd=%d, probe_name=%s and "
1656 "provider_name=%s with for uid %d and gid %d", fd
,
1657 probe_name
, provider_name
, (int) uid
, (int) gid
);
1659 data
.u
.extract_sdt_probe_offsets
.fd
= fd
;
1661 ret
= lttng_strncpy(data
.u
.extract_sdt_probe_offsets
.probe_name
, probe_name
,
1662 sizeof(data
.u
.extract_sdt_probe_offsets
.probe_name
));
1666 ret
= lttng_strncpy(data
.u
.extract_sdt_probe_offsets
.provider_name
,
1668 sizeof(data
.u
.extract_sdt_probe_offsets
.provider_name
));
1673 run_as(RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
, &data
, &run_as_ret
, uid
, gid
);
1674 errno
= run_as_ret
._errno
;
1675 if (run_as_ret
._error
) {
1680 *num_offset
= run_as_ret
.u
.extract_sdt_probe_offsets
.num_offset
;
1681 *offsets
= zmalloc(*num_offset
* sizeof(uint64_t));
1687 memcpy(*offsets
, run_as_ret
.u
.extract_sdt_probe_offsets
.offsets
,
1688 *num_offset
* sizeof(uint64_t));
1694 int run_as_create_worker(const char *procname
,
1695 post_fork_cleanup_cb clean_up_func
,
1696 void *clean_up_user_data
)
1700 pthread_mutex_lock(&worker_lock
);
1701 ret
= run_as_create_worker_no_lock(procname
, clean_up_func
,
1702 clean_up_user_data
);
1703 pthread_mutex_unlock(&worker_lock
);
1708 void run_as_destroy_worker(void)
1710 pthread_mutex_lock(&worker_lock
);
1711 run_as_destroy_worker_no_lock();
1712 pthread_mutex_unlock(&worker_lock
);