tests: Use `--no-wait` when destroying sessions in relayd-grouping
[lttng-tools.git] / src / common / runas.cpp
CommitLineData
60b6c79c 1/*
21cf9b6b 2 * Copyright (C) 2011 EfficiOS Inc.
ab5be9fa
MJ
3 * Copyright (C) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 * Copyright (C) 2019 Jérémie Galarneau <jeremie.galarneau@efficios.com>
60b6c79c 5 *
c922647d 6 * SPDX-License-Identifier: LGPL-2.1-only
60b6c79c 7 *
60b6c79c
MD
8 */
9
6c1c0768 10#define _LGPL_SOURCE
28ab034a
JG
11#include "runas.hpp"
12
13#include <common/bytecode/bytecode.hpp>
14#include <common/common.hpp>
15#include <common/compat/errno.hpp>
16#include <common/compat/getenv.hpp>
17#include <common/compat/string.hpp>
18#include <common/defaults.hpp>
19#include <common/filter/filter-ast.hpp>
20#include <common/lttng-elf.hpp>
21#include <common/lttng-kernel.hpp>
22#include <common/sessiond-comm/sessiond-comm.hpp>
23#include <common/thread.hpp>
24#include <common/unix.hpp>
25#include <common/utils.hpp>
26
27#include <lttng/constant.h>
28
37ccf8ec
FD
29#include <fcntl.h>
30#include <grp.h>
60b6c79c 31#include <limits.h>
37ccf8ec
FD
32#include <pwd.h>
33#include <sched.h>
34#include <signal.h>
60b6c79c
MD
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
60b6c79c 38#include <sys/stat.h>
37ccf8ec
FD
39#include <sys/types.h>
40#include <sys/wait.h>
60b6c79c 41#include <unistd.h>
60b6c79c 42
37ccf8ec
FD
43#define GETPW_BUFFER_FALLBACK_SIZE 4096
44
93bed9fe
JG
45enum run_as_cmd {
46 RUN_AS_MKDIR,
47 RUN_AS_MKDIRAT,
48 RUN_AS_MKDIR_RECURSIVE,
49 RUN_AS_MKDIRAT_RECURSIVE,
50 RUN_AS_OPEN,
51 RUN_AS_OPENAT,
52 RUN_AS_UNLINK,
53 RUN_AS_UNLINKAT,
54 RUN_AS_RMDIR,
55 RUN_AS_RMDIRAT,
56 RUN_AS_RMDIR_RECURSIVE,
57 RUN_AS_RMDIRAT_RECURSIVE,
58 RUN_AS_RENAME,
59 RUN_AS_RENAMEAT,
60 RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET,
61 RUN_AS_EXTRACT_SDT_PROBE_OFFSETS,
c73f064a 62 RUN_AS_GENERATE_FILTER_BYTECODE,
60b6c79c
MD
63};
64
f1494934
JG
65namespace {
66struct run_as_data;
67struct run_as_ret;
e665dfbc 68using run_as_fct = int (*)(struct run_as_data *, struct run_as_ret *);
f1494934 69
93bed9fe
JG
70struct run_as_mkdir_data {
71 int dirfd;
72 char path[LTTNG_PATH_MAX];
73 mode_t mode;
74} LTTNG_PACKED;
75
e11d277b 76struct run_as_open_data {
93bed9fe
JG
77 int dirfd;
78 char path[LTTNG_PATH_MAX];
60b6c79c
MD
79 int flags;
80 mode_t mode;
93bed9fe 81} LTTNG_PACKED;
60b6c79c 82
4628484a 83struct run_as_unlink_data {
93bed9fe
JG
84 int dirfd;
85 char path[LTTNG_PATH_MAX];
86} LTTNG_PACKED;
4628484a 87
93bed9fe
JG
88struct run_as_rmdir_data {
89 int dirfd;
90 char path[LTTNG_PATH_MAX];
c73f064a 91 int flags; /* enum lttng_directory_handle_rmdir_recursive_flags. */
93bed9fe 92} LTTNG_PACKED;
7567352f 93
241e0a5a 94struct run_as_extract_elf_symbol_offset_data {
93bed9fe 95 int fd;
241e0a5a 96 char function[LTTNG_SYMBOL_NAME_LEN];
93bed9fe 97} LTTNG_PACKED;
241e0a5a 98
0ef03255 99struct run_as_extract_sdt_probe_offsets_data {
93bed9fe 100 int fd;
0ef03255
FD
101 char probe_name[LTTNG_SYMBOL_NAME_LEN];
102 char provider_name[LTTNG_SYMBOL_NAME_LEN];
93bed9fe 103} LTTNG_PACKED;
0ef03255 104
c73f064a
JR
105struct run_as_generate_filter_bytecode_data {
106 char filter_expression[LTTNG_FILTER_MAX_LEN];
107} LTTNG_PACKED;
108
93bed9fe
JG
109struct run_as_rename_data {
110 /*
111 * [0] = old_dirfd
112 * [1] = new_dirfd
113 */
114 int dirfds[2];
115 char old_path[LTTNG_PATH_MAX];
116 char new_path[LTTNG_PATH_MAX];
117} LTTNG_PACKED;
fe9f7760
FD
118
119struct run_as_open_ret {
93bed9fe
JG
120 int fd;
121} LTTNG_PACKED;
fe9f7760 122
241e0a5a
FD
123struct run_as_extract_elf_symbol_offset_ret {
124 uint64_t offset;
93bed9fe 125} LTTNG_PACKED;
241e0a5a 126
0ef03255
FD
127struct run_as_extract_sdt_probe_offsets_ret {
128 uint32_t num_offset;
b8e2fb80 129 uint64_t offsets[LTTNG_KERNEL_ABI_MAX_UPROBE_NUM];
93bed9fe 130} LTTNG_PACKED;
7567352f 131
c73f064a
JR
132struct run_as_generate_filter_bytecode_ret {
133 /* A lttng_bytecode_filter struct with 'dynamic' payload. */
134 char bytecode[LTTNG_FILTER_MAX_LEN];
135} LTTNG_PACKED;
136
7567352f
MD
137struct run_as_data {
138 enum run_as_cmd cmd;
139 union {
93bed9fe 140 struct run_as_mkdir_data mkdir;
7567352f
MD
141 struct run_as_open_data open;
142 struct run_as_unlink_data unlink;
93bed9fe
JG
143 struct run_as_rmdir_data rmdir;
144 struct run_as_rename_data rename;
241e0a5a 145 struct run_as_extract_elf_symbol_offset_data extract_elf_symbol_offset;
0ef03255 146 struct run_as_extract_sdt_probe_offsets_data extract_sdt_probe_offsets;
c73f064a 147 struct run_as_generate_filter_bytecode_data generate_filter_bytecode;
7567352f
MD
148 } u;
149 uid_t uid;
150 gid_t gid;
93bed9fe 151} LTTNG_PACKED;
4628484a 152
fe9f7760
FD
153/*
154 * The run_as_ret structure holds the returned value and status of the command.
155 *
156 * The `u` union field holds the return value of the command; in most cases it
157 * represents the success or the failure of the command. In more complex
158 * commands, it holds a computed value.
159 *
160 * The _errno field is the errno recorded after the execution of the command.
161 *
162 * The _error fields is used the signify that return status of the command. For
163 * simple commands returning `int` the _error field will be the same as the
164 * ret_int field. In complex commands, it signify the success or failure of the
165 * command.
166 *
167 */
df5b86c8 168struct run_as_ret {
fe9f7760 169 union {
93bed9fe 170 int ret;
fe9f7760 171 struct run_as_open_ret open;
241e0a5a 172 struct run_as_extract_elf_symbol_offset_ret extract_elf_symbol_offset;
0ef03255 173 struct run_as_extract_sdt_probe_offsets_ret extract_sdt_probe_offsets;
c73f064a 174 struct run_as_generate_filter_bytecode_ret generate_filter_bytecode;
fe9f7760 175 } u;
df5b86c8 176 int _errno;
fe9f7760 177 bool _error;
93bed9fe
JG
178} LTTNG_PACKED;
179
5c7248cd
JG
180#define COMMAND_IN_FDS(data_ptr) \
181 ({ \
182 int *fds = NULL; \
183 if (command_properties[(data_ptr)->cmd].in_fds_offset != -1) { \
184 fds = (int *) ((char *) (data_ptr) + \
185 command_properties[(data_ptr)->cmd].in_fds_offset); \
186 } \
187 fds; \
28ab034a
JG
188 })
189
5c7248cd
JG
190#define COMMAND_OUT_FDS(cmd, ret_ptr) \
191 ({ \
192 int *fds = NULL; \
193 if (command_properties[cmd].out_fds_offset != -1) { \
194 fds = (int *) ((char *) (ret_ptr) + \
195 command_properties[cmd].out_fds_offset); \
196 } \
197 fds; \
28ab034a
JG
198 })
199
5c7248cd 200#define COMMAND_IN_FD_COUNT(data_ptr) ({ command_properties[(data_ptr)->cmd].in_fd_count; })
28ab034a
JG
201
202#define COMMAND_OUT_FD_COUNT(cmd) ({ command_properties[cmd].out_fd_count; })
93bed9fe 203
5c7248cd 204#define COMMAND_USE_CWD_FD(data_ptr) command_properties[(data_ptr)->cmd].use_cwd_fd
93bed9fe
JG
205
206struct run_as_command_properties {
207 /* Set to -1 when not applicable. */
208 ptrdiff_t in_fds_offset, out_fds_offset;
209 unsigned int in_fd_count, out_fd_count;
210 bool use_cwd_fd;
211};
212
f1494934 213const struct run_as_command_properties command_properties[] = {
a6bc4ca9 214 {
93bed9fe 215 .in_fds_offset = offsetof(struct run_as_data, u.mkdir.dirfd),
93bed9fe 216 .out_fds_offset = -1,
a6bc4ca9 217 .in_fd_count = 1,
93bed9fe
JG
218 .out_fd_count = 0,
219 .use_cwd_fd = true,
220 },
a6bc4ca9 221 {
93bed9fe 222 .in_fds_offset = offsetof(struct run_as_data, u.mkdir.dirfd),
93bed9fe 223 .out_fds_offset = -1,
a6bc4ca9 224 .in_fd_count = 1,
93bed9fe
JG
225 .out_fd_count = 0,
226 .use_cwd_fd = false,
227 },
a6bc4ca9 228 {
93bed9fe 229 .in_fds_offset = offsetof(struct run_as_data, u.mkdir.dirfd),
93bed9fe 230 .out_fds_offset = -1,
a6bc4ca9 231 .in_fd_count = 1,
93bed9fe
JG
232 .out_fd_count = 0,
233 .use_cwd_fd = true,
234 },
a6bc4ca9 235 {
93bed9fe 236 .in_fds_offset = offsetof(struct run_as_data, u.mkdir.dirfd),
93bed9fe 237 .out_fds_offset = -1,
a6bc4ca9 238 .in_fd_count = 1,
93bed9fe
JG
239 .out_fd_count = 0,
240 .use_cwd_fd = false,
241 },
a6bc4ca9 242 {
93bed9fe 243 .in_fds_offset = offsetof(struct run_as_data, u.open.dirfd),
93bed9fe 244 .out_fds_offset = offsetof(struct run_as_ret, u.open.fd),
a6bc4ca9 245 .in_fd_count = 1,
93bed9fe
JG
246 .out_fd_count = 1,
247 .use_cwd_fd = true,
248 },
a6bc4ca9 249 {
93bed9fe 250 .in_fds_offset = offsetof(struct run_as_data, u.open.dirfd),
93bed9fe 251 .out_fds_offset = offsetof(struct run_as_ret, u.open.fd),
a6bc4ca9 252 .in_fd_count = 1,
93bed9fe
JG
253 .out_fd_count = 1,
254 .use_cwd_fd = false,
255 },
a6bc4ca9 256 {
93bed9fe 257 .in_fds_offset = offsetof(struct run_as_data, u.unlink.dirfd),
93bed9fe 258 .out_fds_offset = -1,
a6bc4ca9 259 .in_fd_count = 1,
93bed9fe
JG
260 .out_fd_count = 0,
261 .use_cwd_fd = true,
262 },
a6bc4ca9 263 {
93bed9fe 264 .in_fds_offset = offsetof(struct run_as_data, u.unlink.dirfd),
93bed9fe 265 .out_fds_offset = -1,
a6bc4ca9 266 .in_fd_count = 1,
93bed9fe
JG
267 .out_fd_count = 0,
268 .use_cwd_fd = false,
269 },
a6bc4ca9 270 {
93bed9fe 271 .in_fds_offset = offsetof(struct run_as_data, u.rmdir.dirfd),
93bed9fe 272 .out_fds_offset = -1,
a6bc4ca9 273 .in_fd_count = 1,
93bed9fe
JG
274 .out_fd_count = 0,
275 .use_cwd_fd = true,
276 },
a6bc4ca9 277 {
93bed9fe 278 .in_fds_offset = offsetof(struct run_as_data, u.rmdir.dirfd),
93bed9fe 279 .out_fds_offset = -1,
a6bc4ca9 280 .in_fd_count = 1,
93bed9fe
JG
281 .out_fd_count = 0,
282 .use_cwd_fd = false,
283 },
a6bc4ca9 284 {
93bed9fe 285 .in_fds_offset = offsetof(struct run_as_data, u.rmdir.dirfd),
93bed9fe 286 .out_fds_offset = -1,
a6bc4ca9 287 .in_fd_count = 1,
93bed9fe
JG
288 .out_fd_count = 0,
289 .use_cwd_fd = true,
290 },
a6bc4ca9 291 {
93bed9fe 292 .in_fds_offset = offsetof(struct run_as_data, u.rmdir.dirfd),
93bed9fe 293 .out_fds_offset = -1,
a6bc4ca9 294 .in_fd_count = 1,
93bed9fe
JG
295 .out_fd_count = 0,
296 .use_cwd_fd = false,
297 },
a6bc4ca9 298 {
93bed9fe 299 .in_fds_offset = offsetof(struct run_as_data, u.rename.dirfds),
93bed9fe 300 .out_fds_offset = -1,
a6bc4ca9 301 .in_fd_count = 2,
93bed9fe
JG
302 .out_fd_count = 0,
303 .use_cwd_fd = true,
304 },
a6bc4ca9 305 {
93bed9fe 306 .in_fds_offset = offsetof(struct run_as_data, u.rename.dirfds),
93bed9fe 307 .out_fds_offset = -1,
a6bc4ca9 308 .in_fd_count = 2,
93bed9fe
JG
309 .out_fd_count = 0,
310 .use_cwd_fd = false,
311 },
a6bc4ca9 312 {
28ab034a 313 .in_fds_offset = offsetof(struct run_as_data, u.extract_elf_symbol_offset.fd),
93bed9fe 314 .out_fds_offset = -1,
a6bc4ca9 315 .in_fd_count = 1,
93bed9fe
JG
316 .out_fd_count = 0,
317 .use_cwd_fd = false,
318 },
a6bc4ca9 319 {
28ab034a 320 .in_fds_offset = offsetof(struct run_as_data, u.extract_sdt_probe_offsets.fd),
93bed9fe 321 .out_fds_offset = -1,
a6bc4ca9 322 .in_fd_count = 1,
93bed9fe
JG
323 .out_fd_count = 0,
324 .use_cwd_fd = false,
325 },
a6bc4ca9 326 {
c73f064a 327 .in_fds_offset = -1,
c73f064a 328 .out_fds_offset = -1,
a6bc4ca9 329 .in_fd_count = 0,
c73f064a
JR
330 .out_fd_count = 0,
331 .use_cwd_fd = false,
332 },
df5b86c8
MD
333};
334
a6bc4ca9 335struct run_as_worker_data {
28ab034a 336 pid_t pid; /* Worker PID. */
7567352f
MD
337 int sockpair[2];
338 char *procname;
339};
340
341/* Single global worker per process (for now). */
f1494934 342run_as_worker_data *global_worker;
7567352f 343/* Lock protecting the worker. */
f1494934
JG
344pthread_mutex_t worker_lock = PTHREAD_MUTEX_INITIALIZER;
345} /* namespace */
7567352f 346
8f0044bf 347#ifdef VALGRIND
28ab034a 348static int use_clone(void)
8f0044bf
MD
349{
350 return 0;
351}
352#else
cd9adb8b 353static int use_clone()
8f0044bf 354{
e8fa9fb0 355 return !lttng_secure_getenv("LTTNG_DEBUG_NOCLONE");
8f0044bf
MD
356}
357#endif
358
60b6c79c
MD
359/*
360 * Create recursively directory using the FULL path.
361 */
28ab034a 362static int _mkdirat_recursive(struct run_as_data *data, struct run_as_ret *ret_value)
60b6c79c 363{
60b6c79c 364 const char *path;
60b6c79c 365 mode_t mode;
cbf53d23 366 struct lttng_directory_handle *handle;
60b6c79c 367
93bed9fe
JG
368 path = data->u.mkdir.path;
369 mode = data->u.mkdir.mode;
60b6c79c 370
cbf53d23
JG
371 handle = lttng_directory_handle_create_from_dirfd(data->u.mkdir.dirfd);
372 if (!handle) {
373 ret_value->_errno = errno;
374 ret_value->_error = true;
375 ret_value->u.ret = -1;
376 goto end;
377 }
87bbb856 378 /* Ownership of dirfd is transferred to the handle. */
93bed9fe 379 data->u.mkdir.dirfd = -1;
d77dded2 380 /* Safe to call as we have transitioned to the requested uid/gid. */
28ab034a 381 ret_value->u.ret = lttng_directory_handle_create_subdirectory_recursive(handle, path, mode);
fe9f7760 382 ret_value->_errno = errno;
e0252788 383 ret_value->_error = (ret_value->u.ret) != 0;
cbf53d23
JG
384 lttng_directory_handle_put(handle);
385end:
93bed9fe 386 return ret_value->u.ret;
60b6c79c
MD
387}
388
28ab034a 389static int _mkdirat(struct run_as_data *data, struct run_as_ret *ret_value)
60b6c79c 390{
18710679
JG
391 const char *path;
392 mode_t mode;
cbf53d23 393 struct lttng_directory_handle *handle;
18710679 394
93bed9fe
JG
395 path = data->u.mkdir.path;
396 mode = data->u.mkdir.mode;
18710679 397
cbf53d23
JG
398 handle = lttng_directory_handle_create_from_dirfd(data->u.mkdir.dirfd);
399 if (!handle) {
400 ret_value->u.ret = -1;
401 ret_value->_errno = errno;
402 ret_value->_error = true;
403 goto end;
404 }
87bbb856 405 /* Ownership of dirfd is transferred to the handle. */
93bed9fe 406 data->u.mkdir.dirfd = -1;
18710679 407 /* Safe to call as we have transitioned to the requested uid/gid. */
28ab034a 408 ret_value->u.ret = lttng_directory_handle_create_subdirectory(handle, path, mode);
fe9f7760 409 ret_value->_errno = errno;
e0252788 410 ret_value->_error = (ret_value->u.ret) != 0;
cbf53d23
JG
411 lttng_directory_handle_put(handle);
412end:
93bed9fe 413 return ret_value->u.ret;
7567352f 414}
7ce36756 415
28ab034a 416static int _open(struct run_as_data *data, struct run_as_ret *ret_value)
7567352f 417{
93bed9fe 418 int fd;
cbf53d23 419 struct lttng_directory_handle *handle;
93bed9fe 420
cbf53d23
JG
421 handle = lttng_directory_handle_create_from_dirfd(data->u.open.dirfd);
422 if (!handle) {
423 ret_value->_errno = errno;
424 ret_value->_error = true;
425 ret_value->u.ret = -1;
426 goto end;
427 }
93bed9fe
JG
428 /* Ownership of dirfd is transferred to the handle. */
429 data->u.open.dirfd = -1;
430
28ab034a
JG
431 fd = lttng_directory_handle_open_file(
432 handle, data->u.open.path, data->u.open.flags, data->u.open.mode);
93bed9fe
JG
433 if (fd < 0) {
434 ret_value->u.ret = -1;
435 ret_value->u.open.fd = -1;
436 } else {
437 ret_value->u.ret = 0;
438 ret_value->u.open.fd = fd;
439 }
440
fe9f7760 441 ret_value->_errno = errno;
93bed9fe 442 ret_value->_error = fd < 0;
cbf53d23
JG
443 lttng_directory_handle_put(handle);
444end:
93bed9fe 445 return ret_value->u.ret;
7567352f
MD
446}
447
28ab034a 448static int _unlink(struct run_as_data *data, struct run_as_ret *ret_value)
7567352f 449{
cbf53d23 450 struct lttng_directory_handle *handle;
93bed9fe 451
cbf53d23
JG
452 handle = lttng_directory_handle_create_from_dirfd(data->u.unlink.dirfd);
453 if (!handle) {
454 ret_value->u.ret = -1;
455 ret_value->_errno = errno;
456 ret_value->_error = true;
457 goto end;
458 }
93bed9fe
JG
459
460 /* Ownership of dirfd is transferred to the handle. */
461 data->u.unlink.dirfd = -1;
462
28ab034a 463 ret_value->u.ret = lttng_directory_handle_unlink_file(handle, data->u.unlink.path);
93bed9fe 464 ret_value->_errno = errno;
e0252788 465 ret_value->_error = (ret_value->u.ret) != 0;
cbf53d23
JG
466 lttng_directory_handle_put(handle);
467end:
93bed9fe
JG
468 return ret_value->u.ret;
469}
470
28ab034a 471static int _rmdir(struct run_as_data *data, struct run_as_ret *ret_value)
93bed9fe 472{
cbf53d23 473 struct lttng_directory_handle *handle;
93bed9fe 474
cbf53d23
JG
475 handle = lttng_directory_handle_create_from_dirfd(data->u.rmdir.dirfd);
476 if (!handle) {
477 ret_value->u.ret = -1;
478 ret_value->_errno = errno;
479 ret_value->_error = true;
480 goto end;
481 }
93bed9fe
JG
482
483 /* Ownership of dirfd is transferred to the handle. */
484 data->u.rmdir.dirfd = -1;
485
28ab034a 486 ret_value->u.ret = lttng_directory_handle_remove_subdirectory(handle, data->u.rmdir.path);
fe9f7760 487 ret_value->_errno = errno;
e0252788 488 ret_value->_error = (ret_value->u.ret) != 0;
cbf53d23
JG
489 lttng_directory_handle_put(handle);
490end:
93bed9fe 491 return ret_value->u.ret;
60b6c79c
MD
492}
493
28ab034a 494static int _rmdir_recursive(struct run_as_data *data, struct run_as_ret *ret_value)
60b6c79c 495{
cbf53d23 496 struct lttng_directory_handle *handle;
93bed9fe 497
cbf53d23
JG
498 handle = lttng_directory_handle_create_from_dirfd(data->u.rmdir.dirfd);
499 if (!handle) {
500 ret_value->u.ret = -1;
501 ret_value->_errno = errno;
502 ret_value->_error = true;
503 goto end;
504 }
93bed9fe
JG
505
506 /* Ownership of dirfd is transferred to the handle. */
507 data->u.rmdir.dirfd = -1;
508
509 ret_value->u.ret = lttng_directory_handle_remove_subdirectory_recursive(
28ab034a 510 handle, data->u.rmdir.path, data->u.rmdir.flags);
fe9f7760 511 ret_value->_errno = errno;
e0252788 512 ret_value->_error = (ret_value->u.ret) != 0;
cbf53d23
JG
513 lttng_directory_handle_put(handle);
514end:
93bed9fe
JG
515 return ret_value->u.ret;
516}
517
28ab034a 518static int _rename(struct run_as_data *data, struct run_as_ret *ret_value)
93bed9fe
JG
519{
520 const char *old_path, *new_path;
cd9adb8b 521 struct lttng_directory_handle *old_handle = nullptr, *new_handle = nullptr;
93bed9fe
JG
522
523 old_path = data->u.rename.old_path;
524 new_path = data->u.rename.new_path;
525
28ab034a 526 old_handle = lttng_directory_handle_create_from_dirfd(data->u.rename.dirfds[0]);
cbf53d23
JG
527 if (!old_handle) {
528 ret_value->u.ret = -1;
529 goto end;
530 }
28ab034a 531 new_handle = lttng_directory_handle_create_from_dirfd(data->u.rename.dirfds[1]);
cbf53d23
JG
532 if (!new_handle) {
533 ret_value->u.ret = -1;
534 goto end;
535 }
93bed9fe
JG
536
537 /* Ownership of dirfds are transferred to the handles. */
538 data->u.rename.dirfds[0] = data->u.rename.dirfds[1] = -1;
539
540 /* Safe to call as we have transitioned to the requested uid/gid. */
28ab034a
JG
541 ret_value->u.ret =
542 lttng_directory_handle_rename(old_handle, old_path, new_handle, new_path);
cbf53d23
JG
543end:
544 lttng_directory_handle_put(old_handle);
545 lttng_directory_handle_put(new_handle);
93bed9fe 546 ret_value->_errno = errno;
e0252788 547 ret_value->_error = (ret_value->u.ret) != 0;
93bed9fe 548 return ret_value->u.ret;
7567352f 549}
df5b86c8 550
b1b34226 551#ifdef HAVE_ELF_H
28ab034a 552static int _extract_elf_symbol_offset(struct run_as_data *data, struct run_as_ret *ret_value)
241e0a5a
FD
553{
554 int ret = 0;
65eefd4c 555 uint64_t offset;
241e0a5a 556
93bed9fe
JG
557 ret_value->_error = false;
558 ret = lttng_elf_get_symbol_offset(data->u.extract_elf_symbol_offset.fd,
28ab034a
JG
559 data->u.extract_elf_symbol_offset.function,
560 &offset);
241e0a5a
FD
561 if (ret) {
562 DBG("Failed to extract ELF function offset");
563 ret_value->_error = true;
564 }
65eefd4c 565 ret_value->u.extract_elf_symbol_offset.offset = offset;
241e0a5a
FD
566
567 return ret;
568}
569
28ab034a 570static int _extract_sdt_probe_offsets(struct run_as_data *data, struct run_as_ret *ret_value)
0ef03255
FD
571{
572 int ret = 0;
cd9adb8b 573 uint64_t *offsets = nullptr;
0ef03255
FD
574 uint32_t num_offset;
575
576 ret_value->_error = false;
577
578 /* On success, this call allocates the offsets paramater. */
28ab034a
JG
579 ret = lttng_elf_get_sdt_probe_offsets(data->u.extract_sdt_probe_offsets.fd,
580 data->u.extract_sdt_probe_offsets.provider_name,
581 data->u.extract_sdt_probe_offsets.probe_name,
582 &offsets,
583 &num_offset);
0ef03255
FD
584
585 if (ret) {
586 DBG("Failed to extract SDT probe offsets");
587 ret_value->_error = true;
588 goto end;
589 }
590
b8e2fb80 591 if (num_offset <= 0 || num_offset > LTTNG_KERNEL_ABI_MAX_UPROBE_NUM) {
0ef03255
FD
592 DBG("Wrong number of probes.");
593 ret = -1;
594 ret_value->_error = true;
595 goto free_offset;
596 }
597
598 /* Copy the content of the offsets array to the ret struct. */
599 memcpy(ret_value->u.extract_sdt_probe_offsets.offsets,
28ab034a
JG
600 offsets,
601 num_offset * sizeof(uint64_t));
0ef03255
FD
602
603 ret_value->u.extract_sdt_probe_offsets.num_offset = num_offset;
604
605free_offset:
606 free(offsets);
607end:
608 return ret;
609}
b1b34226 610#else
28ab034a
JG
611static int _extract_elf_symbol_offset(struct run_as_data *data __attribute__((unused)),
612 struct run_as_ret *ret_value __attribute__((unused)))
b1b34226
MJ
613{
614 ERR("Unimplemented runas command RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET");
615 return -1;
616}
617
28ab034a
JG
618static int _extract_sdt_probe_offsets(struct run_as_data *data __attribute__((unused)),
619 struct run_as_ret *ret_value __attribute__((unused)))
b1b34226
MJ
620{
621 ERR("Unimplemented runas command RUN_AS_EXTRACT_SDT_PROBE_OFFSETS");
622 return -1;
623}
624#endif
241e0a5a 625
28ab034a
JG
626static int _generate_filter_bytecode(struct run_as_data *data, struct run_as_ret *ret_value)
627{
c73f064a 628 int ret = 0;
cd9adb8b
JG
629 const char *filter_expression = nullptr;
630 struct filter_parser_ctx *ctx = nullptr;
c73f064a
JR
631
632 ret_value->_error = false;
633
634 filter_expression = data->u.generate_filter_bytecode.filter_expression;
635
28ab034a
JG
636 if (lttng_strnlen(filter_expression, LTTNG_FILTER_MAX_LEN - 1) ==
637 LTTNG_FILTER_MAX_LEN - 1) {
c73f064a
JR
638 ret_value->_error = true;
639 ret = -1;
640 goto end;
641 }
642
643 ret = filter_parser_ctx_create_from_filter_expression(filter_expression, &ctx);
644 if (ret < 0) {
645 ret_value->_error = true;
646 ret = -1;
647 goto end;
648 }
649
28ab034a 650 DBG("Size of bytecode generated: %u bytes.", bytecode_get_len(&ctx->bytecode->b));
c73f064a
JR
651
652 /* Copy the lttng_bytecode_filter object to the return structure. */
653 memcpy(ret_value->u.generate_filter_bytecode.bytecode,
28ab034a
JG
654 &ctx->bytecode->b,
655 sizeof(ctx->bytecode->b) + bytecode_get_len(&ctx->bytecode->b));
c73f064a
JR
656
657end:
658 if (ctx) {
659 filter_bytecode_free(ctx);
660 filter_ir_free(ctx);
661 filter_parser_ctx_free(ctx);
662 }
663
664 return ret;
665}
28ab034a 666static run_as_fct run_as_enum_to_fct(enum run_as_cmd cmd)
7567352f
MD
667{
668 switch (cmd) {
669 case RUN_AS_MKDIR:
18710679
JG
670 case RUN_AS_MKDIRAT:
671 return _mkdirat;
672 case RUN_AS_MKDIR_RECURSIVE:
673 case RUN_AS_MKDIRAT_RECURSIVE:
674 return _mkdirat_recursive;
7567352f 675 case RUN_AS_OPEN:
2912cead 676 case RUN_AS_OPENAT:
7567352f
MD
677 return _open;
678 case RUN_AS_UNLINK:
2912cead 679 case RUN_AS_UNLINKAT:
7567352f 680 return _unlink;
93bed9fe
JG
681 case RUN_AS_RMDIR:
682 case RUN_AS_RMDIRAT:
683 return _rmdir;
7567352f 684 case RUN_AS_RMDIR_RECURSIVE:
93bed9fe 685 case RUN_AS_RMDIRAT_RECURSIVE:
7567352f 686 return _rmdir_recursive;
93bed9fe
JG
687 case RUN_AS_RENAME:
688 case RUN_AS_RENAMEAT:
689 return _rename;
241e0a5a
FD
690 case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET:
691 return _extract_elf_symbol_offset;
0ef03255
FD
692 case RUN_AS_EXTRACT_SDT_PROBE_OFFSETS:
693 return _extract_sdt_probe_offsets;
c73f064a
JR
694 case RUN_AS_GENERATE_FILTER_BYTECODE:
695 return _generate_filter_bytecode;
7567352f 696 default:
62a7b8ed 697 ERR("Unknown command %d", (int) cmd);
cd9adb8b 698 return nullptr;
7567352f 699 }
60b6c79c
MD
700}
701
28ab034a 702static int do_send_fds(int sock, const int *fds, unsigned int fd_count)
4628484a 703{
7567352f 704 ssize_t len;
93bed9fe
JG
705 unsigned int i;
706
707 for (i = 0; i < fd_count; i++) {
708 if (fds[i] < 0) {
28ab034a 709 DBG("Attempt to send invalid file descriptor (fd = %i)", fds[i]);
93bed9fe
JG
710 /* Return 0 as this is not a fatal error. */
711 return 0;
712 }
4a76dfd3 713 }
4628484a 714
4a76dfd3 715 len = lttcomm_send_fds_unix_sock(sock, fds, fd_count);
93bed9fe 716 return len < 0 ? -1 : 0;
4628484a
MD
717}
718
28ab034a 719static int do_recv_fds(int sock, int *fds, unsigned int fd_count)
4628484a 720{
93bed9fe
JG
721 int ret = 0;
722 unsigned int i;
7567352f 723 ssize_t len;
4628484a 724
93bed9fe
JG
725 len = lttcomm_recv_fds_unix_sock(sock, fds, fd_count);
726 if (len == 0) {
727 ret = -1;
728 goto end;
da9ee832 729 } else if (len < 0) {
93bed9fe
JG
730 PERROR("Failed to receive file descriptors from socket");
731 ret = -1;
732 goto end;
ca9eb994
JG
733 }
734
93bed9fe
JG
735 for (i = 0; i < fd_count; i++) {
736 if (fds[i] < 0) {
737 ERR("Invalid file descriptor received from worker (fd = %i)", fds[i]);
738 /* Return 0 as this is not a fatal error. */
739 }
55cb0d6f 740 }
93bed9fe 741end:
55cb0d6f 742 return ret;
4628484a
MD
743}
744
28ab034a 745static int send_fds_to_worker(const run_as_worker_data *worker, const struct run_as_data *data)
fe9f7760
FD
746{
747 int ret = 0;
93bed9fe 748 unsigned int i;
fe9f7760 749
93bed9fe
JG
750 if (COMMAND_USE_CWD_FD(data) || COMMAND_IN_FD_COUNT(data) == 0) {
751 goto end;
fe9f7760
FD
752 }
753
93bed9fe
JG
754 for (i = 0; i < COMMAND_IN_FD_COUNT(data); i++) {
755 if (COMMAND_IN_FDS(data)[i] < 0) {
756 ERR("Refusing to send invalid fd to worker (fd = %i)",
28ab034a 757 COMMAND_IN_FDS(data)[i]);
93bed9fe
JG
758 ret = -1;
759 goto end;
760 }
55cb0d6f 761 }
ca9eb994 762
28ab034a 763 ret = do_send_fds(worker->sockpair[0], COMMAND_IN_FDS(data), COMMAND_IN_FD_COUNT(data));
fe9f7760 764 if (ret < 0) {
93bed9fe 765 PERROR("Failed to send file descriptor to run-as worker");
fe9f7760 766 ret = -1;
93bed9fe 767 goto end;
fe9f7760 768 }
93bed9fe 769end:
fe9f7760
FD
770 return ret;
771}
772
28ab034a
JG
773static int
774send_fds_to_master(run_as_worker_data *worker, enum run_as_cmd cmd, struct run_as_ret *run_as_ret)
fe9f7760 775{
93bed9fe
JG
776 int ret = 0;
777 unsigned int i;
fe9f7760 778
93bed9fe
JG
779 if (COMMAND_OUT_FD_COUNT(cmd) == 0) {
780 goto end;
fe9f7760
FD
781 }
782
28ab034a
JG
783 ret = do_send_fds(
784 worker->sockpair[1], COMMAND_OUT_FDS(cmd, run_as_ret), COMMAND_OUT_FD_COUNT(cmd));
fe9f7760 785 if (ret < 0) {
93bed9fe
JG
786 PERROR("Failed to send file descriptor to master process");
787 goto end;
fe9f7760
FD
788 }
789
93bed9fe 790 for (i = 0; i < COMMAND_OUT_FD_COUNT(cmd); i++) {
a4c64187
FD
791 int fd = COMMAND_OUT_FDS(cmd, run_as_ret)[i];
792 if (fd >= 0) {
793 int ret_close = close(fd);
794
795 if (ret_close < 0) {
28ab034a 796 PERROR("Failed to close result file descriptor (fd = %i)", fd);
a4c64187 797 }
93bed9fe
JG
798 }
799 }
800end:
fe9f7760
FD
801 return ret;
802}
803
28ab034a
JG
804static int recv_fds_from_worker(const run_as_worker_data *worker,
805 enum run_as_cmd cmd,
806 struct run_as_ret *run_as_ret)
fe9f7760
FD
807{
808 int ret = 0;
809
93bed9fe
JG
810 if (COMMAND_OUT_FD_COUNT(cmd) == 0) {
811 goto end;
fe9f7760
FD
812 }
813
28ab034a
JG
814 ret = do_recv_fds(
815 worker->sockpair[0], COMMAND_OUT_FDS(cmd, run_as_ret), COMMAND_OUT_FD_COUNT(cmd));
fe9f7760 816 if (ret < 0) {
93bed9fe 817 PERROR("Failed to receive file descriptor from run-as worker");
fe9f7760
FD
818 ret = -1;
819 }
93bed9fe 820end:
fe9f7760
FD
821 return ret;
822}
823
28ab034a 824static int recv_fds_from_master(run_as_worker_data *worker, struct run_as_data *data)
fe9f7760
FD
825{
826 int ret = 0;
827
93bed9fe
JG
828 if (COMMAND_USE_CWD_FD(data)) {
829 unsigned int i;
830
831 for (i = 0; i < COMMAND_IN_FD_COUNT(data); i++) {
832 COMMAND_IN_FDS(data)[i] = AT_FDCWD;
833 }
834 goto end;
fe9f7760
FD
835 }
836
c73f064a
JR
837 if (COMMAND_IN_FD_COUNT(data) == 0) {
838 goto end;
839 }
840
28ab034a 841 ret = do_recv_fds(worker->sockpair[1], COMMAND_IN_FDS(data), COMMAND_IN_FD_COUNT(data));
fe9f7760 842 if (ret < 0) {
93bed9fe 843 PERROR("Failed to receive file descriptors from master process");
fe9f7760
FD
844 ret = -1;
845 }
93bed9fe 846end:
fe9f7760
FD
847 return ret;
848}
849
28ab034a 850static int cleanup_received_fds(struct run_as_data *data)
fe9f7760 851{
93bed9fe 852 int ret = 0, i;
fe9f7760 853
93bed9fe
JG
854 for (i = 0; i < COMMAND_IN_FD_COUNT(data); i++) {
855 if (COMMAND_IN_FDS(data)[i] == -1) {
856 continue;
857 }
858 ret = close(COMMAND_IN_FDS(data)[i]);
859 if (ret) {
860 PERROR("Failed to close file descriptor received fd in run-as worker");
861 goto end;
862 }
fe9f7760 863 }
93bed9fe 864end:
fe9f7760
FD
865 return ret;
866}
0ef03255 867
28ab034a 868static int get_user_infos_from_uid(uid_t uid, char **username, gid_t *primary_gid)
37ccf8ec
FD
869{
870 int ret;
cd9adb8b 871 char *buf = nullptr;
222b6734
FD
872 long raw_get_pw_buf_size;
873 size_t get_pw_buf_size;
37ccf8ec 874 struct passwd pwd;
cd9adb8b 875 struct passwd *result = nullptr;
37ccf8ec
FD
876
877 /* Fetch the max size for the temporary buffer. */
878 errno = 0;
222b6734
FD
879 raw_get_pw_buf_size = sysconf(_SC_GETPW_R_SIZE_MAX);
880 if (raw_get_pw_buf_size < 0) {
37ccf8ec
FD
881 if (errno != 0) {
882 PERROR("Failed to query _SC_GETPW_R_SIZE_MAX");
883 goto error;
884 }
885
886 /* Limit is indeterminate. */
887 WARN("Failed to query _SC_GETPW_R_SIZE_MAX as it is "
28ab034a 888 "indeterminate; falling back to default buffer size");
222b6734 889 raw_get_pw_buf_size = GETPW_BUFFER_FALLBACK_SIZE;
37ccf8ec
FD
890 }
891
222b6734
FD
892 get_pw_buf_size = (size_t) raw_get_pw_buf_size;
893
64803277 894 buf = calloc<char>(get_pw_buf_size);
cd9adb8b 895 if (buf == nullptr) {
37ccf8ec
FD
896 PERROR("Failed to allocate buffer to get password file entries");
897 goto error;
898 }
899
222b6734 900 ret = getpwuid_r(uid, &pwd, buf, get_pw_buf_size, &result);
37ccf8ec 901 if (ret < 0) {
28ab034a 902 PERROR("Failed to get user information for user: uid = %d", (int) uid);
37ccf8ec
FD
903 goto error;
904 }
905
cd9adb8b 906 if (result == nullptr) {
28ab034a 907 ERR("Failed to find user information in password entries: uid = %d", (int) uid);
37ccf8ec
FD
908 ret = -1;
909 goto error;
910 }
911
912 *username = strdup(result->pw_name);
cd9adb8b 913 if (*username == nullptr) {
37ccf8ec
FD
914 PERROR("Failed to copy user name");
915 goto error;
916 }
917
918 *primary_gid = result->pw_gid;
919
920end:
921 free(buf);
922 return ret;
923error:
cd9adb8b 924 *username = nullptr;
37ccf8ec
FD
925 *primary_gid = -1;
926 ret = -1;
927 goto end;
928}
929
28ab034a 930static int demote_creds(uid_t prev_uid, gid_t prev_gid, uid_t new_uid, gid_t new_gid)
37ccf8ec
FD
931{
932 int ret = 0;
933 gid_t primary_gid;
cd9adb8b 934 char *username = nullptr;
37ccf8ec
FD
935
936 /* Change the group id. */
937 if (prev_gid != new_gid) {
938 ret = setegid(new_gid);
939 if (ret < 0) {
28ab034a 940 PERROR("Failed to set effective group id: new_gid = %d", (int) new_gid);
37ccf8ec
FD
941 goto end;
942 }
943 }
944
945 /* Change the user id. */
946 if (prev_uid != new_uid) {
947 ret = get_user_infos_from_uid(new_uid, &username, &primary_gid);
948 if (ret < 0) {
949 goto end;
950 }
951
952 /*
953 * Initialize the supplementary group access list.
954 *
955 * This is needed to handle cases where the supplementary groups
956 * of the user the process is demoting-to would give it access
957 * to a given file/folder, but not it's primary group.
958 *
959 * e.g
960 * username: User1
961 * Primary Group: User1
962 * Secondary group: Disk, Network
963 *
964 * mkdir inside the following directory must work since User1
965 * is part of the Network group.
966 *
967 * drwxrwx--- 2 root Network 4096 Jul 23 17:17 /tmp/my_folder/
968 *
969 *
970 * The order of the following initgroups and seteuid calls is
971 * important here;
972 * Only a root process or one with CAP_SETGID capability can
973 * call the the initgroups() function. We must initialize the
974 * supplementary groups before we change the effective
975 * UID to a less-privileged user.
976 */
977 ret = initgroups(username, primary_gid);
978 if (ret < 0) {
979 PERROR("Failed to init the supplementary group access list: "
28ab034a
JG
980 "username = `%s`, primary gid = %d",
981 username,
982 (int) primary_gid);
37ccf8ec
FD
983 goto end;
984 }
985
986 ret = seteuid(new_uid);
987 if (ret < 0) {
28ab034a 988 PERROR("Failed to set effective user id: new_uid = %d", (int) new_uid);
37ccf8ec
FD
989 goto end;
990 }
991 }
992end:
993 free(username);
994 return ret;
995}
996
28ab034a 997static int promote_creds(uid_t prev_uid, gid_t prev_gid, uid_t new_uid, gid_t new_gid)
37ccf8ec
FD
998{
999 int ret = 0;
1000 gid_t primary_gid;
cd9adb8b 1001 char *username = nullptr;
37ccf8ec
FD
1002
1003 /* Change the group id. */
1004 if (prev_gid != new_gid) {
1005 ret = setegid(new_gid);
1006 if (ret < 0) {
28ab034a 1007 PERROR("Failed to set effective group id: new_gid = %d", (int) new_gid);
37ccf8ec
FD
1008 goto end;
1009 }
1010 }
1011
1012 /* Change the user id. */
1013 if (prev_uid != new_uid) {
1014 ret = get_user_infos_from_uid(new_uid, &username, &primary_gid);
1015 if (ret < 0) {
1016 goto end;
1017 }
1018
1019 /*
1020 * seteuid call must be done before the initgroups call because
1021 * we need to be privileged (CAP_SETGID) to call initgroups().
1022 */
1023 ret = seteuid(new_uid);
1024 if (ret < 0) {
28ab034a 1025 PERROR("Failed to set effective user id: new_uid = %d", (int) new_uid);
37ccf8ec
FD
1026 goto end;
1027 }
1028
1029 /*
1030 * Initialize the supplementary group access list.
1031 *
1032 * There is a possibility the groups we set in the following
1033 * initgroups() call are not exactly the same as the ones we
1034 * had when we originally demoted. This can happen if the
1035 * /etc/group file is modified after the runas process is
1036 * forked. This is very unlikely.
1037 */
1038 ret = initgroups(username, primary_gid);
1039 if (ret < 0) {
1040 PERROR("Failed to init the supplementary group access "
28ab034a
JG
1041 "list: username = `%s`, primary gid = %d",
1042 username,
1043 (int) primary_gid)
37ccf8ec
FD
1044 goto end;
1045 }
1046 }
1047end:
1048 free(username);
1049 return ret;
1050}
1051
7567352f
MD
1052/*
1053 * Return < 0 on error, 0 if OK, 1 on hangup.
1054 */
28ab034a 1055static int handle_one_cmd(run_as_worker_data *worker)
c2b75c49 1056{
37ccf8ec 1057 int ret = 0, promote_ret;
55cb0d6f
JG
1058 struct run_as_data data = {};
1059 ssize_t readlen, writelen;
1060 struct run_as_ret sendret = {};
1061 run_as_fct cmd;
45d6ecaa
JG
1062 const uid_t prev_ruid = getuid();
1063 const gid_t prev_rgid = getgid();
7567352f 1064
fe9f7760
FD
1065 /*
1066 * Stage 1: Receive run_as_data struct from the master.
1067 * The structure contains the command type and all the parameters needed for
1068 * its execution
1069 */
28ab034a 1070 readlen = lttcomm_recv_unix_sock(worker->sockpair[1], &data, sizeof(data));
7567352f
MD
1071 if (readlen == 0) {
1072 /* hang up */
1073 ret = 1;
1074 goto end;
1075 }
1076 if (readlen < sizeof(data)) {
1077 PERROR("lttcomm_recv_unix_sock error");
1078 ret = -1;
1079 goto end;
1080 }
c2b75c49 1081
7567352f
MD
1082 cmd = run_as_enum_to_fct(data.cmd);
1083 if (!cmd) {
1084 ret = -1;
1085 goto end;
1086 }
1087
fe9f7760
FD
1088 /*
1089 * Stage 2: Receive file descriptor from master.
1090 * Some commands need a file descriptor as input so if it's needed we
1091 * receive the fd using the Unix socket.
1092 */
93bed9fe 1093 ret = recv_fds_from_master(worker, &data);
fe9f7760
FD
1094 if (ret < 0) {
1095 PERROR("recv_fd_from_master error");
1096 ret = -1;
1097 goto end;
1098 }
1099
37ccf8ec
FD
1100 ret = demote_creds(prev_ruid, prev_rgid, data.uid, data.gid);
1101 if (ret < 0) {
1102 goto write_return;
c2b75c49 1103 }
fe9f7760 1104
c2b75c49
MD
1105 /*
1106 * Also set umask to 0 for mkdir executable bit.
1107 */
1108 umask(0);
fe9f7760
FD
1109
1110 /*
1111 * Stage 3: Execute the command
1112 */
1113 ret = (*cmd)(&data, &sendret);
1114 if (ret < 0) {
1115 DBG("Execution of command returned an error");
1116 }
6d73c4ef
MD
1117
1118write_return:
93bed9fe 1119 ret = cleanup_received_fds(&data);
fe9f7760
FD
1120 if (ret < 0) {
1121 ERR("Error cleaning up FD");
37ccf8ec 1122 goto promote_back;
fe9f7760
FD
1123 }
1124
1125 /*
1126 * Stage 4: Send run_as_ret structure to the master.
1127 * This structure contain the return value of the command and the errno.
1128 */
28ab034a 1129 writelen = lttcomm_send_unix_sock(worker->sockpair[1], &sendret, sizeof(sendret));
6cd525e8 1130 if (writelen < sizeof(sendret)) {
7567352f
MD
1131 PERROR("lttcomm_send_unix_sock error");
1132 ret = -1;
37ccf8ec 1133 goto promote_back;
7567352f 1134 }
fe9f7760
FD
1135
1136 /*
93bed9fe 1137 * Stage 5: Send resulting file descriptors to the master.
fe9f7760 1138 */
93bed9fe 1139 ret = send_fds_to_master(worker, data.cmd, &sendret);
fe9f7760
FD
1140 if (ret < 0) {
1141 DBG("Sending FD to master returned an error");
7567352f 1142 }
fe9f7760 1143
7567352f 1144 ret = 0;
37ccf8ec
FD
1145
1146promote_back:
1147 /* Return to previous uid/gid. */
1148 promote_ret = promote_creds(data.uid, data.gid, prev_ruid, prev_rgid);
1149 if (promote_ret < 0) {
1150 ERR("Failed to promote back to the initial credentials");
1151 }
1152
7567352f
MD
1153end:
1154 return ret;
1155}
1156
28ab034a 1157static int run_as_worker(run_as_worker_data *worker)
7567352f
MD
1158{
1159 int ret;
1160 ssize_t writelen;
1161 struct run_as_ret sendret;
1162 size_t proc_orig_len;
1163
1164 /*
1165 * Initialize worker. Set a different process cmdline.
1166 */
1167 proc_orig_len = strlen(worker->procname);
1168 memset(worker->procname, 0, proc_orig_len);
1169 strncpy(worker->procname, DEFAULT_RUN_AS_WORKER_NAME, proc_orig_len);
1170
cb8d0d24 1171 ret = lttng_thread_setname(DEFAULT_RUN_AS_WORKER_NAME);
e1055edb 1172 if (ret && ret != -ENOSYS) {
b8090274 1173 /* Don't fail as this is not essential. */
cb8d0d24 1174 DBG("Failed to set pthread name attribute");
6cd525e8 1175 }
7567352f 1176
fe9f7760
FD
1177 memset(&sendret, 0, sizeof(sendret));
1178
28ab034a 1179 writelen = lttcomm_send_unix_sock(worker->sockpair[1], &sendret, sizeof(sendret));
7567352f
MD
1180 if (writelen < sizeof(sendret)) {
1181 PERROR("lttcomm_send_unix_sock error");
1182 ret = EXIT_FAILURE;
1183 goto end;
1184 }
1185
1186 for (;;) {
1187 ret = handle_one_cmd(worker);
1188 if (ret < 0) {
1189 ret = EXIT_FAILURE;
1190 goto end;
1191 } else if (ret > 0) {
1192 break;
1193 } else {
28ab034a 1194 continue; /* Next command. */
7567352f
MD
1195 }
1196 }
1197 ret = EXIT_SUCCESS;
1198end:
1199 return ret;
c2b75c49
MD
1200}
1201
28ab034a
JG
1202static int run_as_cmd(run_as_worker_data *worker,
1203 enum run_as_cmd cmd,
1204 struct run_as_data *data,
1205 struct run_as_ret *ret_value,
1206 uid_t uid,
1207 gid_t gid)
60b6c79c 1208{
fe9f7760 1209 int ret = 0;
7567352f 1210 ssize_t readlen, writelen;
60b6c79c
MD
1211
1212 /*
1213 * If we are non-root, we can only deal with our own uid.
1214 */
1215 if (geteuid() != 0) {
1216 if (uid != geteuid()) {
fe9f7760
FD
1217 ret = -1;
1218 ret_value->_errno = EPERM;
60b6c79c 1219 ERR("Client (%d)/Server (%d) UID mismatch (and sessiond is not root)",
28ab034a
JG
1220 (int) uid,
1221 (int) geteuid());
df5b86c8 1222 goto end;
60b6c79c 1223 }
60b6c79c
MD
1224 }
1225
7567352f
MD
1226 data->cmd = cmd;
1227 data->uid = uid;
1228 data->gid = gid;
1229
fe9f7760
FD
1230 /*
1231 * Stage 1: Send the run_as_data struct to the worker process
1232 */
28ab034a 1233 writelen = lttcomm_send_unix_sock(worker->sockpair[0], data, sizeof(*data));
7567352f
MD
1234 if (writelen < sizeof(*data)) {
1235 PERROR("Error writing message to run_as");
fe9f7760
FD
1236 ret = -1;
1237 ret_value->_errno = EIO;
60b6c79c 1238 goto end;
c2b75c49 1239 }
7567352f 1240
fe9f7760
FD
1241 /*
1242 * Stage 2: Send file descriptor to the worker process if needed
1243 */
93bed9fe 1244 ret = send_fds_to_worker(worker, data);
fe9f7760
FD
1245 if (ret) {
1246 PERROR("do_send_fd error");
1247 ret = -1;
1248 ret_value->_errno = EIO;
1249 goto end;
1250 }
1251
1252 /*
1253 * Stage 3: Wait for the execution of the command
1254 */
1255
1256 /*
1257 * Stage 4: Receive the run_as_ret struct containing the return value and
1258 * errno
1259 */
28ab034a 1260 readlen = lttcomm_recv_unix_sock(worker->sockpair[0], ret_value, sizeof(*ret_value));
da9ee832
JG
1261 if (!readlen) {
1262 ERR("Run-as worker has hung-up during run_as_cmd");
fe9f7760
FD
1263 ret = -1;
1264 ret_value->_errno = EIO;
da9ee832 1265 goto end;
fe9f7760 1266 } else if (readlen < sizeof(*ret_value)) {
7567352f 1267 PERROR("Error reading response from run_as");
fe9f7760
FD
1268 ret = -1;
1269 ret_value->_errno = errno;
033b58a7 1270 goto end;
6cd525e8 1271 }
fe9f7760 1272
ca9eb994
JG
1273 if (ret_value->_error) {
1274 /* Skip stage 5 on error as there will be no fd to receive. */
1275 goto end;
1276 }
1277
fe9f7760
FD
1278 /*
1279 * Stage 5: Receive file descriptor if needed
1280 */
93bed9fe 1281 ret = recv_fds_from_worker(worker, cmd, ret_value);
fe9f7760
FD
1282 if (ret < 0) {
1283 ERR("Error receiving fd");
1284 ret = -1;
1285 ret_value->_errno = EIO;
4c462e79 1286 }
7567352f 1287
60b6c79c 1288end:
fe9f7760 1289 return ret;
60b6c79c
MD
1290}
1291
2d85a600 1292/*
7567352f 1293 * This is for debugging ONLY and should not be considered secure.
2d85a600 1294 */
28ab034a
JG
1295static int run_as_noworker(enum run_as_cmd cmd,
1296 struct run_as_data *data,
1297 struct run_as_ret *ret_value,
1298 uid_t uid __attribute__((unused)),
1299 gid_t gid __attribute__((unused)))
2d85a600 1300{
df5b86c8 1301 int ret, saved_errno;
5b73926f 1302 mode_t old_mask;
7567352f 1303 run_as_fct fct;
5b73926f 1304
7567352f
MD
1305 fct = run_as_enum_to_fct(cmd);
1306 if (!fct) {
1307 errno = -ENOSYS;
1308 ret = -1;
1309 goto end;
1310 }
5b73926f 1311 old_mask = umask(0);
fe9f7760
FD
1312 ret = fct(data, ret_value);
1313 saved_errno = ret_value->_errno;
5b73926f 1314 umask(old_mask);
df5b86c8 1315 errno = saved_errno;
7567352f 1316end:
5b73926f 1317 return ret;
2d85a600
MD
1318}
1319
cd9adb8b 1320static int reset_sighandler()
8fec83ea
JG
1321{
1322 int sig;
1323
1324 DBG("Resetting run_as worker signal handlers to default");
1325 for (sig = 1; sig <= 31; sig++) {
1326 (void) signal(sig, SIG_DFL);
1327 }
1328 return 0;
1329}
1330
28ab034a 1331static void worker_sighandler(int sig)
8fec83ea
JG
1332{
1333 const char *signame;
1334
1335 /*
1336 * The worker will inherit its parent's signals since they are part of
1337 * the same process group. However, in the case of SIGINT and SIGTERM,
1338 * we want to give the worker a chance to teardown gracefully when its
1339 * parent closes the command socket.
1340 */
1341 switch (sig) {
1342 case SIGINT:
1343 signame = "SIGINT";
1344 break;
1345 case SIGTERM:
1346 signame = "SIGTERM";
1347 break;
1348 default:
cd9adb8b 1349 signame = nullptr;
8fec83ea
JG
1350 }
1351
1352 if (signame) {
1353 DBG("run_as worker received signal %s", signame);
1354 } else {
1355 DBG("run_as_worker received signal %d", sig);
1356 }
1357}
1358
cd9adb8b 1359static int set_worker_sighandlers()
8fec83ea
JG
1360{
1361 int ret = 0;
1362 sigset_t sigset;
1363 struct sigaction sa;
1364
1365 if ((ret = sigemptyset(&sigset)) < 0) {
1366 PERROR("sigemptyset");
1367 goto end;
1368 }
1369
1370 sa.sa_handler = worker_sighandler;
1371 sa.sa_mask = sigset;
1372 sa.sa_flags = 0;
cd9adb8b 1373 if ((ret = sigaction(SIGINT, &sa, nullptr)) < 0) {
8fec83ea
JG
1374 PERROR("sigaction SIGINT");
1375 goto end;
1376 }
1377
cd9adb8b 1378 if ((ret = sigaction(SIGTERM, &sa, nullptr)) < 0) {
8fec83ea
JG
1379 PERROR("sigaction SIGTERM");
1380 goto end;
1381 }
1382
1383 DBG("run_as signal handler set for SIGTERM and SIGINT");
1384end:
1385 return ret;
1386}
1387
28ab034a
JG
1388static int run_as_create_worker_no_lock(const char *procname,
1389 post_fork_cleanup_cb clean_up_func,
1390 void *clean_up_user_data)
8fec83ea
JG
1391{
1392 pid_t pid;
1393 int i, ret = 0;
1394 ssize_t readlen;
1395 struct run_as_ret recvret;
a6bc4ca9 1396 run_as_worker_data *worker;
8fec83ea 1397
a0377dfe 1398 LTTNG_ASSERT(!global_worker);
8fec83ea
JG
1399 if (!use_clone()) {
1400 /*
1401 * Don't initialize a worker, all run_as tasks will be performed
1402 * in the current process.
1403 */
1404 ret = 0;
1405 goto end;
1406 }
64803277 1407 worker = zmalloc<run_as_worker_data>();
8fec83ea
JG
1408 if (!worker) {
1409 ret = -ENOMEM;
1410 goto end;
1411 }
1412 worker->procname = strdup(procname);
1413 if (!worker->procname) {
1414 ret = -ENOMEM;
8c96eded 1415 goto error_procname_alloc;
8fec83ea
JG
1416 }
1417 /* Create unix socket. */
1418 if (lttcomm_create_anon_unix_socketpair(worker->sockpair) < 0) {
1419 ret = -1;
1420 goto error_sock;
1421 }
1422
1423 /* Fork worker. */
1424 pid = fork();
1425 if (pid < 0) {
1426 PERROR("fork");
1427 ret = -1;
1428 goto error_fork;
1429 } else if (pid == 0) {
1430 /* Child */
1431
1432 reset_sighandler();
1433
1434 set_worker_sighandlers();
c989e0d4
FD
1435
1436 logger_set_thread_name("Run-as worker", true);
1437
929f71ec
JG
1438 if (clean_up_func) {
1439 if (clean_up_func(clean_up_user_data) < 0) {
1440 ERR("Run-as post-fork clean-up failed, exiting.");
1441 exit(EXIT_FAILURE);
1442 }
1443 }
8fec83ea
JG
1444
1445 /* Just close, no shutdown. */
1446 if (close(worker->sockpair[0])) {
1447 PERROR("close");
1448 exit(EXIT_FAILURE);
1449 }
1450
1451 /*
1452 * Close all FDs aside from STDIN, STDOUT, STDERR and sockpair[1]
1453 * Sockpair[1] is used as a control channel with the master
1454 */
1455 for (i = 3; i < sysconf(_SC_OPEN_MAX); i++) {
1456 if (i != worker->sockpair[1]) {
1457 (void) close(i);
1458 }
1459 }
1460
1461 worker->sockpair[0] = -1;
1462 ret = run_as_worker(worker);
1463 if (lttcomm_close_unix_sock(worker->sockpair[1])) {
1464 PERROR("close");
1465 ret = -1;
1466 }
1467 worker->sockpair[1] = -1;
55cb0d6f 1468 free(worker->procname);
340cf672 1469 free(worker);
8fec83ea
JG
1470 LOG(ret ? PRINT_ERR : PRINT_DBG, "run_as worker exiting (ret = %d)", ret);
1471 exit(ret ? EXIT_FAILURE : EXIT_SUCCESS);
1472 } else {
1473 /* Parent */
1474
1475 /* Just close, no shutdown. */
1476 if (close(worker->sockpair[1])) {
1477 PERROR("close");
1478 ret = -1;
1479 goto error_fork;
1480 }
1481 worker->sockpair[1] = -1;
1482 worker->pid = pid;
1483 /* Wait for worker to become ready. */
28ab034a 1484 readlen = lttcomm_recv_unix_sock(worker->sockpair[0], &recvret, sizeof(recvret));
8fec83ea
JG
1485 if (readlen < sizeof(recvret)) {
1486 ERR("readlen: %zd", readlen);
1487 PERROR("Error reading response from run_as at creation");
1488 ret = -1;
1489 goto error_fork;
1490 }
1491 global_worker = worker;
1492 }
1493end:
1494 return ret;
1495
1496 /* Error handling. */
1497error_fork:
1498 for (i = 0; i < 2; i++) {
1499 if (worker->sockpair[i] < 0) {
1500 continue;
1501 }
1502 if (lttcomm_close_unix_sock(worker->sockpair[i])) {
1503 PERROR("close");
1504 }
1505 worker->sockpair[i] = -1;
1506 }
1507error_sock:
8c96eded
FD
1508 free(worker->procname);
1509error_procname_alloc:
8fec83ea
JG
1510 free(worker);
1511 return ret;
1512}
1513
cd9adb8b 1514static void run_as_destroy_worker_no_lock()
a01c682b 1515{
a6bc4ca9 1516 run_as_worker_data *worker = global_worker;
a01c682b
JR
1517
1518 DBG("Destroying run_as worker");
1519 if (!worker) {
1520 return;
1521 }
1522 /* Close unix socket */
1523 DBG("Closing run_as worker socket");
1524 if (lttcomm_close_unix_sock(worker->sockpair[0])) {
1525 PERROR("close");
1526 }
1527 worker->sockpair[0] = -1;
1528 /* Wait for worker. */
1529 for (;;) {
1530 int status;
1531 pid_t wait_ret;
1532
1533 wait_ret = waitpid(worker->pid, &status, 0);
1534 if (wait_ret < 0) {
1535 if (errno == EINTR) {
1536 continue;
1537 }
1538 PERROR("waitpid");
1539 break;
1540 }
1541
1542 if (WIFEXITED(status)) {
1543 LOG(WEXITSTATUS(status) == 0 ? PRINT_DBG : PRINT_ERR,
28ab034a
JG
1544 DEFAULT_RUN_AS_WORKER_NAME " terminated with status code %d",
1545 WEXITSTATUS(status));
a01c682b
JR
1546 break;
1547 } else if (WIFSIGNALED(status)) {
1548 ERR(DEFAULT_RUN_AS_WORKER_NAME " was killed by signal %d",
28ab034a 1549 WTERMSIG(status));
a01c682b
JR
1550 break;
1551 }
1552 }
1553 free(worker->procname);
1554 free(worker);
cd9adb8b 1555 global_worker = nullptr;
a01c682b
JR
1556}
1557
28ab034a 1558static int run_as_restart_worker(run_as_worker_data *worker)
2d85a600 1559{
fe9f7760 1560 int ret = 0;
cd9adb8b 1561 char *procname = nullptr;
fe9f7760
FD
1562
1563 procname = worker->procname;
1564
1565 /* Close socket to run_as worker process and clean up the zombie process */
a01c682b 1566 run_as_destroy_worker_no_lock();
fe9f7760
FD
1567
1568 /* Create a new run_as worker process*/
cd9adb8b 1569 ret = run_as_create_worker_no_lock(procname, nullptr, nullptr);
28ab034a 1570 if (ret < 0) {
fe9f7760
FD
1571 ERR("Restarting the worker process failed");
1572 ret = -1;
1573 goto err;
1574 }
1575err:
1576 return ret;
1577}
1578
28ab034a
JG
1579static int run_as(enum run_as_cmd cmd,
1580 struct run_as_data *data,
1581 struct run_as_ret *ret_value,
1582 uid_t uid,
1583 gid_t gid)
fe9f7760
FD
1584{
1585 int ret, saved_errno;
7567352f 1586
8fec83ea 1587 pthread_mutex_lock(&worker_lock);
749b7a0c 1588 if (use_clone()) {
7567352f 1589 DBG("Using run_as worker");
8fec83ea 1590
a0377dfe 1591 LTTNG_ASSERT(global_worker);
749b7a0c 1592
fe9f7760
FD
1593 ret = run_as_cmd(global_worker, cmd, data, ret_value, uid, gid);
1594 saved_errno = ret_value->_errno;
1595
fe9f7760
FD
1596 /*
1597 * If the worker thread crashed the errno is set to EIO. we log
1598 * the error and start a new worker process.
1599 */
1600 if (ret == -1 && saved_errno == EIO) {
1601 DBG("Socket closed unexpectedly... "
28ab034a 1602 "Restarting the worker process");
fe9f7760 1603 ret = run_as_restart_worker(global_worker);
fe9f7760
FD
1604 if (ret == -1) {
1605 ERR("Failed to restart worker process.");
1606 goto err;
1607 }
1608 }
2d85a600 1609 } else {
7567352f 1610 DBG("Using run_as without worker");
fe9f7760 1611 ret = run_as_noworker(cmd, data, ret_value, uid, gid);
2d85a600 1612 }
fe9f7760 1613err:
8fec83ea 1614 pthread_mutex_unlock(&worker_lock);
7567352f 1615 return ret;
2d85a600
MD
1616}
1617
e11d277b 1618int run_as_mkdir_recursive(const char *path, mode_t mode, uid_t uid, gid_t gid)
60b6c79c 1619{
18710679
JG
1620 return run_as_mkdirat_recursive(AT_FDCWD, path, mode, uid, gid);
1621}
1622
28ab034a 1623int run_as_mkdirat_recursive(int dirfd, const char *path, mode_t mode, uid_t uid, gid_t gid)
18710679
JG
1624{
1625 int ret;
93bed9fe
JG
1626 struct run_as_data data = {};
1627 struct run_as_ret run_as_ret = {};
60b6c79c 1628
18710679 1629 DBG3("mkdirat() recursive fd = %d%s, path = %s, mode = %d, uid = %d, gid = %d",
28ab034a
JG
1630 dirfd,
1631 dirfd == AT_FDCWD ? " (AT_FDCWD)" : "",
1632 path,
1633 (int) mode,
1634 (int) uid,
1635 (int) gid);
1636 ret = lttng_strncpy(data.u.mkdir.path, path, sizeof(data.u.mkdir.path));
18710679
JG
1637 if (ret) {
1638 ERR("Failed to copy path argument of mkdirat recursive command");
1639 goto error;
1640 }
93bed9fe
JG
1641 data.u.mkdir.path[sizeof(data.u.mkdir.path) - 1] = '\0';
1642 data.u.mkdir.mode = mode;
1643 data.u.mkdir.dirfd = dirfd;
18710679 1644 run_as(dirfd == AT_FDCWD ? RUN_AS_MKDIR_RECURSIVE : RUN_AS_MKDIRAT_RECURSIVE,
28ab034a
JG
1645 &data,
1646 &run_as_ret,
1647 uid,
1648 gid);
18710679 1649 errno = run_as_ret._errno;
93bed9fe 1650 ret = run_as_ret.u.ret;
18710679
JG
1651error:
1652 return ret;
60b6c79c
MD
1653}
1654
e11d277b 1655int run_as_mkdir(const char *path, mode_t mode, uid_t uid, gid_t gid)
60b6c79c 1656{
18710679
JG
1657 return run_as_mkdirat(AT_FDCWD, path, mode, uid, gid);
1658}
1659
28ab034a 1660int run_as_mkdirat(int dirfd, const char *path, mode_t mode, uid_t uid, gid_t gid)
18710679
JG
1661{
1662 int ret;
93bed9fe
JG
1663 struct run_as_data data = {};
1664 struct run_as_ret run_as_ret = {};
fe9f7760 1665
18710679 1666 DBG3("mkdirat() recursive fd = %d%s, path = %s, mode = %d, uid = %d, gid = %d",
28ab034a
JG
1667 dirfd,
1668 dirfd == AT_FDCWD ? " (AT_FDCWD)" : "",
1669 path,
1670 (int) mode,
1671 (int) uid,
1672 (int) gid);
1673 ret = lttng_strncpy(data.u.mkdir.path, path, sizeof(data.u.mkdir.path));
18710679
JG
1674 if (ret) {
1675 ERR("Failed to copy path argument of mkdirat command");
1676 goto error;
1677 }
93bed9fe
JG
1678 data.u.mkdir.path[sizeof(data.u.mkdir.path) - 1] = '\0';
1679 data.u.mkdir.mode = mode;
1680 data.u.mkdir.dirfd = dirfd;
28ab034a 1681 run_as(dirfd == AT_FDCWD ? RUN_AS_MKDIR : RUN_AS_MKDIRAT, &data, &run_as_ret, uid, gid);
18710679 1682 errno = run_as_ret._errno;
93bed9fe 1683 ret = run_as_ret.u.ret;
18710679
JG
1684error:
1685 return ret;
60b6c79c
MD
1686}
1687
28ab034a 1688int run_as_open(const char *path, int flags, mode_t mode, uid_t uid, gid_t gid)
2912cead
JG
1689{
1690 return run_as_openat(AT_FDCWD, path, flags, mode, uid, gid);
1691}
1692
28ab034a 1693int run_as_openat(int dirfd, const char *path, int flags, mode_t mode, uid_t uid, gid_t gid)
60b6c79c 1694{
93bed9fe 1695 int ret;
55cb0d6f
JG
1696 struct run_as_data data = {};
1697 struct run_as_ret run_as_ret = {};
fe9f7760 1698
2912cead 1699 DBG3("openat() fd = %d%s, path = %s, flags = %X, mode = %d, uid %d, gid %d",
28ab034a
JG
1700 dirfd,
1701 dirfd == AT_FDCWD ? " (AT_FDCWD)" : "",
1702 path,
1703 flags,
1704 (int) mode,
1705 (int) uid,
1706 (int) gid);
93bed9fe
JG
1707 ret = lttng_strncpy(data.u.open.path, path, sizeof(data.u.open.path));
1708 if (ret) {
1709 ERR("Failed to copy path argument of open command");
1710 goto error;
1711 }
7567352f
MD
1712 data.u.open.flags = flags;
1713 data.u.open.mode = mode;
93bed9fe 1714 data.u.open.dirfd = dirfd;
28ab034a 1715 run_as(dirfd == AT_FDCWD ? RUN_AS_OPEN : RUN_AS_OPENAT, &data, &run_as_ret, uid, gid);
93bed9fe 1716 errno = run_as_ret._errno;
28ab034a 1717 ret = run_as_ret.u.ret < 0 ? run_as_ret.u.ret : run_as_ret.u.open.fd;
93bed9fe
JG
1718error:
1719 return ret;
60b6c79c 1720}
4628484a 1721
4628484a 1722int run_as_unlink(const char *path, uid_t uid, gid_t gid)
2912cead
JG
1723{
1724 return run_as_unlinkat(AT_FDCWD, path, uid, gid);
1725}
1726
2912cead 1727int run_as_unlinkat(int dirfd, const char *path, uid_t uid, gid_t gid)
4628484a 1728{
93bed9fe
JG
1729 int ret;
1730 struct run_as_data data = {};
1731 struct run_as_ret run_as_ret = {};
fe9f7760 1732
2912cead 1733 DBG3("unlinkat() fd = %d%s, path = %s, uid = %d, gid = %d",
28ab034a
JG
1734 dirfd,
1735 dirfd == AT_FDCWD ? " (AT_FDCWD)" : "",
1736 path,
1737 (int) uid,
1738 (int) gid);
1739 ret = lttng_strncpy(data.u.unlink.path, path, sizeof(data.u.unlink.path));
93bed9fe
JG
1740 if (ret) {
1741 goto error;
1742 }
1743 data.u.unlink.dirfd = dirfd;
28ab034a 1744 run_as(dirfd == AT_FDCWD ? RUN_AS_UNLINK : RUN_AS_UNLINKAT, &data, &run_as_ret, uid, gid);
93bed9fe
JG
1745 errno = run_as_ret._errno;
1746 ret = run_as_ret.u.ret;
1747error:
1748 return ret;
1749}
1750
93bed9fe
JG
1751int run_as_rmdir(const char *path, uid_t uid, gid_t gid)
1752{
1753 return run_as_rmdirat(AT_FDCWD, path, uid, gid);
1754}
1755
93bed9fe
JG
1756int run_as_rmdirat(int dirfd, const char *path, uid_t uid, gid_t gid)
1757{
1758 int ret;
1759 struct run_as_data data = {};
1760 struct run_as_ret run_as_ret = {};
1761
1762 DBG3("rmdirat() fd = %d%s, path = %s, uid = %d, gid = %d",
28ab034a
JG
1763 dirfd,
1764 dirfd == AT_FDCWD ? " (AT_FDCWD)" : "",
1765 path,
1766 (int) uid,
1767 (int) gid);
1768 ret = lttng_strncpy(data.u.rmdir.path, path, sizeof(data.u.rmdir.path));
93bed9fe
JG
1769 if (ret) {
1770 goto error;
1771 }
1772 data.u.rmdir.dirfd = dirfd;
28ab034a 1773 run_as(dirfd == AT_FDCWD ? RUN_AS_RMDIR : RUN_AS_RMDIRAT, &data, &run_as_ret, uid, gid);
93bed9fe
JG
1774 errno = run_as_ret._errno;
1775 ret = run_as_ret.u.ret;
1776error:
1777 return ret;
4628484a
MD
1778}
1779
f75c5439 1780int run_as_rmdir_recursive(const char *path, uid_t uid, gid_t gid, int flags)
4628484a 1781{
f75c5439 1782 return run_as_rmdirat_recursive(AT_FDCWD, path, uid, gid, flags);
93bed9fe 1783}
fe9f7760 1784
f75c5439 1785int run_as_rmdirat_recursive(int dirfd, const char *path, uid_t uid, gid_t gid, int flags)
93bed9fe
JG
1786{
1787 int ret;
1788 struct run_as_data data = {};
1789 struct run_as_ret run_as_ret = {};
4628484a 1790
93bed9fe 1791 DBG3("rmdirat() recursive fd = %d%s, path = %s, uid = %d, gid = %d",
28ab034a
JG
1792 dirfd,
1793 dirfd == AT_FDCWD ? " (AT_FDCWD)" : "",
1794 path,
1795 (int) uid,
1796 (int) gid);
1797 ret = lttng_strncpy(data.u.rmdir.path, path, sizeof(data.u.rmdir.path));
93bed9fe
JG
1798 if (ret) {
1799 goto error;
1800 }
1801 data.u.rmdir.dirfd = dirfd;
f75c5439 1802 data.u.rmdir.flags = flags;
93bed9fe 1803 run_as(dirfd == AT_FDCWD ? RUN_AS_RMDIR_RECURSIVE : RUN_AS_RMDIRAT_RECURSIVE,
28ab034a
JG
1804 &data,
1805 &run_as_ret,
1806 uid,
1807 gid);
93bed9fe
JG
1808 errno = run_as_ret._errno;
1809 ret = run_as_ret.u.ret;
1810error:
1811 return ret;
1812}
1813
a6bc4ca9 1814int run_as_rename(const char *old_name, const char *new_name, uid_t uid, gid_t gid)
93bed9fe 1815{
a6bc4ca9 1816 return run_as_renameat(AT_FDCWD, old_name, AT_FDCWD, new_name, uid, gid);
93bed9fe
JG
1817}
1818
28ab034a
JG
1819int run_as_renameat(int old_dirfd,
1820 const char *old_name,
1821 int new_dirfd,
1822 const char *new_name,
1823 uid_t uid,
1824 gid_t gid)
93bed9fe
JG
1825{
1826 int ret;
1827 struct run_as_data data = {};
1828 struct run_as_ret run_as_ret = {};
1829
1830 DBG3("renameat() old_dirfd = %d%s, old_name = %s, new_dirfd = %d%s, new_name = %s, uid = %d, gid = %d",
28ab034a
JG
1831 old_dirfd,
1832 old_dirfd == AT_FDCWD ? " (AT_FDCWD)" : "",
1833 old_name,
1834 new_dirfd,
1835 new_dirfd == AT_FDCWD ? " (AT_FDCWD)" : "",
1836 new_name,
1837 (int) uid,
1838 (int) gid);
1839 ret = lttng_strncpy(data.u.rename.old_path, old_name, sizeof(data.u.rename.old_path));
93bed9fe
JG
1840 if (ret) {
1841 goto error;
1842 }
28ab034a 1843 ret = lttng_strncpy(data.u.rename.new_path, new_name, sizeof(data.u.rename.new_path));
93bed9fe
JG
1844 if (ret) {
1845 goto error;
1846 }
1847
1848 data.u.rename.dirfds[0] = old_dirfd;
1849 data.u.rename.dirfds[1] = new_dirfd;
28ab034a
JG
1850 run_as(old_dirfd == AT_FDCWD && new_dirfd == AT_FDCWD ? RUN_AS_RENAME : RUN_AS_RENAMEAT,
1851 &data,
1852 &run_as_ret,
1853 uid,
1854 gid);
93bed9fe
JG
1855 errno = run_as_ret._errno;
1856 ret = run_as_ret.u.ret;
1857error:
1858 return ret;
7567352f
MD
1859}
1860
28ab034a
JG
1861int run_as_extract_elf_symbol_offset(
1862 int fd, const char *function, uid_t uid, gid_t gid, uint64_t *offset)
241e0a5a 1863{
93bed9fe
JG
1864 int ret;
1865 struct run_as_data data = {};
55cb0d6f 1866 struct run_as_ret run_as_ret = {};
f726677b 1867
241e0a5a 1868 DBG3("extract_elf_symbol_offset() on fd=%d and function=%s "
28ab034a
JG
1869 "with for uid %d and gid %d",
1870 fd,
1871 function,
1872 (int) uid,
1873 (int) gid);
241e0a5a 1874
93bed9fe 1875 data.u.extract_elf_symbol_offset.fd = fd;
241e0a5a
FD
1876
1877 strncpy(data.u.extract_elf_symbol_offset.function, function, LTTNG_SYMBOL_NAME_LEN - 1);
241e0a5a 1878 data.u.extract_elf_symbol_offset.function[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
93bed9fe 1879 ret = lttng_strncpy(data.u.extract_elf_symbol_offset.function,
28ab034a
JG
1880 function,
1881 sizeof(data.u.extract_elf_symbol_offset.function));
93bed9fe
JG
1882 if (ret) {
1883 goto error;
1884 }
241e0a5a 1885
93bed9fe
JG
1886 run_as(RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET, &data, &run_as_ret, uid, gid);
1887 errno = run_as_ret._errno;
1888 if (run_as_ret._error) {
1889 ret = -1;
1890 goto error;
241e0a5a
FD
1891 }
1892
93bed9fe
JG
1893 *offset = run_as_ret.u.extract_elf_symbol_offset.offset;
1894error:
1895 return ret;
241e0a5a
FD
1896}
1897
28ab034a
JG
1898int run_as_extract_sdt_probe_offsets(int fd,
1899 const char *provider_name,
1900 const char *probe_name,
1901 uid_t uid,
1902 gid_t gid,
1903 uint64_t **offsets,
1904 uint32_t *num_offset)
0ef03255 1905{
93bed9fe
JG
1906 int ret;
1907 struct run_as_data data = {};
1908 struct run_as_ret run_as_ret = {};
f726677b 1909
0ef03255 1910 DBG3("extract_sdt_probe_offsets() on fd=%d, probe_name=%s and "
28ab034a
JG
1911 "provider_name=%s with for uid %d and gid %d",
1912 fd,
1913 probe_name,
1914 provider_name,
1915 (int) uid,
1916 (int) gid);
0ef03255 1917
93bed9fe 1918 data.u.extract_sdt_probe_offsets.fd = fd;
0ef03255 1919
28ab034a
JG
1920 ret = lttng_strncpy(data.u.extract_sdt_probe_offsets.probe_name,
1921 probe_name,
1922 sizeof(data.u.extract_sdt_probe_offsets.probe_name));
93bed9fe
JG
1923 if (ret) {
1924 goto error;
1925 }
1926 ret = lttng_strncpy(data.u.extract_sdt_probe_offsets.provider_name,
28ab034a
JG
1927 provider_name,
1928 sizeof(data.u.extract_sdt_probe_offsets.provider_name));
93bed9fe
JG
1929 if (ret) {
1930 goto error;
0ef03255
FD
1931 }
1932
93bed9fe
JG
1933 run_as(RUN_AS_EXTRACT_SDT_PROBE_OFFSETS, &data, &run_as_ret, uid, gid);
1934 errno = run_as_ret._errno;
1935 if (run_as_ret._error) {
1936 ret = -1;
1937 goto error;
1938 }
0ef03255 1939
93bed9fe 1940 *num_offset = run_as_ret.u.extract_sdt_probe_offsets.num_offset;
64803277 1941 *offsets = calloc<uint64_t>(*num_offset);
0ef03255 1942 if (!*offsets) {
93bed9fe
JG
1943 ret = -ENOMEM;
1944 goto error;
0ef03255
FD
1945 }
1946
28ab034a
JG
1947 memcpy(*offsets,
1948 run_as_ret.u.extract_sdt_probe_offsets.offsets,
1949 *num_offset * sizeof(uint64_t));
93bed9fe
JG
1950error:
1951 return ret;
0ef03255
FD
1952}
1953
c73f064a 1954int run_as_generate_filter_bytecode(const char *filter_expression,
28ab034a
JG
1955 const struct lttng_credentials *creds,
1956 struct lttng_bytecode **bytecode)
c73f064a
JR
1957{
1958 int ret;
1959 struct run_as_data data = {};
1960 struct run_as_ret run_as_ret = {};
cd9adb8b
JG
1961 const struct lttng_bytecode *view_bytecode = nullptr;
1962 struct lttng_bytecode *local_bytecode = nullptr;
58daac01
JR
1963 const uid_t uid = lttng_credentials_get_uid(creds);
1964 const gid_t gid = lttng_credentials_get_gid(creds);
c73f064a
JR
1965
1966 DBG3("generate_filter_bytecode() from expression=\"%s\" for uid %d and gid %d",
28ab034a
JG
1967 filter_expression,
1968 (int) uid,
1969 (int) gid);
c73f064a 1970
28ab034a
JG
1971 ret = lttng_strncpy(data.u.generate_filter_bytecode.filter_expression,
1972 filter_expression,
1973 sizeof(data.u.generate_filter_bytecode.filter_expression));
c73f064a
JR
1974 if (ret) {
1975 goto error;
1976 }
1977
1978 run_as(RUN_AS_GENERATE_FILTER_BYTECODE, &data, &run_as_ret, uid, gid);
1979 errno = run_as_ret._errno;
1980 if (run_as_ret._error) {
1981 ret = -1;
1982 goto error;
1983 }
1984
28ab034a
JG
1985 view_bytecode =
1986 (const struct lttng_bytecode *) run_as_ret.u.generate_filter_bytecode.bytecode;
c73f064a 1987
64803277 1988 local_bytecode = calloc<lttng_bytecode>(view_bytecode->len);
c73f064a
JR
1989 if (!local_bytecode) {
1990 ret = -ENOMEM;
1991 goto error;
1992 }
1993
28ab034a
JG
1994 memcpy(local_bytecode,
1995 run_as_ret.u.generate_filter_bytecode.bytecode,
1996 sizeof(*local_bytecode) + view_bytecode->len);
c73f064a
JR
1997 *bytecode = local_bytecode;
1998error:
1999 return ret;
2000}
2001
929f71ec 2002int run_as_create_worker(const char *procname,
28ab034a
JG
2003 post_fork_cleanup_cb clean_up_func,
2004 void *clean_up_user_data)
7567352f 2005{
8fec83ea 2006 int ret;
7567352f 2007
749b7a0c 2008 pthread_mutex_lock(&worker_lock);
28ab034a 2009 ret = run_as_create_worker_no_lock(procname, clean_up_func, clean_up_user_data);
749b7a0c 2010 pthread_mutex_unlock(&worker_lock);
7567352f
MD
2011 return ret;
2012}
2013
cd9adb8b 2014void run_as_destroy_worker()
7567352f 2015{
749b7a0c 2016 pthread_mutex_lock(&worker_lock);
a01c682b 2017 run_as_destroy_worker_no_lock();
749b7a0c 2018 pthread_mutex_unlock(&worker_lock);
4628484a 2019}
This page took 0.260305 seconds and 4 git commands to generate.