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
];
93 int flags
; /* enum lttng_directory_handle_rmdir_recursive_flags */
96 struct run_as_extract_elf_symbol_offset_data
{
98 char function
[LTTNG_SYMBOL_NAME_LEN
];
101 struct run_as_extract_sdt_probe_offsets_data
{
103 char probe_name
[LTTNG_SYMBOL_NAME_LEN
];
104 char provider_name
[LTTNG_SYMBOL_NAME_LEN
];
107 struct run_as_rename_data
{
113 char old_path
[LTTNG_PATH_MAX
];
114 char new_path
[LTTNG_PATH_MAX
];
117 struct run_as_open_ret
{
121 struct run_as_extract_elf_symbol_offset_ret
{
125 struct run_as_extract_sdt_probe_offsets_ret
{
127 uint64_t offsets
[LTTNG_KERNEL_MAX_UPROBE_NUM
];
133 struct run_as_mkdir_data mkdir
;
134 struct run_as_open_data open
;
135 struct run_as_unlink_data unlink
;
136 struct run_as_rmdir_data rmdir
;
137 struct run_as_rename_data rename
;
138 struct run_as_extract_elf_symbol_offset_data extract_elf_symbol_offset
;
139 struct run_as_extract_sdt_probe_offsets_data extract_sdt_probe_offsets
;
146 * The run_as_ret structure holds the returned value and status of the command.
148 * The `u` union field holds the return value of the command; in most cases it
149 * represents the success or the failure of the command. In more complex
150 * commands, it holds a computed value.
152 * The _errno field is the errno recorded after the execution of the command.
154 * The _error fields is used the signify that return status of the command. For
155 * simple commands returning `int` the _error field will be the same as the
156 * ret_int field. In complex commands, it signify the success or failure of the
163 struct run_as_open_ret open
;
164 struct run_as_extract_elf_symbol_offset_ret extract_elf_symbol_offset
;
165 struct run_as_extract_sdt_probe_offsets_ret extract_sdt_probe_offsets
;
171 #define COMMAND_IN_FDS(data_ptr) ({ \
173 if (command_properties[data_ptr->cmd].in_fds_offset != -1) { \
174 fds = (int *) ((char *) data_ptr + command_properties[data_ptr->cmd].in_fds_offset); \
179 #define COMMAND_OUT_FDS(cmd, ret_ptr) ({ \
181 if (command_properties[cmd].out_fds_offset != -1) { \
182 fds = (int *) ((char *) ret_ptr + command_properties[cmd].out_fds_offset); \
187 #define COMMAND_IN_FD_COUNT(data_ptr) ({ \
188 command_properties[data_ptr->cmd].in_fd_count; \
191 #define COMMAND_OUT_FD_COUNT(cmd) ({ \
192 command_properties[cmd].out_fd_count; \
195 #define COMMAND_USE_CWD_FD(data_ptr) command_properties[data_ptr->cmd].use_cwd_fd
197 struct run_as_command_properties
{
198 /* Set to -1 when not applicable. */
199 ptrdiff_t in_fds_offset
, out_fds_offset
;
200 unsigned int in_fd_count
, out_fd_count
;
204 static const struct run_as_command_properties command_properties
[] = {
206 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
208 .out_fds_offset
= -1,
213 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
215 .out_fds_offset
= -1,
219 [RUN_AS_MKDIR_RECURSIVE
] = {
220 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
222 .out_fds_offset
= -1,
226 [RUN_AS_MKDIRAT_RECURSIVE
] = {
227 .in_fds_offset
= offsetof(struct run_as_data
, u
.mkdir
.dirfd
),
229 .out_fds_offset
= -1,
234 .in_fds_offset
= offsetof(struct run_as_data
, u
.open
.dirfd
),
236 .out_fds_offset
= offsetof(struct run_as_ret
, u
.open
.fd
),
241 .in_fds_offset
= offsetof(struct run_as_data
, u
.open
.dirfd
),
243 .out_fds_offset
= offsetof(struct run_as_ret
, u
.open
.fd
),
248 .in_fds_offset
= offsetof(struct run_as_data
, u
.unlink
.dirfd
),
250 .out_fds_offset
= -1,
254 [RUN_AS_UNLINKAT
] = {
255 .in_fds_offset
= offsetof(struct run_as_data
, u
.unlink
.dirfd
),
257 .out_fds_offset
= -1,
261 [RUN_AS_RMDIR_RECURSIVE
] = {
262 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
264 .out_fds_offset
= -1,
268 [RUN_AS_RMDIRAT_RECURSIVE
] = {
269 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
271 .out_fds_offset
= -1,
276 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
278 .out_fds_offset
= -1,
283 .in_fds_offset
= offsetof(struct run_as_data
, u
.rmdir
.dirfd
),
285 .out_fds_offset
= -1,
290 .in_fds_offset
= offsetof(struct run_as_data
, u
.rename
.dirfds
),
292 .out_fds_offset
= -1,
296 [RUN_AS_RENAMEAT
] = {
297 .in_fds_offset
= offsetof(struct run_as_data
, u
.rename
.dirfds
),
299 .out_fds_offset
= -1,
303 [RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
] = {
304 .in_fds_offset
= offsetof(struct run_as_data
,
305 u
.extract_elf_symbol_offset
.fd
),
307 .out_fds_offset
= -1,
311 [RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
] = {
312 .in_fds_offset
= offsetof(struct run_as_data
,
313 u
.extract_sdt_probe_offsets
.fd
),
315 .out_fds_offset
= -1,
321 struct run_as_worker
{
322 pid_t pid
; /* Worker PID. */
327 /* Single global worker per process (for now). */
328 static struct run_as_worker
*global_worker
;
329 /* Lock protecting the worker. */
330 static pthread_mutex_t worker_lock
= PTHREAD_MUTEX_INITIALIZER
;
342 return !lttng_secure_getenv("LTTNG_DEBUG_NOCLONE");
347 * Create recursively directory using the FULL path.
350 int _mkdirat_recursive(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
354 struct lttng_directory_handle
*handle
;
356 path
= data
->u
.mkdir
.path
;
357 mode
= data
->u
.mkdir
.mode
;
359 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.mkdir
.dirfd
);
361 ret_value
->_errno
= errno
;
362 ret_value
->_error
= true;
363 ret_value
->u
.ret
= -1;
366 /* Ownership of dirfd is transferred to the handle. */
367 data
->u
.mkdir
.dirfd
= -1;
368 /* Safe to call as we have transitioned to the requested uid/gid. */
369 ret_value
->u
.ret
= lttng_directory_handle_create_subdirectory_recursive(
371 ret_value
->_errno
= errno
;
372 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
373 lttng_directory_handle_put(handle
);
375 return ret_value
->u
.ret
;
379 int _mkdirat(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
383 struct lttng_directory_handle
*handle
;
385 path
= data
->u
.mkdir
.path
;
386 mode
= data
->u
.mkdir
.mode
;
388 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.mkdir
.dirfd
);
390 ret_value
->u
.ret
= -1;
391 ret_value
->_errno
= errno
;
392 ret_value
->_error
= true;
395 /* Ownership of dirfd is transferred to the handle. */
396 data
->u
.mkdir
.dirfd
= -1;
397 /* Safe to call as we have transitioned to the requested uid/gid. */
398 ret_value
->u
.ret
= lttng_directory_handle_create_subdirectory(
400 ret_value
->_errno
= errno
;
401 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
402 lttng_directory_handle_put(handle
);
404 return ret_value
->u
.ret
;
408 int _open(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
411 struct lttng_directory_handle
*handle
;
413 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.open
.dirfd
);
415 ret_value
->_errno
= errno
;
416 ret_value
->_error
= true;
417 ret_value
->u
.ret
= -1;
420 /* Ownership of dirfd is transferred to the handle. */
421 data
->u
.open
.dirfd
= -1;
423 fd
= lttng_directory_handle_open_file(handle
,
424 data
->u
.open
.path
, data
->u
.open
.flags
,
427 ret_value
->u
.ret
= -1;
428 ret_value
->u
.open
.fd
= -1;
430 ret_value
->u
.ret
= 0;
431 ret_value
->u
.open
.fd
= fd
;
434 ret_value
->_errno
= errno
;
435 ret_value
->_error
= fd
< 0;
436 lttng_directory_handle_put(handle
);
438 return ret_value
->u
.ret
;
442 int _unlink(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
444 struct lttng_directory_handle
*handle
;
446 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.unlink
.dirfd
);
448 ret_value
->u
.ret
= -1;
449 ret_value
->_errno
= errno
;
450 ret_value
->_error
= true;
454 /* Ownership of dirfd is transferred to the handle. */
455 data
->u
.unlink
.dirfd
= -1;
457 ret_value
->u
.ret
= lttng_directory_handle_unlink_file(handle
,
458 data
->u
.unlink
.path
);
459 ret_value
->_errno
= errno
;
460 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
461 lttng_directory_handle_put(handle
);
463 return ret_value
->u
.ret
;
467 int _rmdir(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
469 struct lttng_directory_handle
*handle
;
471 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.rmdir
.dirfd
);
473 ret_value
->u
.ret
= -1;
474 ret_value
->_errno
= errno
;
475 ret_value
->_error
= true;
479 /* Ownership of dirfd is transferred to the handle. */
480 data
->u
.rmdir
.dirfd
= -1;
482 ret_value
->u
.ret
= lttng_directory_handle_remove_subdirectory(
483 handle
, data
->u
.rmdir
.path
);
484 ret_value
->_errno
= errno
;
485 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
486 lttng_directory_handle_put(handle
);
488 return ret_value
->u
.ret
;
492 int _rmdir_recursive(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
494 struct lttng_directory_handle
*handle
;
496 handle
= lttng_directory_handle_create_from_dirfd(data
->u
.rmdir
.dirfd
);
498 ret_value
->u
.ret
= -1;
499 ret_value
->_errno
= errno
;
500 ret_value
->_error
= true;
504 /* Ownership of dirfd is transferred to the handle. */
505 data
->u
.rmdir
.dirfd
= -1;
507 ret_value
->u
.ret
= lttng_directory_handle_remove_subdirectory_recursive(
508 handle
, data
->u
.rmdir
.path
, data
->u
.rmdir
.flags
);
509 ret_value
->_errno
= errno
;
510 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
511 lttng_directory_handle_put(handle
);
513 return ret_value
->u
.ret
;
517 int _rename(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
519 const char *old_path
, *new_path
;
520 struct lttng_directory_handle
*old_handle
= NULL
, *new_handle
= NULL
;
522 old_path
= data
->u
.rename
.old_path
;
523 new_path
= data
->u
.rename
.new_path
;
525 old_handle
= lttng_directory_handle_create_from_dirfd(
526 data
->u
.rename
.dirfds
[0]);
528 ret_value
->u
.ret
= -1;
531 new_handle
= lttng_directory_handle_create_from_dirfd(
532 data
->u
.rename
.dirfds
[1]);
534 ret_value
->u
.ret
= -1;
538 /* Ownership of dirfds are transferred to the handles. */
539 data
->u
.rename
.dirfds
[0] = data
->u
.rename
.dirfds
[1] = -1;
541 /* Safe to call as we have transitioned to the requested uid/gid. */
542 ret_value
->u
.ret
= lttng_directory_handle_rename(
543 old_handle
, old_path
, new_handle
, new_path
);
545 lttng_directory_handle_put(old_handle
);
546 lttng_directory_handle_put(new_handle
);
547 ret_value
->_errno
= errno
;
548 ret_value
->_error
= (ret_value
->u
.ret
) ? true : false;
549 return ret_value
->u
.ret
;
554 int _extract_elf_symbol_offset(struct run_as_data
*data
,
555 struct run_as_ret
*ret_value
)
560 ret_value
->_error
= false;
561 ret
= lttng_elf_get_symbol_offset(data
->u
.extract_elf_symbol_offset
.fd
,
562 data
->u
.extract_elf_symbol_offset
.function
,
565 DBG("Failed to extract ELF function offset");
566 ret_value
->_error
= true;
568 ret_value
->u
.extract_elf_symbol_offset
.offset
= offset
;
574 int _extract_sdt_probe_offsets(struct run_as_data
*data
,
575 struct run_as_ret
*ret_value
)
578 uint64_t *offsets
= NULL
;
581 ret_value
->_error
= false;
583 /* On success, this call allocates the offsets paramater. */
584 ret
= lttng_elf_get_sdt_probe_offsets(
585 data
->u
.extract_sdt_probe_offsets
.fd
,
586 data
->u
.extract_sdt_probe_offsets
.provider_name
,
587 data
->u
.extract_sdt_probe_offsets
.probe_name
,
588 &offsets
, &num_offset
);
591 DBG("Failed to extract SDT probe offsets");
592 ret_value
->_error
= true;
596 if (num_offset
<= 0 || num_offset
> LTTNG_KERNEL_MAX_UPROBE_NUM
) {
597 DBG("Wrong number of probes.");
599 ret_value
->_error
= true;
603 /* Copy the content of the offsets array to the ret struct. */
604 memcpy(ret_value
->u
.extract_sdt_probe_offsets
.offsets
,
605 offsets
, num_offset
* sizeof(uint64_t));
607 ret_value
->u
.extract_sdt_probe_offsets
.num_offset
= num_offset
;
616 int _extract_elf_symbol_offset(struct run_as_data
*data
,
617 struct run_as_ret
*ret_value
)
619 ERR("Unimplemented runas command RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET");
624 int _extract_sdt_probe_offsets(struct run_as_data
*data
,
625 struct run_as_ret
*ret_value
)
627 ERR("Unimplemented runas command RUN_AS_EXTRACT_SDT_PROBE_OFFSETS");
633 run_as_fct
run_as_enum_to_fct(enum run_as_cmd cmd
)
639 case RUN_AS_MKDIR_RECURSIVE
:
640 case RUN_AS_MKDIRAT_RECURSIVE
:
641 return _mkdirat_recursive
;
646 case RUN_AS_UNLINKAT
:
651 case RUN_AS_RMDIR_RECURSIVE
:
652 case RUN_AS_RMDIRAT_RECURSIVE
:
653 return _rmdir_recursive
;
655 case RUN_AS_RENAMEAT
:
657 case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
:
658 return _extract_elf_symbol_offset
;
659 case RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
:
660 return _extract_sdt_probe_offsets
;
662 ERR("Unknown command %d", (int) cmd
);
668 int do_send_fds(int sock
, const int *fds
, unsigned int fd_count
)
673 for (i
= 0; i
< fd_count
; i
++) {
675 ERR("Attempt to send invalid file descriptor to master (fd = %i)",
677 /* Return 0 as this is not a fatal error. */
682 len
= lttcomm_send_fds_unix_sock(sock
, fds
, fd_count
);
683 return len
< 0 ? -1 : 0;
687 int do_recv_fds(int sock
, int *fds
, unsigned int fd_count
)
693 len
= lttcomm_recv_fds_unix_sock(sock
, fds
, fd_count
);
697 } else if (len
< 0) {
698 PERROR("Failed to receive file descriptors from socket");
703 for (i
= 0; i
< fd_count
; i
++) {
705 ERR("Invalid file descriptor received from worker (fd = %i)", fds
[i
]);
706 /* Return 0 as this is not a fatal error. */
714 int send_fds_to_worker(const struct run_as_worker
*worker
,
715 const struct run_as_data
*data
)
720 if (COMMAND_USE_CWD_FD(data
) || COMMAND_IN_FD_COUNT(data
) == 0) {
724 for (i
= 0; i
< COMMAND_IN_FD_COUNT(data
); i
++) {
725 if (COMMAND_IN_FDS(data
)[i
] < 0) {
726 ERR("Refusing to send invalid fd to worker (fd = %i)",
727 COMMAND_IN_FDS(data
)[i
]);
733 ret
= do_send_fds(worker
->sockpair
[0], COMMAND_IN_FDS(data
),
734 COMMAND_IN_FD_COUNT(data
));
736 PERROR("Failed to send file descriptor to run-as worker");
745 int send_fds_to_master(struct run_as_worker
*worker
, enum run_as_cmd cmd
,
746 struct run_as_ret
*run_as_ret
)
751 if (COMMAND_OUT_FD_COUNT(cmd
) == 0) {
755 ret
= do_send_fds(worker
->sockpair
[1], COMMAND_OUT_FDS(cmd
, run_as_ret
),
756 COMMAND_OUT_FD_COUNT(cmd
));
758 PERROR("Failed to send file descriptor to master process");
762 for (i
= 0; i
< COMMAND_OUT_FD_COUNT(cmd
); i
++) {
763 int ret_close
= close(COMMAND_OUT_FDS(cmd
, run_as_ret
)[i
]);
766 PERROR("Failed to close result file descriptor");
774 int recv_fds_from_worker(const struct run_as_worker
*worker
, enum run_as_cmd cmd
,
775 struct run_as_ret
*run_as_ret
)
779 if (COMMAND_OUT_FD_COUNT(cmd
) == 0) {
783 ret
= do_recv_fds(worker
->sockpair
[0], COMMAND_OUT_FDS(cmd
, run_as_ret
),
784 COMMAND_OUT_FD_COUNT(cmd
));
786 PERROR("Failed to receive file descriptor from run-as worker");
794 int recv_fds_from_master(struct run_as_worker
*worker
, struct run_as_data
*data
)
798 if (COMMAND_USE_CWD_FD(data
)) {
801 for (i
= 0; i
< COMMAND_IN_FD_COUNT(data
); i
++) {
802 COMMAND_IN_FDS(data
)[i
] = AT_FDCWD
;
807 ret
= do_recv_fds(worker
->sockpair
[1], COMMAND_IN_FDS(data
),
808 COMMAND_IN_FD_COUNT(data
));
810 PERROR("Failed to receive file descriptors from master process");
818 int cleanup_received_fds(struct run_as_data
*data
)
822 for (i
= 0; i
< COMMAND_IN_FD_COUNT(data
); i
++) {
823 if (COMMAND_IN_FDS(data
)[i
] == -1) {
826 ret
= close(COMMAND_IN_FDS(data
)[i
]);
828 PERROR("Failed to close file descriptor received fd in run-as worker");
837 * Return < 0 on error, 0 if OK, 1 on hangup.
840 int handle_one_cmd(struct run_as_worker
*worker
)
843 struct run_as_data data
= {};
844 ssize_t readlen
, writelen
;
845 struct run_as_ret sendret
= {};
850 * Stage 1: Receive run_as_data struct from the master.
851 * The structure contains the command type and all the parameters needed for
854 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[1], &data
,
861 if (readlen
< sizeof(data
)) {
862 PERROR("lttcomm_recv_unix_sock error");
867 cmd
= run_as_enum_to_fct(data
.cmd
);
874 * Stage 2: Receive file descriptor from master.
875 * Some commands need a file descriptor as input so if it's needed we
876 * receive the fd using the Unix socket.
878 ret
= recv_fds_from_master(worker
, &data
);
880 PERROR("recv_fd_from_master error");
885 prev_euid
= getuid();
886 if (data
.gid
!= getegid()) {
887 ret
= setegid(data
.gid
);
889 sendret
._error
= true;
890 sendret
._errno
= errno
;
895 if (data
.uid
!= prev_euid
) {
896 ret
= seteuid(data
.uid
);
898 sendret
._error
= true;
899 sendret
._errno
= errno
;
906 * Also set umask to 0 for mkdir executable bit.
911 * Stage 3: Execute the command
913 ret
= (*cmd
)(&data
, &sendret
);
915 DBG("Execution of command returned an error");
919 ret
= cleanup_received_fds(&data
);
921 ERR("Error cleaning up FD");
926 * Stage 4: Send run_as_ret structure to the master.
927 * This structure contain the return value of the command and the errno.
929 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[1], &sendret
,
931 if (writelen
< sizeof(sendret
)) {
932 PERROR("lttcomm_send_unix_sock error");
938 * Stage 5: Send resulting file descriptors to the master.
940 ret
= send_fds_to_master(worker
, data
.cmd
, &sendret
);
942 DBG("Sending FD to master returned an error");
946 if (seteuid(prev_euid
) < 0) {
957 int run_as_worker(struct run_as_worker
*worker
)
961 struct run_as_ret sendret
;
962 size_t proc_orig_len
;
965 * Initialize worker. Set a different process cmdline.
967 proc_orig_len
= strlen(worker
->procname
);
968 memset(worker
->procname
, 0, proc_orig_len
);
969 strncpy(worker
->procname
, DEFAULT_RUN_AS_WORKER_NAME
, proc_orig_len
);
971 ret
= lttng_prctl(PR_SET_NAME
,
972 (unsigned long) DEFAULT_RUN_AS_WORKER_NAME
, 0, 0, 0);
973 if (ret
&& ret
!= -ENOSYS
) {
974 /* Don't fail as this is not essential. */
975 PERROR("prctl PR_SET_NAME");
978 memset(&sendret
, 0, sizeof(sendret
));
980 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[1], &sendret
,
982 if (writelen
< sizeof(sendret
)) {
983 PERROR("lttcomm_send_unix_sock error");
989 ret
= handle_one_cmd(worker
);
993 } else if (ret
> 0) {
996 continue; /* Next command. */
1005 int run_as_cmd(struct run_as_worker
*worker
,
1006 enum run_as_cmd cmd
,
1007 struct run_as_data
*data
,
1008 struct run_as_ret
*ret_value
,
1009 uid_t uid
, gid_t gid
)
1012 ssize_t readlen
, writelen
;
1015 * If we are non-root, we can only deal with our own uid.
1017 if (geteuid() != 0) {
1018 if (uid
!= geteuid()) {
1020 ret_value
->_errno
= EPERM
;
1021 ERR("Client (%d)/Server (%d) UID mismatch (and sessiond is not root)",
1022 (int) uid
, (int) geteuid());
1032 * Stage 1: Send the run_as_data struct to the worker process
1034 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[0], data
,
1036 if (writelen
< sizeof(*data
)) {
1037 PERROR("Error writing message to run_as");
1039 ret_value
->_errno
= EIO
;
1044 * Stage 2: Send file descriptor to the worker process if needed
1046 ret
= send_fds_to_worker(worker
, data
);
1048 PERROR("do_send_fd error");
1050 ret_value
->_errno
= EIO
;
1055 * Stage 3: Wait for the execution of the command
1059 * Stage 4: Receive the run_as_ret struct containing the return value and
1062 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[0], ret_value
,
1063 sizeof(*ret_value
));
1065 ERR("Run-as worker has hung-up during run_as_cmd");
1067 ret_value
->_errno
= EIO
;
1069 } else if (readlen
< sizeof(*ret_value
)) {
1070 PERROR("Error reading response from run_as");
1072 ret_value
->_errno
= errno
;
1076 if (ret_value
->_error
) {
1077 /* Skip stage 5 on error as there will be no fd to receive. */
1082 * Stage 5: Receive file descriptor if needed
1084 ret
= recv_fds_from_worker(worker
, cmd
, ret_value
);
1086 ERR("Error receiving fd");
1088 ret_value
->_errno
= EIO
;
1096 * This is for debugging ONLY and should not be considered secure.
1099 int run_as_noworker(enum run_as_cmd cmd
,
1100 struct run_as_data
*data
, struct run_as_ret
*ret_value
,
1101 uid_t uid
, gid_t gid
)
1103 int ret
, saved_errno
;
1107 fct
= run_as_enum_to_fct(cmd
);
1113 old_mask
= umask(0);
1114 ret
= fct(data
, ret_value
);
1115 saved_errno
= ret_value
->_errno
;
1117 errno
= saved_errno
;
1123 int reset_sighandler(void)
1127 DBG("Resetting run_as worker signal handlers to default");
1128 for (sig
= 1; sig
<= 31; sig
++) {
1129 (void) signal(sig
, SIG_DFL
);
1135 void worker_sighandler(int sig
)
1137 const char *signame
;
1140 * The worker will inherit its parent's signals since they are part of
1141 * the same process group. However, in the case of SIGINT and SIGTERM,
1142 * we want to give the worker a chance to teardown gracefully when its
1143 * parent closes the command socket.
1150 signame
= "SIGTERM";
1157 DBG("run_as worker received signal %s", signame
);
1159 DBG("run_as_worker received signal %d", sig
);
1164 int set_worker_sighandlers(void)
1168 struct sigaction sa
;
1170 if ((ret
= sigemptyset(&sigset
)) < 0) {
1171 PERROR("sigemptyset");
1175 sa
.sa_handler
= worker_sighandler
;
1176 sa
.sa_mask
= sigset
;
1178 if ((ret
= sigaction(SIGINT
, &sa
, NULL
)) < 0) {
1179 PERROR("sigaction SIGINT");
1183 if ((ret
= sigaction(SIGTERM
, &sa
, NULL
)) < 0) {
1184 PERROR("sigaction SIGTERM");
1188 DBG("run_as signal handler set for SIGTERM and SIGINT");
1194 int run_as_create_worker_no_lock(const char *procname
,
1195 post_fork_cleanup_cb clean_up_func
,
1196 void *clean_up_user_data
)
1201 struct run_as_ret recvret
;
1202 struct run_as_worker
*worker
;
1204 assert(!global_worker
);
1207 * Don't initialize a worker, all run_as tasks will be performed
1208 * in the current process.
1213 worker
= zmalloc(sizeof(*worker
));
1218 worker
->procname
= strdup(procname
);
1219 if (!worker
->procname
) {
1221 goto error_procname_alloc
;
1223 /* Create unix socket. */
1224 if (lttcomm_create_anon_unix_socketpair(worker
->sockpair
) < 0) {
1235 } else if (pid
== 0) {
1240 set_worker_sighandlers();
1241 if (clean_up_func
) {
1242 if (clean_up_func(clean_up_user_data
) < 0) {
1243 ERR("Run-as post-fork clean-up failed, exiting.");
1248 /* Just close, no shutdown. */
1249 if (close(worker
->sockpair
[0])) {
1255 * Close all FDs aside from STDIN, STDOUT, STDERR and sockpair[1]
1256 * Sockpair[1] is used as a control channel with the master
1258 for (i
= 3; i
< sysconf(_SC_OPEN_MAX
); i
++) {
1259 if (i
!= worker
->sockpair
[1]) {
1264 worker
->sockpair
[0] = -1;
1265 ret
= run_as_worker(worker
);
1266 if (lttcomm_close_unix_sock(worker
->sockpair
[1])) {
1270 worker
->sockpair
[1] = -1;
1271 free(worker
->procname
);
1273 LOG(ret
? PRINT_ERR
: PRINT_DBG
, "run_as worker exiting (ret = %d)", ret
);
1274 exit(ret
? EXIT_FAILURE
: EXIT_SUCCESS
);
1278 /* Just close, no shutdown. */
1279 if (close(worker
->sockpair
[1])) {
1284 worker
->sockpair
[1] = -1;
1286 /* Wait for worker to become ready. */
1287 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[0],
1288 &recvret
, sizeof(recvret
));
1289 if (readlen
< sizeof(recvret
)) {
1290 ERR("readlen: %zd", readlen
);
1291 PERROR("Error reading response from run_as at creation");
1295 global_worker
= worker
;
1300 /* Error handling. */
1302 for (i
= 0; i
< 2; i
++) {
1303 if (worker
->sockpair
[i
] < 0) {
1306 if (lttcomm_close_unix_sock(worker
->sockpair
[i
])) {
1309 worker
->sockpair
[i
] = -1;
1312 free(worker
->procname
);
1313 error_procname_alloc
:
1319 void run_as_destroy_worker_no_lock(void)
1321 struct run_as_worker
*worker
= global_worker
;
1323 DBG("Destroying run_as worker");
1327 /* Close unix socket */
1328 DBG("Closing run_as worker socket");
1329 if (lttcomm_close_unix_sock(worker
->sockpair
[0])) {
1332 worker
->sockpair
[0] = -1;
1333 /* Wait for worker. */
1338 wait_ret
= waitpid(worker
->pid
, &status
, 0);
1340 if (errno
== EINTR
) {
1347 if (WIFEXITED(status
)) {
1348 LOG(WEXITSTATUS(status
) == 0 ? PRINT_DBG
: PRINT_ERR
,
1349 DEFAULT_RUN_AS_WORKER_NAME
" terminated with status code %d",
1350 WEXITSTATUS(status
));
1352 } else if (WIFSIGNALED(status
)) {
1353 ERR(DEFAULT_RUN_AS_WORKER_NAME
" was killed by signal %d",
1358 free(worker
->procname
);
1360 global_worker
= NULL
;
1364 int run_as_restart_worker(struct run_as_worker
*worker
)
1367 char *procname
= NULL
;
1369 procname
= worker
->procname
;
1371 /* Close socket to run_as worker process and clean up the zombie process */
1372 run_as_destroy_worker_no_lock();
1374 /* Create a new run_as worker process*/
1375 ret
= run_as_create_worker_no_lock(procname
, NULL
, NULL
);
1377 ERR("Restarting the worker process failed");
1386 int run_as(enum run_as_cmd cmd
, struct run_as_data
*data
,
1387 struct run_as_ret
*ret_value
, uid_t uid
, gid_t gid
)
1389 int ret
, saved_errno
;
1391 pthread_mutex_lock(&worker_lock
);
1393 DBG("Using run_as worker");
1395 assert(global_worker
);
1397 ret
= run_as_cmd(global_worker
, cmd
, data
, ret_value
, uid
, gid
);
1398 saved_errno
= ret_value
->_errno
;
1401 * If the worker thread crashed the errno is set to EIO. we log
1402 * the error and start a new worker process.
1404 if (ret
== -1 && saved_errno
== EIO
) {
1405 DBG("Socket closed unexpectedly... "
1406 "Restarting the worker process");
1407 ret
= run_as_restart_worker(global_worker
);
1409 ERR("Failed to restart worker process.");
1414 DBG("Using run_as without worker");
1415 ret
= run_as_noworker(cmd
, data
, ret_value
, uid
, gid
);
1418 pthread_mutex_unlock(&worker_lock
);
1423 int run_as_mkdir_recursive(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
1425 return run_as_mkdirat_recursive(AT_FDCWD
, path
, mode
, uid
, gid
);
1429 int run_as_mkdirat_recursive(int dirfd
, const char *path
, mode_t mode
,
1430 uid_t uid
, gid_t gid
)
1433 struct run_as_data data
= {};
1434 struct run_as_ret run_as_ret
= {};
1436 DBG3("mkdirat() recursive fd = %d%s, path = %s, mode = %d, uid = %d, gid = %d",
1437 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1438 path
, (int) mode
, (int) uid
, (int) gid
);
1439 ret
= lttng_strncpy(data
.u
.mkdir
.path
, path
,
1440 sizeof(data
.u
.mkdir
.path
));
1442 ERR("Failed to copy path argument of mkdirat recursive command");
1445 data
.u
.mkdir
.path
[sizeof(data
.u
.mkdir
.path
) - 1] = '\0';
1446 data
.u
.mkdir
.mode
= mode
;
1447 data
.u
.mkdir
.dirfd
= dirfd
;
1448 run_as(dirfd
== AT_FDCWD
? RUN_AS_MKDIR_RECURSIVE
: RUN_AS_MKDIRAT_RECURSIVE
,
1449 &data
, &run_as_ret
, uid
, gid
);
1450 errno
= run_as_ret
._errno
;
1451 ret
= run_as_ret
.u
.ret
;
1457 int run_as_mkdir(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
1459 return run_as_mkdirat(AT_FDCWD
, path
, mode
, uid
, gid
);
1463 int run_as_mkdirat(int dirfd
, const char *path
, mode_t mode
,
1464 uid_t uid
, gid_t gid
)
1467 struct run_as_data data
= {};
1468 struct run_as_ret run_as_ret
= {};
1470 DBG3("mkdirat() recursive fd = %d%s, path = %s, mode = %d, uid = %d, gid = %d",
1471 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1472 path
, (int) mode
, (int) uid
, (int) gid
);
1473 ret
= lttng_strncpy(data
.u
.mkdir
.path
, path
,
1474 sizeof(data
.u
.mkdir
.path
));
1476 ERR("Failed to copy path argument of mkdirat command");
1479 data
.u
.mkdir
.path
[sizeof(data
.u
.mkdir
.path
) - 1] = '\0';
1480 data
.u
.mkdir
.mode
= mode
;
1481 data
.u
.mkdir
.dirfd
= dirfd
;
1482 run_as(dirfd
== AT_FDCWD
? RUN_AS_MKDIR
: RUN_AS_MKDIRAT
,
1483 &data
, &run_as_ret
, uid
, gid
);
1484 errno
= run_as_ret
._errno
;
1485 ret
= run_as_ret
.u
.ret
;
1491 int run_as_open(const char *path
, int flags
, mode_t mode
, uid_t uid
,
1494 return run_as_openat(AT_FDCWD
, path
, flags
, mode
, uid
, gid
);
1498 int run_as_openat(int dirfd
, const char *path
, int flags
, mode_t mode
,
1499 uid_t uid
, gid_t gid
)
1502 struct run_as_data data
= {};
1503 struct run_as_ret run_as_ret
= {};
1505 DBG3("openat() fd = %d%s, path = %s, flags = %X, mode = %d, uid %d, gid %d",
1506 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1507 path
, flags
, (int) mode
, (int) uid
, (int) gid
);
1508 ret
= lttng_strncpy(data
.u
.open
.path
, path
, sizeof(data
.u
.open
.path
));
1510 ERR("Failed to copy path argument of open command");
1513 data
.u
.open
.flags
= flags
;
1514 data
.u
.open
.mode
= mode
;
1515 data
.u
.open
.dirfd
= dirfd
;
1516 run_as(dirfd
== AT_FDCWD
? RUN_AS_OPEN
: RUN_AS_OPENAT
,
1517 &data
, &run_as_ret
, uid
, gid
);
1518 errno
= run_as_ret
._errno
;
1519 ret
= run_as_ret
.u
.ret
< 0 ? run_as_ret
.u
.ret
:
1520 run_as_ret
.u
.open
.fd
;
1526 int run_as_unlink(const char *path
, uid_t uid
, gid_t gid
)
1528 return run_as_unlinkat(AT_FDCWD
, path
, uid
, gid
);
1532 int run_as_unlinkat(int dirfd
, const char *path
, uid_t uid
, gid_t gid
)
1535 struct run_as_data data
= {};
1536 struct run_as_ret run_as_ret
= {};
1538 DBG3("unlinkat() fd = %d%s, path = %s, uid = %d, gid = %d",
1539 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1540 path
, (int) uid
, (int) gid
);
1541 ret
= lttng_strncpy(data
.u
.unlink
.path
, path
,
1542 sizeof(data
.u
.unlink
.path
));
1546 data
.u
.unlink
.dirfd
= dirfd
;
1547 run_as(dirfd
== AT_FDCWD
? RUN_AS_UNLINK
: RUN_AS_UNLINKAT
, &data
,
1548 &run_as_ret
, uid
, gid
);
1549 errno
= run_as_ret
._errno
;
1550 ret
= run_as_ret
.u
.ret
;
1556 int run_as_rmdir(const char *path
, uid_t uid
, gid_t gid
)
1558 return run_as_rmdirat(AT_FDCWD
, path
, uid
, gid
);
1562 int run_as_rmdirat(int dirfd
, const char *path
, uid_t uid
, gid_t gid
)
1565 struct run_as_data data
= {};
1566 struct run_as_ret run_as_ret
= {};
1568 DBG3("rmdirat() fd = %d%s, path = %s, uid = %d, gid = %d",
1569 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1570 path
, (int) uid
, (int) gid
);
1571 ret
= lttng_strncpy(data
.u
.rmdir
.path
, path
,
1572 sizeof(data
.u
.rmdir
.path
));
1576 data
.u
.rmdir
.dirfd
= dirfd
;
1577 run_as(dirfd
== AT_FDCWD
? RUN_AS_RMDIR
: RUN_AS_RMDIRAT
, &data
,
1578 &run_as_ret
, uid
, gid
);
1579 errno
= run_as_ret
._errno
;
1580 ret
= run_as_ret
.u
.ret
;
1586 int run_as_rmdir_recursive(const char *path
, uid_t uid
, gid_t gid
, int flags
)
1588 return run_as_rmdirat_recursive(AT_FDCWD
, path
, uid
, gid
, flags
);
1592 int run_as_rmdirat_recursive(int dirfd
, const char *path
, uid_t uid
, gid_t gid
, int flags
)
1595 struct run_as_data data
= {};
1596 struct run_as_ret run_as_ret
= {};
1598 DBG3("rmdirat() recursive fd = %d%s, path = %s, uid = %d, gid = %d",
1599 dirfd
, dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1600 path
, (int) uid
, (int) gid
);
1601 ret
= lttng_strncpy(data
.u
.rmdir
.path
, path
,
1602 sizeof(data
.u
.rmdir
.path
));
1606 data
.u
.rmdir
.dirfd
= dirfd
;
1607 data
.u
.rmdir
.flags
= flags
;
1608 run_as(dirfd
== AT_FDCWD
? RUN_AS_RMDIR_RECURSIVE
: RUN_AS_RMDIRAT_RECURSIVE
,
1609 &data
, &run_as_ret
, uid
, gid
);
1610 errno
= run_as_ret
._errno
;
1611 ret
= run_as_ret
.u
.ret
;
1617 int run_as_rename(const char *old
, const char *new, uid_t uid
, gid_t gid
)
1619 return run_as_renameat(AT_FDCWD
, old
, AT_FDCWD
, new, uid
, gid
);
1623 int run_as_renameat(int old_dirfd
, const char *old_name
,
1624 int new_dirfd
, const char *new_name
, uid_t uid
, gid_t gid
)
1627 struct run_as_data data
= {};
1628 struct run_as_ret run_as_ret
= {};
1630 DBG3("renameat() old_dirfd = %d%s, old_name = %s, new_dirfd = %d%s, new_name = %s, uid = %d, gid = %d",
1631 old_dirfd
, old_dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1633 new_dirfd
, new_dirfd
== AT_FDCWD
? " (AT_FDCWD)" : "",
1634 new_name
, (int) uid
, (int) gid
);
1635 ret
= lttng_strncpy(data
.u
.rename
.old_path
, old_name
,
1636 sizeof(data
.u
.rename
.old_path
));
1640 ret
= lttng_strncpy(data
.u
.rename
.new_path
, new_name
,
1641 sizeof(data
.u
.rename
.new_path
));
1646 data
.u
.rename
.dirfds
[0] = old_dirfd
;
1647 data
.u
.rename
.dirfds
[1] = new_dirfd
;
1648 run_as(old_dirfd
== AT_FDCWD
&& new_dirfd
== AT_FDCWD
?
1649 RUN_AS_RENAME
: RUN_AS_RENAMEAT
,
1650 &data
, &run_as_ret
, uid
, gid
);
1651 errno
= run_as_ret
._errno
;
1652 ret
= run_as_ret
.u
.ret
;
1658 int run_as_extract_elf_symbol_offset(int fd
, const char* function
,
1659 uid_t uid
, gid_t gid
, uint64_t *offset
)
1662 struct run_as_data data
= {};
1663 struct run_as_ret run_as_ret
= {};
1665 DBG3("extract_elf_symbol_offset() on fd=%d and function=%s "
1666 "with for uid %d and gid %d", fd
, function
,
1667 (int) uid
, (int) gid
);
1669 data
.u
.extract_elf_symbol_offset
.fd
= fd
;
1671 strncpy(data
.u
.extract_elf_symbol_offset
.function
, function
, LTTNG_SYMBOL_NAME_LEN
- 1);
1672 data
.u
.extract_elf_symbol_offset
.function
[LTTNG_SYMBOL_NAME_LEN
- 1] = '\0';
1673 ret
= lttng_strncpy(data
.u
.extract_elf_symbol_offset
.function
,
1675 sizeof(data
.u
.extract_elf_symbol_offset
.function
));
1680 run_as(RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
, &data
, &run_as_ret
, uid
, gid
);
1681 errno
= run_as_ret
._errno
;
1682 if (run_as_ret
._error
) {
1687 *offset
= run_as_ret
.u
.extract_elf_symbol_offset
.offset
;
1693 int run_as_extract_sdt_probe_offsets(int fd
, const char* provider_name
,
1694 const char* probe_name
, uid_t uid
, gid_t gid
,
1695 uint64_t **offsets
, uint32_t *num_offset
)
1698 struct run_as_data data
= {};
1699 struct run_as_ret run_as_ret
= {};
1701 DBG3("extract_sdt_probe_offsets() on fd=%d, probe_name=%s and "
1702 "provider_name=%s with for uid %d and gid %d", fd
,
1703 probe_name
, provider_name
, (int) uid
, (int) gid
);
1705 data
.u
.extract_sdt_probe_offsets
.fd
= fd
;
1707 ret
= lttng_strncpy(data
.u
.extract_sdt_probe_offsets
.probe_name
, probe_name
,
1708 sizeof(data
.u
.extract_sdt_probe_offsets
.probe_name
));
1712 ret
= lttng_strncpy(data
.u
.extract_sdt_probe_offsets
.provider_name
,
1714 sizeof(data
.u
.extract_sdt_probe_offsets
.provider_name
));
1719 run_as(RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
, &data
, &run_as_ret
, uid
, gid
);
1720 errno
= run_as_ret
._errno
;
1721 if (run_as_ret
._error
) {
1726 *num_offset
= run_as_ret
.u
.extract_sdt_probe_offsets
.num_offset
;
1727 *offsets
= zmalloc(*num_offset
* sizeof(uint64_t));
1733 memcpy(*offsets
, run_as_ret
.u
.extract_sdt_probe_offsets
.offsets
,
1734 *num_offset
* sizeof(uint64_t));
1740 int run_as_create_worker(const char *procname
,
1741 post_fork_cleanup_cb clean_up_func
,
1742 void *clean_up_user_data
)
1746 pthread_mutex_lock(&worker_lock
);
1747 ret
= run_as_create_worker_no_lock(procname
, clean_up_func
,
1748 clean_up_user_data
);
1749 pthread_mutex_unlock(&worker_lock
);
1754 void run_as_destroy_worker(void)
1756 pthread_mutex_lock(&worker_lock
);
1757 run_as_destroy_worker_no_lock();
1758 pthread_mutex_unlock(&worker_lock
);