Add rmdirat and renameat to run-as commands
[lttng-tools.git] / src / common / runas.c
CommitLineData
60b6c79c
MD
1/*
2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 * Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
93bed9fe 4 * 2019 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
60b6c79c 5 *
d14d33bf
AM
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.
60b6c79c
MD
9 *
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
d14d33bf 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
60b6c79c
MD
13 * more details.
14 *
d14d33bf
AM
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.
60b6c79c
MD
18 */
19
6c1c0768 20#define _LGPL_SOURCE
60b6c79c
MD
21#include <errno.h>
22#include <limits.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <sys/wait.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <unistd.h>
30#include <fcntl.h>
c2b75c49 31#include <sched.h>
0452bf08 32#include <signal.h>
749b7a0c 33#include <assert.h>
e1055edb 34#include <signal.h>
60b6c79c 35
0ef03255 36#include <common/lttng-kernel.h>
90e535ef 37#include <common/common.h>
3fd15a74 38#include <common/utils.h>
e8fa9fb0 39#include <common/compat/getenv.h>
e1055edb 40#include <common/compat/prctl.h>
2038dd6c
JG
41#include <common/unix.h>
42#include <common/defaults.h>
241e0a5a
FD
43#include <common/lttng-elf.h>
44
45#include <lttng/constant.h>
60b6c79c 46
0857097f
DG
47#include "runas.h"
48
7567352f 49struct run_as_data;
fe9f7760
FD
50struct run_as_ret;
51typedef int (*run_as_fct)(struct run_as_data *data, struct run_as_ret *ret_value);
c2b75c49 52
93bed9fe
JG
53enum run_as_cmd {
54 RUN_AS_MKDIR,
55 RUN_AS_MKDIRAT,
56 RUN_AS_MKDIR_RECURSIVE,
57 RUN_AS_MKDIRAT_RECURSIVE,
58 RUN_AS_OPEN,
59 RUN_AS_OPENAT,
60 RUN_AS_UNLINK,
61 RUN_AS_UNLINKAT,
62 RUN_AS_RMDIR,
63 RUN_AS_RMDIRAT,
64 RUN_AS_RMDIR_RECURSIVE,
65 RUN_AS_RMDIRAT_RECURSIVE,
66 RUN_AS_RENAME,
67 RUN_AS_RENAMEAT,
68 RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET,
69 RUN_AS_EXTRACT_SDT_PROBE_OFFSETS,
60b6c79c
MD
70};
71
93bed9fe
JG
72struct run_as_mkdir_data {
73 int dirfd;
74 char path[LTTNG_PATH_MAX];
75 mode_t mode;
76} LTTNG_PACKED;
77
e11d277b 78struct run_as_open_data {
93bed9fe
JG
79 int dirfd;
80 char path[LTTNG_PATH_MAX];
60b6c79c
MD
81 int flags;
82 mode_t mode;
93bed9fe 83} LTTNG_PACKED;
60b6c79c 84
4628484a 85struct run_as_unlink_data {
93bed9fe
JG
86 int dirfd;
87 char path[LTTNG_PATH_MAX];
88} LTTNG_PACKED;
4628484a 89
93bed9fe
JG
90struct run_as_rmdir_data {
91 int dirfd;
92 char path[LTTNG_PATH_MAX];
93} LTTNG_PACKED;
7567352f 94
241e0a5a 95struct run_as_extract_elf_symbol_offset_data {
93bed9fe 96 int fd;
241e0a5a 97 char function[LTTNG_SYMBOL_NAME_LEN];
93bed9fe 98} LTTNG_PACKED;
241e0a5a 99
0ef03255 100struct run_as_extract_sdt_probe_offsets_data {
93bed9fe 101 int fd;
0ef03255
FD
102 char probe_name[LTTNG_SYMBOL_NAME_LEN];
103 char provider_name[LTTNG_SYMBOL_NAME_LEN];
93bed9fe 104} LTTNG_PACKED;
0ef03255 105
93bed9fe
JG
106struct run_as_rename_data {
107 /*
108 * [0] = old_dirfd
109 * [1] = new_dirfd
110 */
111 int dirfds[2];
112 char old_path[LTTNG_PATH_MAX];
113 char new_path[LTTNG_PATH_MAX];
114} LTTNG_PACKED;
fe9f7760
FD
115
116struct run_as_open_ret {
93bed9fe
JG
117 int fd;
118} LTTNG_PACKED;
fe9f7760 119
241e0a5a
FD
120struct run_as_extract_elf_symbol_offset_ret {
121 uint64_t offset;
93bed9fe 122} LTTNG_PACKED;
241e0a5a 123
0ef03255
FD
124struct run_as_extract_sdt_probe_offsets_ret {
125 uint32_t num_offset;
126 uint64_t offsets[LTTNG_KERNEL_MAX_UPROBE_NUM];
93bed9fe 127} LTTNG_PACKED;
7567352f
MD
128
129struct run_as_data {
130 enum run_as_cmd cmd;
131 union {
93bed9fe 132 struct run_as_mkdir_data mkdir;
7567352f
MD
133 struct run_as_open_data open;
134 struct run_as_unlink_data unlink;
93bed9fe
JG
135 struct run_as_rmdir_data rmdir;
136 struct run_as_rename_data rename;
241e0a5a 137 struct run_as_extract_elf_symbol_offset_data extract_elf_symbol_offset;
0ef03255 138 struct run_as_extract_sdt_probe_offsets_data extract_sdt_probe_offsets;
7567352f
MD
139 } u;
140 uid_t uid;
141 gid_t gid;
93bed9fe 142} LTTNG_PACKED;
4628484a 143
fe9f7760
FD
144/*
145 * The run_as_ret structure holds the returned value and status of the command.
146 *
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.
150 *
151 * The _errno field is the errno recorded after the execution of the command.
152 *
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
156 * command.
157 *
158 */
df5b86c8 159struct run_as_ret {
fe9f7760 160 union {
93bed9fe 161 int ret;
fe9f7760 162 struct run_as_open_ret open;
241e0a5a 163 struct run_as_extract_elf_symbol_offset_ret extract_elf_symbol_offset;
0ef03255 164 struct run_as_extract_sdt_probe_offsets_ret extract_sdt_probe_offsets;
fe9f7760 165 } u;
df5b86c8 166 int _errno;
fe9f7760 167 bool _error;
93bed9fe
JG
168} LTTNG_PACKED;
169
170#define COMMAND_IN_FDS(data_ptr) ({ \
171 int *fds = NULL; \
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); \
174 } \
175 fds; \
176})
177
178#define COMMAND_OUT_FDS(cmd, ret_ptr) ({ \
179 int *fds = NULL; \
180 if (command_properties[cmd].out_fds_offset != -1) { \
181 fds = (int *) ((char *) ret_ptr + command_properties[cmd].out_fds_offset); \
182 } \
183 fds; \
184})
185
186#define COMMAND_IN_FD_COUNT(data_ptr) ({ \
187 command_properties[data_ptr->cmd].in_fd_count; \
188})
189
190#define COMMAND_OUT_FD_COUNT(cmd) ({ \
191 command_properties[cmd].out_fd_count; \
192})
193
194#define COMMAND_USE_CWD_FD(data_ptr) command_properties[data_ptr->cmd].use_cwd_fd
195
196struct 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;
200 bool use_cwd_fd;
201};
202
203static const struct run_as_command_properties command_properties[] = {
204 [RUN_AS_MKDIR] = {
205 .in_fds_offset = offsetof(struct run_as_data, u.mkdir.dirfd),
206 .in_fd_count = 1,
207 .out_fds_offset = -1,
208 .out_fd_count = 0,
209 .use_cwd_fd = true,
210 },
211 [RUN_AS_MKDIRAT] = {
212 .in_fds_offset = offsetof(struct run_as_data, u.mkdir.dirfd),
213 .in_fd_count = 1,
214 .out_fds_offset = -1,
215 .out_fd_count = 0,
216 .use_cwd_fd = false,
217 },
218 [RUN_AS_MKDIR_RECURSIVE] = {
219 .in_fds_offset = offsetof(struct run_as_data, u.mkdir.dirfd),
220 .in_fd_count = 1,
221 .out_fds_offset = -1,
222 .out_fd_count = 0,
223 .use_cwd_fd = true,
224 },
225 [RUN_AS_MKDIRAT_RECURSIVE] = {
226 .in_fds_offset = offsetof(struct run_as_data, u.mkdir.dirfd),
227 .in_fd_count = 1,
228 .out_fds_offset = -1,
229 .out_fd_count = 0,
230 .use_cwd_fd = false,
231 },
232 [RUN_AS_OPEN] = {
233 .in_fds_offset = offsetof(struct run_as_data, u.open.dirfd),
234 .in_fd_count = 1,
235 .out_fds_offset = offsetof(struct run_as_ret, u.open.fd),
236 .out_fd_count = 1,
237 .use_cwd_fd = true,
238 },
239 [RUN_AS_OPENAT] = {
240 .in_fds_offset = offsetof(struct run_as_data, u.open.dirfd),
241 .in_fd_count = 1,
242 .out_fds_offset = offsetof(struct run_as_ret, u.open.fd),
243 .out_fd_count = 1,
244 .use_cwd_fd = false,
245 },
246 [RUN_AS_UNLINK] = {
247 .in_fds_offset = offsetof(struct run_as_data, u.unlink.dirfd),
248 .in_fd_count = 1,
249 .out_fds_offset = -1,
250 .out_fd_count = 0,
251 .use_cwd_fd = true,
252 },
253 [RUN_AS_UNLINKAT] = {
254 .in_fds_offset = offsetof(struct run_as_data, u.unlink.dirfd),
255 .in_fd_count = 1,
256 .out_fds_offset = -1,
257 .out_fd_count = 0,
258 .use_cwd_fd = false,
259 },
260 [RUN_AS_RMDIR_RECURSIVE] = {
261 .in_fds_offset = offsetof(struct run_as_data, u.rmdir.dirfd),
262 .in_fd_count = 1,
263 .out_fds_offset = -1,
264 .out_fd_count = 0,
265 .use_cwd_fd = true,
266 },
267 [RUN_AS_RMDIRAT_RECURSIVE] = {
268 .in_fds_offset = offsetof(struct run_as_data, u.rmdir.dirfd),
269 .in_fd_count = 1,
270 .out_fds_offset = -1,
271 .out_fd_count = 0,
272 .use_cwd_fd = false,
273 },
274 [RUN_AS_RMDIR] = {
275 .in_fds_offset = offsetof(struct run_as_data, u.rmdir.dirfd),
276 .in_fd_count = 1,
277 .out_fds_offset = -1,
278 .out_fd_count = 0,
279 .use_cwd_fd = true,
280 },
281 [RUN_AS_RMDIRAT] = {
282 .in_fds_offset = offsetof(struct run_as_data, u.rmdir.dirfd),
283 .in_fd_count = 1,
284 .out_fds_offset = -1,
285 .out_fd_count = 0,
286 .use_cwd_fd = false,
287 },
288 [RUN_AS_RENAME] = {
289 .in_fds_offset = offsetof(struct run_as_data, u.rename.dirfds),
290 .in_fd_count = 2,
291 .out_fds_offset = -1,
292 .out_fd_count = 0,
293 .use_cwd_fd = true,
294 },
295 [RUN_AS_RENAMEAT] = {
296 .in_fds_offset = offsetof(struct run_as_data, u.rename.dirfds),
297 .in_fd_count = 2,
298 .out_fds_offset = -1,
299 .out_fd_count = 0,
300 .use_cwd_fd = false,
301 },
302 [RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET] = {
303 .in_fds_offset = offsetof(struct run_as_data,
304 u.extract_elf_symbol_offset.fd),
305 .in_fd_count = 1,
306 .out_fds_offset = -1,
307 .out_fd_count = 0,
308 .use_cwd_fd = false,
309 },
310 [RUN_AS_EXTRACT_SDT_PROBE_OFFSETS] = {
311 .in_fds_offset = offsetof(struct run_as_data,
312 u.extract_sdt_probe_offsets.fd),
313 .in_fd_count = 1,
314 .out_fds_offset = -1,
315 .out_fd_count = 0,
316 .use_cwd_fd = false,
317 },
df5b86c8
MD
318};
319
7567352f
MD
320struct run_as_worker {
321 pid_t pid; /* Worker PID. */
322 int sockpair[2];
323 char *procname;
324};
325
326/* Single global worker per process (for now). */
327static struct run_as_worker *global_worker;
328/* Lock protecting the worker. */
329static pthread_mutex_t worker_lock = PTHREAD_MUTEX_INITIALIZER;
330
8f0044bf
MD
331#ifdef VALGRIND
332static
333int use_clone(void)
334{
335 return 0;
336}
337#else
338static
339int use_clone(void)
340{
e8fa9fb0 341 return !lttng_secure_getenv("LTTNG_DEBUG_NOCLONE");
8f0044bf
MD
342}
343#endif
344
60b6c79c
MD
345/*
346 * Create recursively directory using the FULL path.
347 */
348static
18710679 349int _mkdirat_recursive(struct run_as_data *data, struct run_as_ret *ret_value)
60b6c79c 350{
60b6c79c 351 const char *path;
60b6c79c 352 mode_t mode;
18710679 353 struct lttng_directory_handle handle;
60b6c79c 354
93bed9fe
JG
355 path = data->u.mkdir.path;
356 mode = data->u.mkdir.mode;
60b6c79c 357
93bed9fe
JG
358 (void) lttng_directory_handle_init_from_dirfd(&handle,
359 data->u.mkdir.dirfd);
87bbb856 360 /* Ownership of dirfd is transferred to the handle. */
93bed9fe 361 data->u.mkdir.dirfd = -1;
d77dded2 362 /* Safe to call as we have transitioned to the requested uid/gid. */
93bed9fe 363 ret_value->u.ret =
18710679
JG
364 lttng_directory_handle_create_subdirectory_recursive(
365 &handle, path, mode);
fe9f7760 366 ret_value->_errno = errno;
93bed9fe 367 ret_value->_error = (ret_value->u.ret) ? true : false;
18710679 368 lttng_directory_handle_fini(&handle);
93bed9fe 369 return ret_value->u.ret;
60b6c79c
MD
370}
371
372static
18710679 373int _mkdirat(struct run_as_data *data, struct run_as_ret *ret_value)
60b6c79c 374{
18710679
JG
375 const char *path;
376 mode_t mode;
377 struct lttng_directory_handle handle;
378
93bed9fe
JG
379 path = data->u.mkdir.path;
380 mode = data->u.mkdir.mode;
18710679 381
93bed9fe
JG
382 (void) lttng_directory_handle_init_from_dirfd(&handle,
383 data->u.mkdir.dirfd);
87bbb856 384 /* Ownership of dirfd is transferred to the handle. */
93bed9fe 385 data->u.mkdir.dirfd = -1;
18710679 386 /* Safe to call as we have transitioned to the requested uid/gid. */
93bed9fe 387 ret_value->u.ret =
18710679
JG
388 lttng_directory_handle_create_subdirectory(
389 &handle, path, mode);
fe9f7760 390 ret_value->_errno = errno;
93bed9fe 391 ret_value->_error = (ret_value->u.ret) ? true : false;
18710679 392 lttng_directory_handle_fini(&handle);
93bed9fe 393 return ret_value->u.ret;
7567352f 394}
7ce36756 395
7567352f 396static
fe9f7760 397int _open(struct run_as_data *data, struct run_as_ret *ret_value)
7567352f 398{
93bed9fe
JG
399 int fd;
400 struct lttng_directory_handle handle;
401
402 (void) lttng_directory_handle_init_from_dirfd(&handle,
403 data->u.open.dirfd);
404 /* Ownership of dirfd is transferred to the handle. */
405 data->u.open.dirfd = -1;
406
407 fd = lttng_directory_handle_open_file(&handle,
408 data->u.open.path, data->u.open.flags,
409 data->u.open.mode);
410 if (fd < 0) {
411 ret_value->u.ret = -1;
412 ret_value->u.open.fd = -1;
413 } else {
414 ret_value->u.ret = 0;
415 ret_value->u.open.fd = fd;
416 }
417
fe9f7760 418 ret_value->_errno = errno;
93bed9fe
JG
419 ret_value->_error = fd < 0;
420 lttng_directory_handle_fini(&handle);
421 return ret_value->u.ret;
7567352f
MD
422}
423
424static
fe9f7760 425int _unlink(struct run_as_data *data, struct run_as_ret *ret_value)
7567352f 426{
93bed9fe
JG
427 struct lttng_directory_handle handle;
428
429 (void) lttng_directory_handle_init_from_dirfd(&handle,
430 data->u.unlink.dirfd);
431
432 /* Ownership of dirfd is transferred to the handle. */
433 data->u.unlink.dirfd = -1;
434
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;
441}
442
443static
444int _rmdir(struct run_as_data *data, struct run_as_ret *ret_value)
445{
446 struct lttng_directory_handle handle;
447
448 (void) lttng_directory_handle_init_from_dirfd(&handle,
449 data->u.rmdir.dirfd);
450
451 /* Ownership of dirfd is transferred to the handle. */
452 data->u.rmdir.dirfd = -1;
453
454 ret_value->u.ret = lttng_directory_handle_remove_subdirectory(
455 &handle, data->u.rmdir.path);
fe9f7760 456 ret_value->_errno = errno;
93bed9fe
JG
457 ret_value->_error = (ret_value->u.ret) ? true : false;
458 lttng_directory_handle_fini(&handle);
459 return ret_value->u.ret;
60b6c79c
MD
460}
461
462static
fe9f7760 463int _rmdir_recursive(struct run_as_data *data, struct run_as_ret *ret_value)
60b6c79c 464{
93bed9fe
JG
465 struct lttng_directory_handle handle;
466
467 (void) lttng_directory_handle_init_from_dirfd(&handle,
468 data->u.rmdir.dirfd);
469
470 /* Ownership of dirfd is transferred to the handle. */
471 data->u.rmdir.dirfd = -1;
472
473 ret_value->u.ret = lttng_directory_handle_remove_subdirectory_recursive(
474 &handle, data->u.rmdir.path);
fe9f7760 475 ret_value->_errno = errno;
93bed9fe
JG
476 ret_value->_error = (ret_value->u.ret) ? true : false;
477 lttng_directory_handle_fini(&handle);
478 return ret_value->u.ret;
479}
480
481static
482int _rename(struct run_as_data *data, struct run_as_ret *ret_value)
483{
484 const char *old_path, *new_path;
485 struct lttng_directory_handle old_handle, new_handle;
486
487 old_path = data->u.rename.old_path;
488 new_path = data->u.rename.new_path;
489
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]);
494
495 /* Ownership of dirfds are transferred to the handles. */
496 data->u.rename.dirfds[0] = data->u.rename.dirfds[1] = -1;
497
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;
7567352f 506}
df5b86c8 507
b1b34226 508#ifdef HAVE_ELF_H
241e0a5a
FD
509static
510int _extract_elf_symbol_offset(struct run_as_data *data,
511 struct run_as_ret *ret_value)
512{
513 int ret = 0;
241e0a5a 514
93bed9fe
JG
515 ret_value->_error = false;
516 ret = lttng_elf_get_symbol_offset(data->u.extract_elf_symbol_offset.fd,
241e0a5a
FD
517 data->u.extract_elf_symbol_offset.function,
518 &ret_value->u.extract_elf_symbol_offset.offset);
519 if (ret) {
520 DBG("Failed to extract ELF function offset");
521 ret_value->_error = true;
522 }
523
524 return ret;
525}
526
0ef03255
FD
527static
528int _extract_sdt_probe_offsets(struct run_as_data *data,
529 struct run_as_ret *ret_value)
530{
531 int ret = 0;
532 uint64_t *offsets = NULL;
533 uint32_t num_offset;
534
535 ret_value->_error = false;
536
537 /* On success, this call allocates the offsets paramater. */
93bed9fe
JG
538 ret = lttng_elf_get_sdt_probe_offsets(
539 data->u.extract_sdt_probe_offsets.fd,
0ef03255
FD
540 data->u.extract_sdt_probe_offsets.provider_name,
541 data->u.extract_sdt_probe_offsets.probe_name,
542 &offsets, &num_offset);
543
544 if (ret) {
545 DBG("Failed to extract SDT probe offsets");
546 ret_value->_error = true;
547 goto end;
548 }
549
550 if (num_offset <= 0 || num_offset > LTTNG_KERNEL_MAX_UPROBE_NUM) {
551 DBG("Wrong number of probes.");
552 ret = -1;
553 ret_value->_error = true;
554 goto free_offset;
555 }
556
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));
560
561 ret_value->u.extract_sdt_probe_offsets.num_offset = num_offset;
562
563free_offset:
564 free(offsets);
565end:
566 return ret;
567}
b1b34226
MJ
568#else
569static
570int _extract_elf_symbol_offset(struct run_as_data *data,
571 struct run_as_ret *ret_value)
572{
573 ERR("Unimplemented runas command RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET");
574 return -1;
575}
576
577static
578int _extract_sdt_probe_offsets(struct run_as_data *data,
579 struct run_as_ret *ret_value)
580{
581 ERR("Unimplemented runas command RUN_AS_EXTRACT_SDT_PROBE_OFFSETS");
582 return -1;
583}
584#endif
241e0a5a 585
7567352f
MD
586static
587run_as_fct run_as_enum_to_fct(enum run_as_cmd cmd)
588{
589 switch (cmd) {
590 case RUN_AS_MKDIR:
18710679
JG
591 case RUN_AS_MKDIRAT:
592 return _mkdirat;
593 case RUN_AS_MKDIR_RECURSIVE:
594 case RUN_AS_MKDIRAT_RECURSIVE:
595 return _mkdirat_recursive;
7567352f 596 case RUN_AS_OPEN:
2912cead 597 case RUN_AS_OPENAT:
7567352f
MD
598 return _open;
599 case RUN_AS_UNLINK:
2912cead 600 case RUN_AS_UNLINKAT:
7567352f 601 return _unlink;
93bed9fe
JG
602 case RUN_AS_RMDIR:
603 case RUN_AS_RMDIRAT:
604 return _rmdir;
7567352f 605 case RUN_AS_RMDIR_RECURSIVE:
93bed9fe 606 case RUN_AS_RMDIRAT_RECURSIVE:
7567352f 607 return _rmdir_recursive;
93bed9fe
JG
608 case RUN_AS_RENAME:
609 case RUN_AS_RENAMEAT:
610 return _rename;
241e0a5a
FD
611 case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET:
612 return _extract_elf_symbol_offset;
0ef03255
FD
613 case RUN_AS_EXTRACT_SDT_PROBE_OFFSETS:
614 return _extract_sdt_probe_offsets;
7567352f 615 default:
62a7b8ed 616 ERR("Unknown command %d", (int) cmd);
7567352f
MD
617 return NULL;
618 }
60b6c79c
MD
619}
620
4628484a 621static
93bed9fe 622int do_send_fds(int sock, const int *fds, unsigned int fd_count)
4628484a 623{
7567352f 624 ssize_t len;
93bed9fe
JG
625 unsigned int i;
626
627 for (i = 0; i < fd_count; i++) {
628 if (fds[i] < 0) {
629 ERR("Attempt to send invalid file descriptor to master (fd = %i)",
630 fds[i]);
631 /* Return 0 as this is not a fatal error. */
632 return 0;
633 }
634 }
4628484a 635
93bed9fe
JG
636 len = lttcomm_send_fds_unix_sock(sock, fds, fd_count);
637 return len < 0 ? -1 : 0;
4628484a
MD
638}
639
640static
93bed9fe 641int do_recv_fds(int sock, int *fds, unsigned int fd_count)
4628484a 642{
93bed9fe
JG
643 int ret = 0;
644 unsigned int i;
7567352f 645 ssize_t len;
4628484a 646
93bed9fe
JG
647 len = lttcomm_recv_fds_unix_sock(sock, fds, fd_count);
648 if (len == 0) {
649 ret = -1;
650 goto end;
da9ee832 651 } else if (len < 0) {
93bed9fe
JG
652 PERROR("Failed to receive file descriptors from socket");
653 ret = -1;
654 goto end;
ca9eb994
JG
655 }
656
93bed9fe
JG
657 for (i = 0; i < fd_count; i++) {
658 if (fds[i] < 0) {
659 ERR("Invalid file descriptor received from worker (fd = %i)", fds[i]);
660 /* Return 0 as this is not a fatal error. */
661 }
662 }
663end:
664 return ret;
4628484a
MD
665}
666
fe9f7760 667static
93bed9fe
JG
668int send_fds_to_worker(const struct run_as_worker *worker,
669 const struct run_as_data *data)
fe9f7760
FD
670{
671 int ret = 0;
93bed9fe 672 unsigned int i;
fe9f7760 673
93bed9fe
JG
674 if (COMMAND_USE_CWD_FD(data) || COMMAND_IN_FD_COUNT(data) == 0) {
675 goto end;
fe9f7760
FD
676 }
677
93bed9fe
JG
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]);
682 ret = -1;
683 goto end;
684 }
685 }
ca9eb994 686
93bed9fe
JG
687 ret = do_send_fds(worker->sockpair[0], COMMAND_IN_FDS(data),
688 COMMAND_IN_FD_COUNT(data));
fe9f7760 689 if (ret < 0) {
93bed9fe 690 PERROR("Failed to send file descriptor to run-as worker");
fe9f7760 691 ret = -1;
93bed9fe 692 goto end;
fe9f7760 693 }
93bed9fe 694end:
fe9f7760
FD
695 return ret;
696}
697
698static
93bed9fe
JG
699int send_fds_to_master(struct run_as_worker *worker, enum run_as_cmd cmd,
700 struct run_as_ret *run_as_ret)
fe9f7760 701{
93bed9fe
JG
702 int ret = 0;
703 unsigned int i;
fe9f7760 704
93bed9fe
JG
705 if (COMMAND_OUT_FD_COUNT(cmd) == 0) {
706 goto end;
fe9f7760
FD
707 }
708
93bed9fe
JG
709 ret = do_send_fds(worker->sockpair[1], COMMAND_OUT_FDS(cmd, run_as_ret),
710 COMMAND_OUT_FD_COUNT(cmd));
fe9f7760 711 if (ret < 0) {
93bed9fe
JG
712 PERROR("Failed to send file descriptor to master process");
713 goto end;
fe9f7760
FD
714 }
715
93bed9fe
JG
716 for (i = 0; i < COMMAND_OUT_FD_COUNT(cmd); i++) {
717 int ret_close = close(COMMAND_OUT_FDS(cmd, run_as_ret)[i]);
ca9eb994 718
93bed9fe
JG
719 if (ret_close < 0) {
720 PERROR("Failed to close result file descriptor");
721 }
722 }
723end:
fe9f7760
FD
724 return ret;
725}
726
727static
93bed9fe
JG
728int recv_fds_from_worker(const struct run_as_worker *worker, enum run_as_cmd cmd,
729 struct run_as_ret *run_as_ret)
fe9f7760
FD
730{
731 int ret = 0;
732
93bed9fe
JG
733 if (COMMAND_OUT_FD_COUNT(cmd) == 0) {
734 goto end;
fe9f7760
FD
735 }
736
93bed9fe
JG
737 ret = do_recv_fds(worker->sockpair[0], COMMAND_OUT_FDS(cmd, run_as_ret),
738 COMMAND_OUT_FD_COUNT(cmd));
fe9f7760 739 if (ret < 0) {
93bed9fe 740 PERROR("Failed to receive file descriptor from run-as worker");
fe9f7760
FD
741 ret = -1;
742 }
93bed9fe 743end:
fe9f7760
FD
744 return ret;
745}
746
747static
93bed9fe 748int recv_fds_from_master(struct run_as_worker *worker, struct run_as_data *data)
fe9f7760
FD
749{
750 int ret = 0;
751
93bed9fe
JG
752 if (COMMAND_USE_CWD_FD(data)) {
753 unsigned int i;
754
755 for (i = 0; i < COMMAND_IN_FD_COUNT(data); i++) {
756 COMMAND_IN_FDS(data)[i] = AT_FDCWD;
757 }
758 goto end;
fe9f7760
FD
759 }
760
93bed9fe
JG
761 ret = do_recv_fds(worker->sockpair[1], COMMAND_IN_FDS(data),
762 COMMAND_IN_FD_COUNT(data));
fe9f7760 763 if (ret < 0) {
93bed9fe 764 PERROR("Failed to receive file descriptors from master process");
fe9f7760
FD
765 ret = -1;
766 }
93bed9fe 767end:
fe9f7760
FD
768 return ret;
769}
770
771static
93bed9fe 772int cleanup_received_fds(struct run_as_data *data)
fe9f7760 773{
93bed9fe 774 int ret = 0, i;
fe9f7760 775
93bed9fe
JG
776 for (i = 0; i < COMMAND_IN_FD_COUNT(data); i++) {
777 if (COMMAND_IN_FDS(data)[i] == -1) {
778 continue;
779 }
780 ret = close(COMMAND_IN_FDS(data)[i]);
781 if (ret) {
782 PERROR("Failed to close file descriptor received fd in run-as worker");
783 goto end;
784 }
fe9f7760 785 }
93bed9fe 786end:
fe9f7760
FD
787 return ret;
788}
0ef03255 789
7567352f
MD
790/*
791 * Return < 0 on error, 0 if OK, 1 on hangup.
792 */
c2b75c49 793static
7567352f 794int handle_one_cmd(struct run_as_worker *worker)
c2b75c49 795{
7567352f 796 int ret = 0;
93bed9fe
JG
797 struct run_as_data data = {};
798 ssize_t readlen, writelen;
799 struct run_as_ret sendret = {};
800 run_as_fct cmd;
7567352f
MD
801 uid_t prev_euid;
802
fe9f7760
FD
803 /*
804 * Stage 1: Receive run_as_data struct from the master.
805 * The structure contains the command type and all the parameters needed for
806 * its execution
807 */
7567352f
MD
808 readlen = lttcomm_recv_unix_sock(worker->sockpair[1], &data,
809 sizeof(data));
810 if (readlen == 0) {
811 /* hang up */
812 ret = 1;
813 goto end;
814 }
815 if (readlen < sizeof(data)) {
816 PERROR("lttcomm_recv_unix_sock error");
817 ret = -1;
818 goto end;
819 }
c2b75c49 820
7567352f
MD
821 cmd = run_as_enum_to_fct(data.cmd);
822 if (!cmd) {
823 ret = -1;
824 goto end;
825 }
826
fe9f7760
FD
827 /*
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.
831 */
93bed9fe 832 ret = recv_fds_from_master(worker, &data);
fe9f7760
FD
833 if (ret < 0) {
834 PERROR("recv_fd_from_master error");
835 ret = -1;
836 goto end;
837 }
838
7567352f
MD
839 prev_euid = getuid();
840 if (data.gid != getegid()) {
841 ret = setegid(data.gid);
1576d582 842 if (ret < 0) {
561f5f2c
JG
843 sendret._error = true;
844 sendret._errno = errno;
4c462e79 845 PERROR("setegid");
6d73c4ef 846 goto write_return;
1576d582 847 }
c2b75c49 848 }
7567352f
MD
849 if (data.uid != prev_euid) {
850 ret = seteuid(data.uid);
1576d582 851 if (ret < 0) {
561f5f2c
JG
852 sendret._error = true;
853 sendret._errno = errno;
4c462e79 854 PERROR("seteuid");
6d73c4ef 855 goto write_return;
1576d582 856 }
c2b75c49 857 }
fe9f7760 858
c2b75c49
MD
859 /*
860 * Also set umask to 0 for mkdir executable bit.
861 */
862 umask(0);
fe9f7760
FD
863
864 /*
865 * Stage 3: Execute the command
866 */
867 ret = (*cmd)(&data, &sendret);
868 if (ret < 0) {
869 DBG("Execution of command returned an error");
870 }
6d73c4ef
MD
871
872write_return:
93bed9fe 873 ret = cleanup_received_fds(&data);
fe9f7760
FD
874 if (ret < 0) {
875 ERR("Error cleaning up FD");
876 goto end;
877 }
878
879 /*
880 * Stage 4: Send run_as_ret structure to the master.
881 * This structure contain the return value of the command and the errno.
882 */
7567352f
MD
883 writelen = lttcomm_send_unix_sock(worker->sockpair[1], &sendret,
884 sizeof(sendret));
6cd525e8 885 if (writelen < sizeof(sendret)) {
7567352f
MD
886 PERROR("lttcomm_send_unix_sock error");
887 ret = -1;
888 goto end;
889 }
fe9f7760
FD
890
891 /*
93bed9fe 892 * Stage 5: Send resulting file descriptors to the master.
fe9f7760 893 */
93bed9fe 894 ret = send_fds_to_master(worker, data.cmd, &sendret);
fe9f7760
FD
895 if (ret < 0) {
896 DBG("Sending FD to master returned an error");
7567352f
MD
897 goto end;
898 }
fe9f7760 899
7567352f
MD
900 if (seteuid(prev_euid) < 0) {
901 PERROR("seteuid");
902 ret = -1;
903 goto end;
904 }
905 ret = 0;
906end:
907 return ret;
908}
909
910static
911int run_as_worker(struct run_as_worker *worker)
912{
913 int ret;
914 ssize_t writelen;
915 struct run_as_ret sendret;
916 size_t proc_orig_len;
917
918 /*
919 * Initialize worker. Set a different process cmdline.
920 */
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);
924
e1055edb
JG
925 ret = lttng_prctl(PR_SET_NAME,
926 (unsigned long) DEFAULT_RUN_AS_WORKER_NAME, 0, 0, 0);
927 if (ret && ret != -ENOSYS) {
b8090274
JG
928 /* Don't fail as this is not essential. */
929 PERROR("prctl PR_SET_NAME");
6cd525e8 930 }
7567352f 931
fe9f7760
FD
932 memset(&sendret, 0, sizeof(sendret));
933
7567352f
MD
934 writelen = lttcomm_send_unix_sock(worker->sockpair[1], &sendret,
935 sizeof(sendret));
936 if (writelen < sizeof(sendret)) {
937 PERROR("lttcomm_send_unix_sock error");
938 ret = EXIT_FAILURE;
939 goto end;
940 }
941
942 for (;;) {
943 ret = handle_one_cmd(worker);
944 if (ret < 0) {
945 ret = EXIT_FAILURE;
946 goto end;
947 } else if (ret > 0) {
948 break;
949 } else {
950 continue; /* Next command. */
951 }
952 }
953 ret = EXIT_SUCCESS;
954end:
955 return ret;
c2b75c49
MD
956}
957
60b6c79c 958static
7567352f
MD
959int run_as_cmd(struct run_as_worker *worker,
960 enum run_as_cmd cmd,
961 struct run_as_data *data,
fe9f7760 962 struct run_as_ret *ret_value,
7567352f 963 uid_t uid, gid_t gid)
60b6c79c 964{
fe9f7760 965 int ret = 0;
7567352f 966 ssize_t readlen, writelen;
60b6c79c
MD
967
968 /*
969 * If we are non-root, we can only deal with our own uid.
970 */
971 if (geteuid() != 0) {
972 if (uid != geteuid()) {
fe9f7760
FD
973 ret = -1;
974 ret_value->_errno = EPERM;
60b6c79c 975 ERR("Client (%d)/Server (%d) UID mismatch (and sessiond is not root)",
08797918 976 (int) uid, (int) geteuid());
df5b86c8 977 goto end;
60b6c79c 978 }
60b6c79c
MD
979 }
980
7567352f
MD
981 data->cmd = cmd;
982 data->uid = uid;
983 data->gid = gid;
984
fe9f7760
FD
985 /*
986 * Stage 1: Send the run_as_data struct to the worker process
987 */
7567352f
MD
988 writelen = lttcomm_send_unix_sock(worker->sockpair[0], data,
989 sizeof(*data));
990 if (writelen < sizeof(*data)) {
991 PERROR("Error writing message to run_as");
fe9f7760
FD
992 ret = -1;
993 ret_value->_errno = EIO;
60b6c79c 994 goto end;
c2b75c49 995 }
7567352f 996
fe9f7760
FD
997 /*
998 * Stage 2: Send file descriptor to the worker process if needed
999 */
93bed9fe 1000 ret = send_fds_to_worker(worker, data);
fe9f7760
FD
1001 if (ret) {
1002 PERROR("do_send_fd error");
1003 ret = -1;
1004 ret_value->_errno = EIO;
1005 goto end;
1006 }
1007
1008 /*
1009 * Stage 3: Wait for the execution of the command
1010 */
1011
1012 /*
1013 * Stage 4: Receive the run_as_ret struct containing the return value and
1014 * errno
1015 */
1016 readlen = lttcomm_recv_unix_sock(worker->sockpair[0], ret_value,
1017 sizeof(*ret_value));
da9ee832
JG
1018 if (!readlen) {
1019 ERR("Run-as worker has hung-up during run_as_cmd");
fe9f7760
FD
1020 ret = -1;
1021 ret_value->_errno = EIO;
da9ee832 1022 goto end;
fe9f7760 1023 } else if (readlen < sizeof(*ret_value)) {
7567352f 1024 PERROR("Error reading response from run_as");
fe9f7760
FD
1025 ret = -1;
1026 ret_value->_errno = errno;
033b58a7 1027 goto end;
6cd525e8 1028 }
fe9f7760 1029
ca9eb994
JG
1030 if (ret_value->_error) {
1031 /* Skip stage 5 on error as there will be no fd to receive. */
1032 goto end;
1033 }
1034
fe9f7760
FD
1035 /*
1036 * Stage 5: Receive file descriptor if needed
1037 */
93bed9fe 1038 ret = recv_fds_from_worker(worker, cmd, ret_value);
fe9f7760
FD
1039 if (ret < 0) {
1040 ERR("Error receiving fd");
1041 ret = -1;
1042 ret_value->_errno = EIO;
4c462e79 1043 }
7567352f 1044
60b6c79c 1045end:
fe9f7760 1046 return ret;
60b6c79c
MD
1047}
1048
2d85a600 1049/*
7567352f 1050 * This is for debugging ONLY and should not be considered secure.
2d85a600
MD
1051 */
1052static
fe9f7760
FD
1053int 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)
2d85a600 1056{
df5b86c8 1057 int ret, saved_errno;
5b73926f 1058 mode_t old_mask;
7567352f 1059 run_as_fct fct;
5b73926f 1060
7567352f
MD
1061 fct = run_as_enum_to_fct(cmd);
1062 if (!fct) {
1063 errno = -ENOSYS;
1064 ret = -1;
1065 goto end;
1066 }
5b73926f 1067 old_mask = umask(0);
fe9f7760
FD
1068 ret = fct(data, ret_value);
1069 saved_errno = ret_value->_errno;
5b73926f 1070 umask(old_mask);
df5b86c8 1071 errno = saved_errno;
7567352f 1072end:
5b73926f 1073 return ret;
2d85a600
MD
1074}
1075
8fec83ea
JG
1076static
1077int reset_sighandler(void)
1078{
1079 int sig;
1080
1081 DBG("Resetting run_as worker signal handlers to default");
1082 for (sig = 1; sig <= 31; sig++) {
1083 (void) signal(sig, SIG_DFL);
1084 }
1085 return 0;
1086}
1087
1088static
1089void worker_sighandler(int sig)
1090{
1091 const char *signame;
1092
1093 /*
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.
1098 */
1099 switch (sig) {
1100 case SIGINT:
1101 signame = "SIGINT";
1102 break;
1103 case SIGTERM:
1104 signame = "SIGTERM";
1105 break;
1106 default:
1107 signame = NULL;
1108 }
1109
1110 if (signame) {
1111 DBG("run_as worker received signal %s", signame);
1112 } else {
1113 DBG("run_as_worker received signal %d", sig);
1114 }
1115}
1116
1117static
1118int set_worker_sighandlers(void)
1119{
1120 int ret = 0;
1121 sigset_t sigset;
1122 struct sigaction sa;
1123
1124 if ((ret = sigemptyset(&sigset)) < 0) {
1125 PERROR("sigemptyset");
1126 goto end;
1127 }
1128
1129 sa.sa_handler = worker_sighandler;
1130 sa.sa_mask = sigset;
1131 sa.sa_flags = 0;
1132 if ((ret = sigaction(SIGINT, &sa, NULL)) < 0) {
1133 PERROR("sigaction SIGINT");
1134 goto end;
1135 }
1136
1137 if ((ret = sigaction(SIGTERM, &sa, NULL)) < 0) {
1138 PERROR("sigaction SIGTERM");
1139 goto end;
1140 }
1141
1142 DBG("run_as signal handler set for SIGTERM and SIGINT");
1143end:
1144 return ret;
1145}
1146
1147static
929f71ec
JG
1148int run_as_create_worker_no_lock(const char *procname,
1149 post_fork_cleanup_cb clean_up_func,
1150 void *clean_up_user_data)
8fec83ea
JG
1151{
1152 pid_t pid;
1153 int i, ret = 0;
1154 ssize_t readlen;
1155 struct run_as_ret recvret;
1156 struct run_as_worker *worker;
1157
1158 assert(!global_worker);
1159 if (!use_clone()) {
1160 /*
1161 * Don't initialize a worker, all run_as tasks will be performed
1162 * in the current process.
1163 */
1164 ret = 0;
1165 goto end;
1166 }
1167 worker = zmalloc(sizeof(*worker));
1168 if (!worker) {
1169 ret = -ENOMEM;
1170 goto end;
1171 }
1172 worker->procname = strdup(procname);
1173 if (!worker->procname) {
1174 ret = -ENOMEM;
8c96eded 1175 goto error_procname_alloc;
8fec83ea
JG
1176 }
1177 /* Create unix socket. */
1178 if (lttcomm_create_anon_unix_socketpair(worker->sockpair) < 0) {
1179 ret = -1;
1180 goto error_sock;
1181 }
1182
1183 /* Fork worker. */
1184 pid = fork();
1185 if (pid < 0) {
1186 PERROR("fork");
1187 ret = -1;
1188 goto error_fork;
1189 } else if (pid == 0) {
1190 /* Child */
1191
1192 reset_sighandler();
1193
1194 set_worker_sighandlers();
929f71ec
JG
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.");
1198 exit(EXIT_FAILURE);
1199 }
1200 }
8fec83ea
JG
1201
1202 /* Just close, no shutdown. */
1203 if (close(worker->sockpair[0])) {
1204 PERROR("close");
1205 exit(EXIT_FAILURE);
1206 }
1207
1208 /*
1209 * Close all FDs aside from STDIN, STDOUT, STDERR and sockpair[1]
1210 * Sockpair[1] is used as a control channel with the master
1211 */
1212 for (i = 3; i < sysconf(_SC_OPEN_MAX); i++) {
1213 if (i != worker->sockpair[1]) {
1214 (void) close(i);
1215 }
1216 }
1217
1218 worker->sockpair[0] = -1;
1219 ret = run_as_worker(worker);
1220 if (lttcomm_close_unix_sock(worker->sockpair[1])) {
1221 PERROR("close");
1222 ret = -1;
1223 }
1224 worker->sockpair[1] = -1;
340cf672
JG
1225 free(worker->procname);
1226 free(worker);
8fec83ea
JG
1227 LOG(ret ? PRINT_ERR : PRINT_DBG, "run_as worker exiting (ret = %d)", ret);
1228 exit(ret ? EXIT_FAILURE : EXIT_SUCCESS);
1229 } else {
1230 /* Parent */
1231
1232 /* Just close, no shutdown. */
1233 if (close(worker->sockpair[1])) {
1234 PERROR("close");
1235 ret = -1;
1236 goto error_fork;
1237 }
1238 worker->sockpair[1] = -1;
1239 worker->pid = pid;
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");
1246 ret = -1;
1247 goto error_fork;
1248 }
1249 global_worker = worker;
1250 }
1251end:
1252 return ret;
1253
1254 /* Error handling. */
1255error_fork:
1256 for (i = 0; i < 2; i++) {
1257 if (worker->sockpair[i] < 0) {
1258 continue;
1259 }
1260 if (lttcomm_close_unix_sock(worker->sockpair[i])) {
1261 PERROR("close");
1262 }
1263 worker->sockpair[i] = -1;
1264 }
1265error_sock:
8c96eded
FD
1266 free(worker->procname);
1267error_procname_alloc:
8fec83ea
JG
1268 free(worker);
1269 return ret;
1270}
1271
a01c682b
JR
1272static
1273void run_as_destroy_worker_no_lock(void)
1274{
1275 struct run_as_worker *worker = global_worker;
1276
1277 DBG("Destroying run_as worker");
1278 if (!worker) {
1279 return;
1280 }
1281 /* Close unix socket */
1282 DBG("Closing run_as worker socket");
1283 if (lttcomm_close_unix_sock(worker->sockpair[0])) {
1284 PERROR("close");
1285 }
1286 worker->sockpair[0] = -1;
1287 /* Wait for worker. */
1288 for (;;) {
1289 int status;
1290 pid_t wait_ret;
1291
1292 wait_ret = waitpid(worker->pid, &status, 0);
1293 if (wait_ret < 0) {
1294 if (errno == EINTR) {
1295 continue;
1296 }
1297 PERROR("waitpid");
1298 break;
1299 }
1300
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));
1305 break;
1306 } else if (WIFSIGNALED(status)) {
1307 ERR(DEFAULT_RUN_AS_WORKER_NAME " was killed by signal %d",
1308 WTERMSIG(status));
1309 break;
1310 }
1311 }
1312 free(worker->procname);
1313 free(worker);
1314 global_worker = NULL;
1315}
1316
2d85a600 1317static
fe9f7760 1318int run_as_restart_worker(struct run_as_worker *worker)
2d85a600 1319{
fe9f7760
FD
1320 int ret = 0;
1321 char *procname = NULL;
1322
1323 procname = worker->procname;
1324
1325 /* Close socket to run_as worker process and clean up the zombie process */
a01c682b 1326 run_as_destroy_worker_no_lock();
fe9f7760
FD
1327
1328 /* Create a new run_as worker process*/
929f71ec 1329 ret = run_as_create_worker_no_lock(procname, NULL, NULL);
fe9f7760
FD
1330 if (ret < 0 ) {
1331 ERR("Restarting the worker process failed");
1332 ret = -1;
1333 goto err;
1334 }
1335err:
1336 return ret;
1337}
1338
1339static
1340int 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)
1342{
1343 int ret, saved_errno;
7567352f 1344
8fec83ea 1345 pthread_mutex_lock(&worker_lock);
749b7a0c 1346 if (use_clone()) {
7567352f 1347 DBG("Using run_as worker");
8fec83ea 1348
749b7a0c 1349 assert(global_worker);
749b7a0c 1350
fe9f7760
FD
1351 ret = run_as_cmd(global_worker, cmd, data, ret_value, uid, gid);
1352 saved_errno = ret_value->_errno;
1353
fe9f7760
FD
1354 /*
1355 * If the worker thread crashed the errno is set to EIO. we log
1356 * the error and start a new worker process.
1357 */
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);
fe9f7760
FD
1362 if (ret == -1) {
1363 ERR("Failed to restart worker process.");
1364 goto err;
1365 }
1366 }
2d85a600 1367 } else {
7567352f 1368 DBG("Using run_as without worker");
fe9f7760 1369 ret = run_as_noworker(cmd, data, ret_value, uid, gid);
2d85a600 1370 }
fe9f7760 1371err:
8fec83ea 1372 pthread_mutex_unlock(&worker_lock);
7567352f 1373 return ret;
2d85a600
MD
1374}
1375
90e535ef 1376LTTNG_HIDDEN
e11d277b 1377int run_as_mkdir_recursive(const char *path, mode_t mode, uid_t uid, gid_t gid)
60b6c79c 1378{
18710679
JG
1379 return run_as_mkdirat_recursive(AT_FDCWD, path, mode, uid, gid);
1380}
1381
1382LTTNG_HIDDEN
1383int run_as_mkdirat_recursive(int dirfd, const char *path, mode_t mode,
1384 uid_t uid, gid_t gid)
1385{
1386 int ret;
93bed9fe
JG
1387 struct run_as_data data = {};
1388 struct run_as_ret run_as_ret = {};
60b6c79c 1389
18710679
JG
1390 DBG3("mkdirat() recursive fd = %d%s, path = %s, mode = %d, uid = %d, gid = %d",
1391 dirfd, dirfd == AT_FDCWD ? " (AT_FDCWD)" : "",
08797918 1392 path, (int) mode, (int) uid, (int) gid);
93bed9fe
JG
1393 ret = lttng_strncpy(data.u.mkdir.path, path,
1394 sizeof(data.u.mkdir.path));
18710679
JG
1395 if (ret) {
1396 ERR("Failed to copy path argument of mkdirat recursive command");
1397 goto error;
1398 }
93bed9fe
JG
1399 data.u.mkdir.path[sizeof(data.u.mkdir.path) - 1] = '\0';
1400 data.u.mkdir.mode = mode;
1401 data.u.mkdir.dirfd = dirfd;
18710679
JG
1402 run_as(dirfd == AT_FDCWD ? RUN_AS_MKDIR_RECURSIVE : RUN_AS_MKDIRAT_RECURSIVE,
1403 &data, &run_as_ret, uid, gid);
1404 errno = run_as_ret._errno;
93bed9fe 1405 ret = run_as_ret.u.ret;
18710679
JG
1406error:
1407 return ret;
60b6c79c
MD
1408}
1409
90e535ef 1410LTTNG_HIDDEN
e11d277b 1411int run_as_mkdir(const char *path, mode_t mode, uid_t uid, gid_t gid)
60b6c79c 1412{
18710679
JG
1413 return run_as_mkdirat(AT_FDCWD, path, mode, uid, gid);
1414}
1415
1416LTTNG_HIDDEN
1417int run_as_mkdirat(int dirfd, const char *path, mode_t mode,
1418 uid_t uid, gid_t gid)
1419{
1420 int ret;
93bed9fe
JG
1421 struct run_as_data data = {};
1422 struct run_as_ret run_as_ret = {};
fe9f7760 1423
18710679
JG
1424 DBG3("mkdirat() recursive fd = %d%s, path = %s, mode = %d, uid = %d, gid = %d",
1425 dirfd, dirfd == AT_FDCWD ? " (AT_FDCWD)" : "",
08797918 1426 path, (int) mode, (int) uid, (int) gid);
93bed9fe
JG
1427 ret = lttng_strncpy(data.u.mkdir.path, path,
1428 sizeof(data.u.mkdir.path));
18710679
JG
1429 if (ret) {
1430 ERR("Failed to copy path argument of mkdirat command");
1431 goto error;
1432 }
93bed9fe
JG
1433 data.u.mkdir.path[sizeof(data.u.mkdir.path) - 1] = '\0';
1434 data.u.mkdir.mode = mode;
1435 data.u.mkdir.dirfd = dirfd;
18710679
JG
1436 run_as(dirfd == AT_FDCWD ? RUN_AS_MKDIR : RUN_AS_MKDIRAT,
1437 &data, &run_as_ret, uid, gid);
1438 errno = run_as_ret._errno;
93bed9fe 1439 ret = run_as_ret.u.ret;
18710679
JG
1440error:
1441 return ret;
60b6c79c
MD
1442}
1443
90e535ef 1444LTTNG_HIDDEN
2912cead
JG
1445int run_as_open(const char *path, int flags, mode_t mode, uid_t uid,
1446 gid_t gid)
1447{
1448 return run_as_openat(AT_FDCWD, path, flags, mode, uid, gid);
1449}
1450
1451LTTNG_HIDDEN
1452int run_as_openat(int dirfd, const char *path, int flags, mode_t mode,
1453 uid_t uid, gid_t gid)
60b6c79c 1454{
93bed9fe
JG
1455 int ret;
1456 struct run_as_data data = {};
1457 struct run_as_ret run_as_ret = {};
fe9f7760 1458
2912cead
JG
1459 DBG3("openat() fd = %d%s, path = %s, flags = %X, mode = %d, uid %d, gid %d",
1460 dirfd, dirfd == AT_FDCWD ? " (AT_FDCWD)" : "",
08797918 1461 path, flags, (int) mode, (int) uid, (int) gid);
93bed9fe
JG
1462 ret = lttng_strncpy(data.u.open.path, path, sizeof(data.u.open.path));
1463 if (ret) {
1464 ERR("Failed to copy path argument of open command");
1465 goto error;
1466 }
7567352f
MD
1467 data.u.open.flags = flags;
1468 data.u.open.mode = mode;
93bed9fe 1469 data.u.open.dirfd = dirfd;
2912cead 1470 run_as(dirfd == AT_FDCWD ? RUN_AS_OPEN : RUN_AS_OPENAT,
93bed9fe
JG
1471 &data, &run_as_ret, uid, gid);
1472 errno = run_as_ret._errno;
1473 ret = run_as_ret.u.ret < 0 ? run_as_ret.u.ret :
1474 run_as_ret.u.open.fd;
1475error:
1476 return ret;
60b6c79c 1477}
4628484a
MD
1478
1479LTTNG_HIDDEN
1480int run_as_unlink(const char *path, uid_t uid, gid_t gid)
2912cead
JG
1481{
1482 return run_as_unlinkat(AT_FDCWD, path, uid, gid);
1483}
1484
1485LTTNG_HIDDEN
1486int run_as_unlinkat(int dirfd, const char *path, uid_t uid, gid_t gid)
4628484a 1487{
93bed9fe
JG
1488 int ret;
1489 struct run_as_data data = {};
1490 struct run_as_ret run_as_ret = {};
fe9f7760 1491
2912cead
JG
1492 DBG3("unlinkat() fd = %d%s, path = %s, uid = %d, gid = %d",
1493 dirfd, dirfd == AT_FDCWD ? " (AT_FDCWD)" : "",
08797918 1494 path, (int) uid, (int) gid);
93bed9fe
JG
1495 ret = lttng_strncpy(data.u.unlink.path, path,
1496 sizeof(data.u.unlink.path));
1497 if (ret) {
1498 goto error;
1499 }
1500 data.u.unlink.dirfd = dirfd;
1501 run_as(dirfd == AT_FDCWD ? RUN_AS_UNLINK : RUN_AS_UNLINKAT, &data,
1502 &run_as_ret, uid, gid);
1503 errno = run_as_ret._errno;
1504 ret = run_as_ret.u.ret;
1505error:
1506 return ret;
1507}
1508
1509LTTNG_HIDDEN
1510int run_as_rmdir(const char *path, uid_t uid, gid_t gid)
1511{
1512 return run_as_rmdirat(AT_FDCWD, path, uid, gid);
1513}
1514
1515LTTNG_HIDDEN
1516int run_as_rmdirat(int dirfd, const char *path, uid_t uid, gid_t gid)
1517{
1518 int ret;
1519 struct run_as_data data = {};
1520 struct run_as_ret run_as_ret = {};
1521
1522 DBG3("rmdirat() fd = %d%s, path = %s, uid = %d, gid = %d",
1523 dirfd, dirfd == AT_FDCWD ? " (AT_FDCWD)" : "",
1524 path, (int) uid, (int) gid);
1525 ret = lttng_strncpy(data.u.rmdir.path, path,
1526 sizeof(data.u.rmdir.path));
1527 if (ret) {
1528 goto error;
1529 }
1530 data.u.rmdir.dirfd = dirfd;
1531 run_as(dirfd == AT_FDCWD ? RUN_AS_RMDIR : RUN_AS_RMDIRAT, &data,
1532 &run_as_ret, uid, gid);
1533 errno = run_as_ret._errno;
1534 ret = run_as_ret.u.ret;
1535error:
1536 return ret;
4628484a
MD
1537}
1538
1539LTTNG_HIDDEN
7567352f 1540int run_as_rmdir_recursive(const char *path, uid_t uid, gid_t gid)
4628484a 1541{
93bed9fe
JG
1542 return run_as_rmdirat_recursive(AT_FDCWD, path, uid, gid);
1543}
fe9f7760 1544
93bed9fe
JG
1545LTTNG_HIDDEN
1546int run_as_rmdirat_recursive(int dirfd, const char *path, uid_t uid, gid_t gid)
1547{
1548 int ret;
1549 struct run_as_data data = {};
1550 struct run_as_ret run_as_ret = {};
4628484a 1551
93bed9fe
JG
1552 DBG3("rmdirat() recursive fd = %d%s, path = %s, uid = %d, gid = %d",
1553 dirfd, dirfd == AT_FDCWD ? " (AT_FDCWD)" : "",
08797918 1554 path, (int) uid, (int) gid);
93bed9fe
JG
1555 ret = lttng_strncpy(data.u.rmdir.path, path,
1556 sizeof(data.u.rmdir.path));
1557 if (ret) {
1558 goto error;
1559 }
1560 data.u.rmdir.dirfd = dirfd;
1561 run_as(dirfd == AT_FDCWD ? RUN_AS_RMDIR_RECURSIVE : RUN_AS_RMDIRAT_RECURSIVE,
1562 &data, &run_as_ret, uid, gid);
1563 errno = run_as_ret._errno;
1564 ret = run_as_ret.u.ret;
1565error:
1566 return ret;
1567}
1568
1569LTTNG_HIDDEN
1570int run_as_rename(const char *old, const char *new, uid_t uid, gid_t gid)
1571{
1572 return run_as_renameat(AT_FDCWD, old, AT_FDCWD, new, uid, gid);
1573}
1574
1575LTTNG_HIDDEN
1576int run_as_renameat(int old_dirfd, const char *old_name,
1577 int new_dirfd, const char *new_name, uid_t uid, gid_t gid)
1578{
1579 int ret;
1580 struct run_as_data data = {};
1581 struct run_as_ret run_as_ret = {};
1582
1583 DBG3("renameat() old_dirfd = %d%s, old_name = %s, new_dirfd = %d%s, new_name = %s, uid = %d, gid = %d",
1584 old_dirfd, old_dirfd == AT_FDCWD ? " (AT_FDCWD)" : "",
1585 old_name,
1586 new_dirfd, new_dirfd == AT_FDCWD ? " (AT_FDCWD)" : "",
1587 new_name, (int) uid, (int) gid);
1588 ret = lttng_strncpy(data.u.rename.old_path, old_name,
1589 sizeof(data.u.rename.old_path));
1590 if (ret) {
1591 goto error;
1592 }
1593 ret = lttng_strncpy(data.u.rename.new_path, new_name,
1594 sizeof(data.u.rename.new_path));
1595 if (ret) {
1596 goto error;
1597 }
1598
1599 data.u.rename.dirfds[0] = old_dirfd;
1600 data.u.rename.dirfds[1] = new_dirfd;
1601 run_as(old_dirfd == AT_FDCWD && new_dirfd == AT_FDCWD ?
1602 RUN_AS_RENAME : RUN_AS_RENAMEAT,
1603 &data, &run_as_ret, uid, gid);
1604 errno = run_as_ret._errno;
1605 ret = run_as_ret.u.ret;
1606error:
1607 return ret;
7567352f
MD
1608}
1609
241e0a5a
FD
1610LTTNG_HIDDEN
1611int run_as_extract_elf_symbol_offset(int fd, const char* function,
1612 uid_t uid, gid_t gid, uint64_t *offset)
1613{
93bed9fe
JG
1614 int ret;
1615 struct run_as_data data = {};
1616 struct run_as_ret run_as_ret = {};
f726677b 1617
241e0a5a 1618 DBG3("extract_elf_symbol_offset() on fd=%d and function=%s "
93bed9fe
JG
1619 "with for uid %d and gid %d", fd, function,
1620 (int) uid, (int) gid);
241e0a5a 1621
93bed9fe 1622 data.u.extract_elf_symbol_offset.fd = fd;
241e0a5a
FD
1623
1624 strncpy(data.u.extract_elf_symbol_offset.function, function, LTTNG_SYMBOL_NAME_LEN - 1);
241e0a5a 1625 data.u.extract_elf_symbol_offset.function[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
93bed9fe
JG
1626 ret = lttng_strncpy(data.u.extract_elf_symbol_offset.function,
1627 function,
1628 sizeof(data.u.extract_elf_symbol_offset.function));
1629 if (ret) {
1630 goto error;
1631 }
241e0a5a 1632
93bed9fe
JG
1633 run_as(RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET, &data, &run_as_ret, uid, gid);
1634 errno = run_as_ret._errno;
1635 if (run_as_ret._error) {
1636 ret = -1;
1637 goto error;
241e0a5a
FD
1638 }
1639
93bed9fe
JG
1640 *offset = run_as_ret.u.extract_elf_symbol_offset.offset;
1641error:
1642 return ret;
241e0a5a
FD
1643}
1644
0ef03255
FD
1645LTTNG_HIDDEN
1646int run_as_extract_sdt_probe_offsets(int fd, const char* provider_name,
1647 const char* probe_name, uid_t uid, gid_t gid,
1648 uint64_t **offsets, uint32_t *num_offset)
1649{
93bed9fe
JG
1650 int ret;
1651 struct run_as_data data = {};
1652 struct run_as_ret run_as_ret = {};
f726677b 1653
0ef03255 1654 DBG3("extract_sdt_probe_offsets() on fd=%d, probe_name=%s and "
93bed9fe
JG
1655 "provider_name=%s with for uid %d and gid %d", fd,
1656 probe_name, provider_name, (int) uid, (int) gid);
0ef03255 1657
93bed9fe 1658 data.u.extract_sdt_probe_offsets.fd = fd;
0ef03255 1659
93bed9fe
JG
1660 ret = lttng_strncpy(data.u.extract_sdt_probe_offsets.probe_name, probe_name,
1661 sizeof(data.u.extract_sdt_probe_offsets.probe_name));
1662 if (ret) {
1663 goto error;
1664 }
1665 ret = lttng_strncpy(data.u.extract_sdt_probe_offsets.provider_name,
1666 provider_name,
1667 sizeof(data.u.extract_sdt_probe_offsets.provider_name));
1668 if (ret) {
1669 goto error;
0ef03255
FD
1670 }
1671
93bed9fe
JG
1672 run_as(RUN_AS_EXTRACT_SDT_PROBE_OFFSETS, &data, &run_as_ret, uid, gid);
1673 errno = run_as_ret._errno;
1674 if (run_as_ret._error) {
1675 ret = -1;
1676 goto error;
1677 }
0ef03255 1678
93bed9fe 1679 *num_offset = run_as_ret.u.extract_sdt_probe_offsets.num_offset;
0ef03255
FD
1680 *offsets = zmalloc(*num_offset * sizeof(uint64_t));
1681 if (!*offsets) {
93bed9fe
JG
1682 ret = -ENOMEM;
1683 goto error;
0ef03255
FD
1684 }
1685
93bed9fe
JG
1686 memcpy(*offsets, run_as_ret.u.extract_sdt_probe_offsets.offsets,
1687 *num_offset * sizeof(uint64_t));
1688error:
1689 return ret;
0ef03255
FD
1690}
1691
7567352f 1692LTTNG_HIDDEN
929f71ec
JG
1693int run_as_create_worker(const char *procname,
1694 post_fork_cleanup_cb clean_up_func,
1695 void *clean_up_user_data)
7567352f 1696{
8fec83ea 1697 int ret;
7567352f 1698
749b7a0c 1699 pthread_mutex_lock(&worker_lock);
929f71ec
JG
1700 ret = run_as_create_worker_no_lock(procname, clean_up_func,
1701 clean_up_user_data);
749b7a0c 1702 pthread_mutex_unlock(&worker_lock);
7567352f
MD
1703 return ret;
1704}
1705
1706LTTNG_HIDDEN
1707void run_as_destroy_worker(void)
1708{
749b7a0c 1709 pthread_mutex_lock(&worker_lock);
a01c682b 1710 run_as_destroy_worker_no_lock();
749b7a0c 1711 pthread_mutex_unlock(&worker_lock);
4628484a 1712}
This page took 0.126381 seconds and 4 git commands to generate.