run_as: add extract ELF symbol offset command
[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>
4 *
d14d33bf
AM
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License, version 2 only,
7 * as published by the Free Software Foundation.
60b6c79c
MD
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
d14d33bf 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
60b6c79c
MD
12 * more details.
13 *
d14d33bf
AM
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
60b6c79c
MD
17 */
18
6c1c0768 19#define _LGPL_SOURCE
60b6c79c
MD
20#include <errno.h>
21#include <limits.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <sys/wait.h>
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <unistd.h>
29#include <fcntl.h>
c2b75c49 30#include <sched.h>
0452bf08 31#include <signal.h>
749b7a0c 32#include <assert.h>
e1055edb 33#include <signal.h>
60b6c79c 34
90e535ef 35#include <common/common.h>
3fd15a74 36#include <common/utils.h>
e8fa9fb0 37#include <common/compat/getenv.h>
e1055edb 38#include <common/compat/prctl.h>
2038dd6c
JG
39#include <common/unix.h>
40#include <common/defaults.h>
241e0a5a
FD
41#include <common/lttng-elf.h>
42
43#include <lttng/constant.h>
60b6c79c 44
0857097f
DG
45#include "runas.h"
46
7567352f 47struct run_as_data;
fe9f7760
FD
48struct run_as_ret;
49typedef int (*run_as_fct)(struct run_as_data *data, struct run_as_ret *ret_value);
c2b75c49 50
e11d277b 51struct run_as_mkdir_data {
7567352f 52 char path[PATH_MAX];
60b6c79c
MD
53 mode_t mode;
54};
55
e11d277b 56struct run_as_open_data {
7567352f 57 char path[PATH_MAX];
60b6c79c
MD
58 int flags;
59 mode_t mode;
60};
61
4628484a 62struct run_as_unlink_data {
7567352f 63 char path[PATH_MAX];
4628484a
MD
64};
65
7567352f
MD
66struct run_as_rmdir_recursive_data {
67 char path[PATH_MAX];
68};
69
241e0a5a
FD
70struct run_as_extract_elf_symbol_offset_data {
71 char function[LTTNG_SYMBOL_NAME_LEN];
72};
73
fe9f7760
FD
74struct run_as_mkdir_ret {
75 int ret;
76};
77
78struct run_as_open_ret {
79 int ret;
80};
81
82struct run_as_unlink_ret {
83 int ret;
84};
85
86struct run_as_rmdir_recursive_ret {
87 int ret;
88};
89
241e0a5a
FD
90struct run_as_extract_elf_symbol_offset_ret {
91 uint64_t offset;
92};
93
7567352f
MD
94enum run_as_cmd {
95 RUN_AS_MKDIR,
96 RUN_AS_OPEN,
97 RUN_AS_UNLINK,
98 RUN_AS_RMDIR_RECURSIVE,
99 RUN_AS_MKDIR_RECURSIVE,
241e0a5a 100 RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET,
7567352f
MD
101};
102
103struct run_as_data {
104 enum run_as_cmd cmd;
fe9f7760 105 int fd;
7567352f
MD
106 union {
107 struct run_as_mkdir_data mkdir;
108 struct run_as_open_data open;
109 struct run_as_unlink_data unlink;
110 struct run_as_rmdir_recursive_data rmdir_recursive;
241e0a5a 111 struct run_as_extract_elf_symbol_offset_data extract_elf_symbol_offset;
7567352f
MD
112 } u;
113 uid_t uid;
114 gid_t gid;
4628484a
MD
115};
116
fe9f7760
FD
117/*
118 * The run_as_ret structure holds the returned value and status of the command.
119 *
120 * The `u` union field holds the return value of the command; in most cases it
121 * represents the success or the failure of the command. In more complex
122 * commands, it holds a computed value.
123 *
124 * The _errno field is the errno recorded after the execution of the command.
125 *
126 * The _error fields is used the signify that return status of the command. For
127 * simple commands returning `int` the _error field will be the same as the
128 * ret_int field. In complex commands, it signify the success or failure of the
129 * command.
130 *
131 */
df5b86c8 132struct run_as_ret {
fe9f7760
FD
133 int fd;
134 union {
135 struct run_as_mkdir_ret mkdir;
136 struct run_as_open_ret open;
137 struct run_as_unlink_ret unlink;
138 struct run_as_rmdir_recursive_ret rmdir_recursive;
241e0a5a 139 struct run_as_extract_elf_symbol_offset_ret extract_elf_symbol_offset;
fe9f7760 140 } u;
df5b86c8 141 int _errno;
fe9f7760 142 bool _error;
df5b86c8
MD
143};
144
7567352f
MD
145struct run_as_worker {
146 pid_t pid; /* Worker PID. */
147 int sockpair[2];
148 char *procname;
149};
150
151/* Single global worker per process (for now). */
152static struct run_as_worker *global_worker;
153/* Lock protecting the worker. */
154static pthread_mutex_t worker_lock = PTHREAD_MUTEX_INITIALIZER;
155
8f0044bf
MD
156#ifdef VALGRIND
157static
158int use_clone(void)
159{
160 return 0;
161}
162#else
163static
164int use_clone(void)
165{
e8fa9fb0 166 return !lttng_secure_getenv("LTTNG_DEBUG_NOCLONE");
8f0044bf
MD
167}
168#endif
169
d77dded2
JG
170LTTNG_HIDDEN
171int _utils_mkdir_recursive_unsafe(const char *path, mode_t mode);
172
60b6c79c
MD
173/*
174 * Create recursively directory using the FULL path.
175 */
176static
fe9f7760 177int _mkdir_recursive(struct run_as_data *data, struct run_as_ret *ret_value)
60b6c79c 178{
60b6c79c 179 const char *path;
60b6c79c 180 mode_t mode;
60b6c79c 181
7567352f
MD
182 path = data->u.mkdir.path;
183 mode = data->u.mkdir.mode;
60b6c79c 184
d77dded2 185 /* Safe to call as we have transitioned to the requested uid/gid. */
fe9f7760
FD
186 ret_value->u.mkdir.ret = _utils_mkdir_recursive_unsafe(path, mode);
187 ret_value->_errno = errno;
188 ret_value->_error = (ret_value->u.mkdir.ret) ? true : false;
189 return ret_value->u.mkdir.ret;
60b6c79c
MD
190}
191
192static
fe9f7760 193int _mkdir(struct run_as_data *data, struct run_as_ret *ret_value)
60b6c79c 194{
fe9f7760
FD
195 ret_value->u.mkdir.ret = mkdir(data->u.mkdir.path, data->u.mkdir.mode);
196 ret_value->_errno = errno;
197 ret_value->_error = (ret_value->u.mkdir.ret) ? true : false;
198 return ret_value->u.mkdir.ret;
7567352f 199}
7ce36756 200
7567352f 201static
fe9f7760 202int _open(struct run_as_data *data, struct run_as_ret *ret_value)
7567352f 203{
fe9f7760
FD
204 ret_value->u.open.ret = open(data->u.open.path, data->u.open.flags, data->u.open.mode);
205 ret_value->fd = ret_value->u.open.ret;
206 ret_value->_errno = errno;
207 ret_value->_error = (ret_value->u.open.ret) ? true : false;
208 return ret_value->u.open.ret;
7567352f
MD
209}
210
211static
fe9f7760 212int _unlink(struct run_as_data *data, struct run_as_ret *ret_value)
7567352f 213{
fe9f7760
FD
214 ret_value->u.unlink.ret = unlink(data->u.unlink.path);
215 ret_value->_errno = errno;
216 ret_value->_error = (ret_value->u.unlink.ret) ? true : false;
217 return ret_value->u.unlink.ret;
60b6c79c
MD
218}
219
220static
fe9f7760 221int _rmdir_recursive(struct run_as_data *data, struct run_as_ret *ret_value)
60b6c79c 222{
fe9f7760
FD
223 ret_value->u.rmdir_recursive.ret = utils_recursive_rmdir(data->u.rmdir_recursive.path);
224 ret_value->_errno = errno;
225 ret_value->_error = (ret_value->u.rmdir_recursive.ret) ? true : false;
226 return ret_value->u.rmdir_recursive.ret;
7567352f 227}
df5b86c8 228
241e0a5a
FD
229static
230int _extract_elf_symbol_offset(struct run_as_data *data,
231 struct run_as_ret *ret_value)
232{
233 int ret = 0;
234 ret_value->_error = false;
235
236 ret = lttng_elf_get_symbol_offset(data->fd,
237 data->u.extract_elf_symbol_offset.function,
238 &ret_value->u.extract_elf_symbol_offset.offset);
239 if (ret) {
240 DBG("Failed to extract ELF function offset");
241 ret_value->_error = true;
242 }
243
244 return ret;
245}
246
247
7567352f
MD
248static
249run_as_fct run_as_enum_to_fct(enum run_as_cmd cmd)
250{
251 switch (cmd) {
252 case RUN_AS_MKDIR:
253 return _mkdir;
254 case RUN_AS_OPEN:
255 return _open;
256 case RUN_AS_UNLINK:
257 return _unlink;
258 case RUN_AS_RMDIR_RECURSIVE:
259 return _rmdir_recursive;
260 case RUN_AS_MKDIR_RECURSIVE:
261 return _mkdir_recursive;
241e0a5a
FD
262 case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET:
263 return _extract_elf_symbol_offset;
7567352f 264 default:
62a7b8ed 265 ERR("Unknown command %d", (int) cmd);
7567352f
MD
266 return NULL;
267 }
60b6c79c
MD
268}
269
4628484a 270static
fe9f7760 271int do_send_fd(int sock, int fd)
4628484a 272{
7567352f 273 ssize_t len;
4628484a 274
7567352f 275 if (fd < 0) {
fe9f7760 276 ERR("Invalid file description");
7567352f
MD
277 return 0;
278 }
fe9f7760
FD
279
280 len = lttcomm_send_fds_unix_sock(sock, &fd, 1);
7567352f
MD
281 if (len < 0) {
282 PERROR("lttcomm_send_fds_unix_sock");
283 return -1;
284 }
7567352f 285 return 0;
4628484a
MD
286}
287
288static
fe9f7760 289int do_recv_fd(int sock, int *fd)
4628484a 290{
7567352f 291 ssize_t len;
4628484a 292
7567352f 293 if (*fd < 0) {
fe9f7760 294 ERR("Invalid file description");
7567352f
MD
295 return 0;
296 }
fe9f7760
FD
297
298 len = lttcomm_recv_fds_unix_sock(sock, fd, 1);
299
da9ee832
JG
300 if (!len) {
301 return -1;
302 } else if (len < 0) {
7567352f
MD
303 PERROR("lttcomm_recv_fds_unix_sock");
304 return -1;
305 }
306 return 0;
4628484a
MD
307}
308
fe9f7760
FD
309static
310int send_fd_to_worker(struct run_as_worker *worker, enum run_as_cmd cmd, int fd)
311{
312 int ret = 0;
313
314 switch (cmd) {
241e0a5a
FD
315 case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET:
316 break;
fe9f7760
FD
317 default:
318 return 0;
319 }
320
321 ret = do_send_fd(worker->sockpair[0], fd);
322 if (ret < 0) {
323 PERROR("do_send_fd");
324 ret = -1;
325 }
326
327 return ret;
328}
329
330static
331int send_fd_to_master(struct run_as_worker *worker, enum run_as_cmd cmd, int fd)
332{
333 int ret = 0, ret_close = 0;
334
335 switch (cmd) {
336 case RUN_AS_OPEN:
337 break;
338 default:
339 return 0;
340 }
341
342 ret = do_send_fd(worker->sockpair[1], fd);
343 if (ret < 0) {
344 PERROR("do_send_fd error");
345 ret = -1;
346 }
347
348 ret_close = close(fd);
349 if (ret_close < 0) {
350 PERROR("close");
351 }
352
353 return ret;
354}
355
356static
357int recv_fd_from_worker(struct run_as_worker *worker, enum run_as_cmd cmd, int *fd)
358{
359 int ret = 0;
360
361 switch (cmd) {
362 case RUN_AS_OPEN:
363 break;
364 default:
365 return 0;
366 }
367
368 ret = do_recv_fd(worker->sockpair[0], fd);
369 if (ret < 0) {
370 PERROR("do_recv_fd error");
371 ret = -1;
372 }
373
374 return ret;
375}
376
377static
378int recv_fd_from_master(struct run_as_worker *worker, enum run_as_cmd cmd, int *fd)
379{
380 int ret = 0;
381
382 switch (cmd) {
241e0a5a
FD
383 case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET:
384 break;
fe9f7760
FD
385 default:
386 return 0;
387 }
388
389 ret = do_recv_fd(worker->sockpair[1], fd);
390 if (ret < 0) {
391 PERROR("do_recv_fd error");
392 ret = -1;
393 }
394
395 return ret;
396}
397
398static
399int cleanup_received_fd(enum run_as_cmd cmd, int fd)
400{
401 int ret = 0;
402
403 switch (cmd) {
241e0a5a
FD
404 case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET:
405 break;
fe9f7760
FD
406 default:
407 return 0;
408 }
409
410 ret = close(fd);
411 if (ret < 0) {
412 PERROR("close error");
413 ret = -1;
414 }
415
416 return ret;
417}
7567352f
MD
418/*
419 * Return < 0 on error, 0 if OK, 1 on hangup.
420 */
c2b75c49 421static
7567352f 422int handle_one_cmd(struct run_as_worker *worker)
c2b75c49 423{
7567352f
MD
424 int ret = 0;
425 struct run_as_data data;
426 ssize_t readlen, writelen;
df5b86c8 427 struct run_as_ret sendret;
7567352f
MD
428 run_as_fct cmd;
429 uid_t prev_euid;
430
fe9f7760
FD
431 /*
432 * Stage 1: Receive run_as_data struct from the master.
433 * The structure contains the command type and all the parameters needed for
434 * its execution
435 */
7567352f
MD
436 readlen = lttcomm_recv_unix_sock(worker->sockpair[1], &data,
437 sizeof(data));
438 if (readlen == 0) {
439 /* hang up */
440 ret = 1;
441 goto end;
442 }
443 if (readlen < sizeof(data)) {
444 PERROR("lttcomm_recv_unix_sock error");
445 ret = -1;
446 goto end;
447 }
c2b75c49 448
7567352f
MD
449 cmd = run_as_enum_to_fct(data.cmd);
450 if (!cmd) {
451 ret = -1;
452 goto end;
453 }
454
fe9f7760
FD
455 /*
456 * Stage 2: Receive file descriptor from master.
457 * Some commands need a file descriptor as input so if it's needed we
458 * receive the fd using the Unix socket.
459 */
460 ret = recv_fd_from_master(worker, data.cmd, &data.fd);
461 if (ret < 0) {
462 PERROR("recv_fd_from_master error");
463 ret = -1;
464 goto end;
465 }
466
7567352f
MD
467 prev_euid = getuid();
468 if (data.gid != getegid()) {
469 ret = setegid(data.gid);
1576d582 470 if (ret < 0) {
4c462e79 471 PERROR("setegid");
6d73c4ef 472 goto write_return;
1576d582 473 }
c2b75c49 474 }
7567352f
MD
475 if (data.uid != prev_euid) {
476 ret = seteuid(data.uid);
1576d582 477 if (ret < 0) {
4c462e79 478 PERROR("seteuid");
6d73c4ef 479 goto write_return;
1576d582 480 }
c2b75c49 481 }
fe9f7760 482
c2b75c49
MD
483 /*
484 * Also set umask to 0 for mkdir executable bit.
485 */
486 umask(0);
fe9f7760
FD
487
488 /*
489 * Stage 3: Execute the command
490 */
491 ret = (*cmd)(&data, &sendret);
492 if (ret < 0) {
493 DBG("Execution of command returned an error");
494 }
6d73c4ef
MD
495
496write_return:
fe9f7760
FD
497 ret = cleanup_received_fd(data.cmd, data.fd);
498 if (ret < 0) {
499 ERR("Error cleaning up FD");
500 goto end;
501 }
502
503 /*
504 * Stage 4: Send run_as_ret structure to the master.
505 * This structure contain the return value of the command and the errno.
506 */
7567352f
MD
507 writelen = lttcomm_send_unix_sock(worker->sockpair[1], &sendret,
508 sizeof(sendret));
6cd525e8 509 if (writelen < sizeof(sendret)) {
7567352f
MD
510 PERROR("lttcomm_send_unix_sock error");
511 ret = -1;
512 goto end;
513 }
fe9f7760
FD
514
515 /*
516 * Stage 5: Send file descriptor to the master
517 * Some commands return a file descriptor so if it's needed we pass it back
518 * to the master using the Unix socket.
519 */
520 ret = send_fd_to_master(worker, data.cmd, sendret.fd);
521 if (ret < 0) {
522 DBG("Sending FD to master returned an error");
7567352f
MD
523 goto end;
524 }
fe9f7760 525
7567352f
MD
526 if (seteuid(prev_euid) < 0) {
527 PERROR("seteuid");
528 ret = -1;
529 goto end;
530 }
531 ret = 0;
532end:
533 return ret;
534}
535
536static
537int run_as_worker(struct run_as_worker *worker)
538{
539 int ret;
540 ssize_t writelen;
541 struct run_as_ret sendret;
542 size_t proc_orig_len;
543
544 /*
545 * Initialize worker. Set a different process cmdline.
546 */
547 proc_orig_len = strlen(worker->procname);
548 memset(worker->procname, 0, proc_orig_len);
549 strncpy(worker->procname, DEFAULT_RUN_AS_WORKER_NAME, proc_orig_len);
550
e1055edb
JG
551 ret = lttng_prctl(PR_SET_NAME,
552 (unsigned long) DEFAULT_RUN_AS_WORKER_NAME, 0, 0, 0);
553 if (ret && ret != -ENOSYS) {
b8090274
JG
554 /* Don't fail as this is not essential. */
555 PERROR("prctl PR_SET_NAME");
6cd525e8 556 }
7567352f 557
fe9f7760
FD
558 memset(&sendret, 0, sizeof(sendret));
559
7567352f
MD
560 writelen = lttcomm_send_unix_sock(worker->sockpair[1], &sendret,
561 sizeof(sendret));
562 if (writelen < sizeof(sendret)) {
563 PERROR("lttcomm_send_unix_sock error");
564 ret = EXIT_FAILURE;
565 goto end;
566 }
567
568 for (;;) {
569 ret = handle_one_cmd(worker);
570 if (ret < 0) {
571 ret = EXIT_FAILURE;
572 goto end;
573 } else if (ret > 0) {
574 break;
575 } else {
576 continue; /* Next command. */
577 }
578 }
579 ret = EXIT_SUCCESS;
580end:
581 return ret;
c2b75c49
MD
582}
583
60b6c79c 584static
7567352f
MD
585int run_as_cmd(struct run_as_worker *worker,
586 enum run_as_cmd cmd,
587 struct run_as_data *data,
fe9f7760 588 struct run_as_ret *ret_value,
7567352f 589 uid_t uid, gid_t gid)
60b6c79c 590{
fe9f7760 591 int ret = 0;
7567352f 592 ssize_t readlen, writelen;
60b6c79c
MD
593
594 /*
595 * If we are non-root, we can only deal with our own uid.
596 */
597 if (geteuid() != 0) {
598 if (uid != geteuid()) {
fe9f7760
FD
599 ret = -1;
600 ret_value->_errno = EPERM;
60b6c79c 601 ERR("Client (%d)/Server (%d) UID mismatch (and sessiond is not root)",
08797918 602 (int) uid, (int) geteuid());
df5b86c8 603 goto end;
60b6c79c 604 }
60b6c79c
MD
605 }
606
7567352f
MD
607 data->cmd = cmd;
608 data->uid = uid;
609 data->gid = gid;
610
fe9f7760
FD
611 /*
612 * Stage 1: Send the run_as_data struct to the worker process
613 */
7567352f
MD
614 writelen = lttcomm_send_unix_sock(worker->sockpair[0], data,
615 sizeof(*data));
616 if (writelen < sizeof(*data)) {
617 PERROR("Error writing message to run_as");
fe9f7760
FD
618 ret = -1;
619 ret_value->_errno = EIO;
60b6c79c 620 goto end;
c2b75c49 621 }
7567352f 622
fe9f7760
FD
623 /*
624 * Stage 2: Send file descriptor to the worker process if needed
625 */
626 ret = send_fd_to_worker(worker, data->cmd, data->fd);
627 if (ret) {
628 PERROR("do_send_fd error");
629 ret = -1;
630 ret_value->_errno = EIO;
631 goto end;
632 }
633
634 /*
635 * Stage 3: Wait for the execution of the command
636 */
637
638 /*
639 * Stage 4: Receive the run_as_ret struct containing the return value and
640 * errno
641 */
642 readlen = lttcomm_recv_unix_sock(worker->sockpair[0], ret_value,
643 sizeof(*ret_value));
da9ee832
JG
644 if (!readlen) {
645 ERR("Run-as worker has hung-up during run_as_cmd");
fe9f7760
FD
646 ret = -1;
647 ret_value->_errno = EIO;
da9ee832 648 goto end;
fe9f7760 649 } else if (readlen < sizeof(*ret_value)) {
7567352f 650 PERROR("Error reading response from run_as");
fe9f7760
FD
651 ret = -1;
652 ret_value->_errno = errno;
6cd525e8 653 }
fe9f7760
FD
654
655 /*
656 * Stage 5: Receive file descriptor if needed
657 */
658 ret = recv_fd_from_worker(worker, data->cmd, &ret_value->fd);
659 if (ret < 0) {
660 ERR("Error receiving fd");
661 ret = -1;
662 ret_value->_errno = EIO;
4c462e79 663 }
7567352f 664
60b6c79c 665end:
fe9f7760 666 return ret;
60b6c79c
MD
667}
668
2d85a600 669/*
7567352f 670 * This is for debugging ONLY and should not be considered secure.
2d85a600
MD
671 */
672static
fe9f7760
FD
673int run_as_noworker(enum run_as_cmd cmd,
674 struct run_as_data *data, struct run_as_ret *ret_value,
675 uid_t uid, gid_t gid)
2d85a600 676{
df5b86c8 677 int ret, saved_errno;
5b73926f 678 mode_t old_mask;
7567352f 679 run_as_fct fct;
5b73926f 680
7567352f
MD
681 fct = run_as_enum_to_fct(cmd);
682 if (!fct) {
683 errno = -ENOSYS;
684 ret = -1;
685 goto end;
686 }
5b73926f 687 old_mask = umask(0);
fe9f7760
FD
688 ret = fct(data, ret_value);
689 saved_errno = ret_value->_errno;
5b73926f 690 umask(old_mask);
df5b86c8 691 errno = saved_errno;
7567352f 692end:
5b73926f 693 return ret;
2d85a600
MD
694}
695
696static
fe9f7760 697int run_as_restart_worker(struct run_as_worker *worker)
2d85a600 698{
fe9f7760
FD
699 int ret = 0;
700 char *procname = NULL;
701
702 procname = worker->procname;
703
704 /* Close socket to run_as worker process and clean up the zombie process */
705 run_as_destroy_worker();
706
707 /* Create a new run_as worker process*/
708 ret = run_as_create_worker(procname);
709 if (ret < 0 ) {
710 ERR("Restarting the worker process failed");
711 ret = -1;
712 goto err;
713 }
714err:
715 return ret;
716}
717
718static
719int run_as(enum run_as_cmd cmd, struct run_as_data *data,
720 struct run_as_ret *ret_value, uid_t uid, gid_t gid)
721{
722 int ret, saved_errno;
7567352f 723
749b7a0c 724 if (use_clone()) {
7567352f 725 DBG("Using run_as worker");
749b7a0c
JG
726 pthread_mutex_lock(&worker_lock);
727 assert(global_worker);
749b7a0c 728
fe9f7760
FD
729 ret = run_as_cmd(global_worker, cmd, data, ret_value, uid, gid);
730 saved_errno = ret_value->_errno;
731
732 pthread_mutex_unlock(&worker_lock);
733 /*
734 * If the worker thread crashed the errno is set to EIO. we log
735 * the error and start a new worker process.
736 */
737 if (ret == -1 && saved_errno == EIO) {
738 DBG("Socket closed unexpectedly... "
739 "Restarting the worker process");
740 ret = run_as_restart_worker(global_worker);
741
742 if (ret == -1) {
743 ERR("Failed to restart worker process.");
744 goto err;
745 }
746 }
2d85a600 747 } else {
7567352f 748 DBG("Using run_as without worker");
fe9f7760 749 ret = run_as_noworker(cmd, data, ret_value, uid, gid);
2d85a600 750 }
fe9f7760 751err:
7567352f 752 return ret;
2d85a600
MD
753}
754
90e535ef 755LTTNG_HIDDEN
e11d277b 756int run_as_mkdir_recursive(const char *path, mode_t mode, uid_t uid, gid_t gid)
60b6c79c 757{
7567352f 758 struct run_as_data data;
fe9f7760 759 struct run_as_ret ret;
60b6c79c 760
8446e5eb 761 memset(&data, 0, sizeof(data));
fe9f7760 762 memset(&ret, 0, sizeof(ret));
60b6c79c 763 DBG3("mkdir() recursive %s with mode %d for uid %d and gid %d",
08797918 764 path, (int) mode, (int) uid, (int) gid);
7567352f
MD
765 strncpy(data.u.mkdir.path, path, PATH_MAX - 1);
766 data.u.mkdir.path[PATH_MAX - 1] = '\0';
767 data.u.mkdir.mode = mode;
fe9f7760
FD
768
769 run_as(RUN_AS_MKDIR_RECURSIVE, &data, &ret, uid, gid);
770 errno = ret._errno;
771 return ret.u.mkdir.ret;
60b6c79c
MD
772}
773
90e535ef 774LTTNG_HIDDEN
e11d277b 775int run_as_mkdir(const char *path, mode_t mode, uid_t uid, gid_t gid)
60b6c79c 776{
7567352f 777 struct run_as_data data;
fe9f7760 778 struct run_as_ret ret;
60b6c79c 779
8446e5eb 780 memset(&data, 0, sizeof(data));
fe9f7760
FD
781 memset(&ret, 0, sizeof(ret));
782
60b6c79c 783 DBG3("mkdir() %s with mode %d for uid %d and gid %d",
08797918 784 path, (int) mode, (int) uid, (int) gid);
7567352f
MD
785 strncpy(data.u.mkdir.path, path, PATH_MAX - 1);
786 data.u.mkdir.path[PATH_MAX - 1] = '\0';
787 data.u.mkdir.mode = mode;
fe9f7760
FD
788 run_as(RUN_AS_MKDIR, &data, &ret, uid, gid);
789 errno = ret._errno;
790 return ret.u.mkdir.ret;
60b6c79c
MD
791}
792
90e535ef 793LTTNG_HIDDEN
e11d277b 794int run_as_open(const char *path, int flags, mode_t mode, uid_t uid, gid_t gid)
60b6c79c 795{
7567352f 796 struct run_as_data data;
fe9f7760 797 struct run_as_ret ret;
c2b75c49 798
8446e5eb 799 memset(&data, 0, sizeof(data));
fe9f7760
FD
800 memset(&ret, 0, sizeof(ret));
801
47fb7563 802 DBG3("open() %s with flags %X mode %d for uid %d and gid %d",
08797918 803 path, flags, (int) mode, (int) uid, (int) gid);
7567352f
MD
804 strncpy(data.u.open.path, path, PATH_MAX - 1);
805 data.u.open.path[PATH_MAX - 1] = '\0';
806 data.u.open.flags = flags;
807 data.u.open.mode = mode;
fe9f7760
FD
808 run_as(RUN_AS_OPEN, &data, &ret, uid, gid);
809 errno = ret._errno;
810 ret.u.open.ret = ret.fd;
811 return ret.u.open.ret;
60b6c79c 812}
4628484a
MD
813
814LTTNG_HIDDEN
815int run_as_unlink(const char *path, uid_t uid, gid_t gid)
816{
7567352f 817 struct run_as_data data;
fe9f7760 818 struct run_as_ret ret;
4628484a 819
8446e5eb 820 memset(&data, 0, sizeof(data));
fe9f7760
FD
821 memset(&ret, 0, sizeof(ret));
822
4628484a 823 DBG3("unlink() %s with for uid %d and gid %d",
08797918 824 path, (int) uid, (int) gid);
7567352f
MD
825 strncpy(data.u.unlink.path, path, PATH_MAX - 1);
826 data.u.unlink.path[PATH_MAX - 1] = '\0';
fe9f7760
FD
827 run_as(RUN_AS_UNLINK, &data, &ret, uid, gid);
828 errno = ret._errno;
829 return ret.u.unlink.ret;
4628484a
MD
830}
831
832LTTNG_HIDDEN
7567352f 833int run_as_rmdir_recursive(const char *path, uid_t uid, gid_t gid)
4628484a 834{
7567352f 835 struct run_as_data data;
fe9f7760
FD
836 struct run_as_ret ret;
837
838 memset(&data, 0, sizeof(data));
839 memset(&ret, 0, sizeof(ret));
4628484a 840
7567352f 841 DBG3("rmdir_recursive() %s with for uid %d and gid %d",
08797918 842 path, (int) uid, (int) gid);
7567352f
MD
843 strncpy(data.u.rmdir_recursive.path, path, PATH_MAX - 1);
844 data.u.rmdir_recursive.path[PATH_MAX - 1] = '\0';
fe9f7760
FD
845 run_as(RUN_AS_RMDIR_RECURSIVE, &data, &ret, uid, gid);
846 errno = ret._errno;
847 return ret.u.rmdir_recursive.ret;
7567352f
MD
848}
849
241e0a5a
FD
850LTTNG_HIDDEN
851int run_as_extract_elf_symbol_offset(int fd, const char* function,
852 uid_t uid, gid_t gid, uint64_t *offset)
853{
854 struct run_as_data data;
855 struct run_as_ret ret;
856
857 DBG3("extract_elf_symbol_offset() on fd=%d and function=%s "
858 "with for uid %d and gid %d", fd, function, (int) uid, (int) gid);
859
860 data.fd = fd;
861
862 strncpy(data.u.extract_elf_symbol_offset.function, function, LTTNG_SYMBOL_NAME_LEN - 1);
863
864 data.u.extract_elf_symbol_offset.function[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
865
866 run_as(RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET, &data, &ret, uid, gid);
867
868 errno = ret._errno;
869
870 if (ret._error) {
871 return -1;
872 }
873
874 *offset = ret.u.extract_elf_symbol_offset.offset;
875 return 0;
876}
877
f8f66d38 878static
a80ed305 879int reset_sighandler(void)
f8f66d38 880{
5b5bb8c8 881 int sig;
f8f66d38 882
978d5d79 883 DBG("Resetting run_as worker signal handlers to default");
5b5bb8c8
JG
884 for (sig = 1; sig <= 31; sig++) {
885 (void) signal(sig, SIG_DFL);
f8f66d38 886 }
5b5bb8c8 887 return 0;
a80ed305
JG
888}
889
890static
891void worker_sighandler(int sig)
892{
893 const char *signame;
894
895 /*
cd89f030
JG
896 * The worker will inherit its parent's signals since they are part of
897 * the same process group. However, in the case of SIGINT and SIGTERM,
898 * we want to give the worker a chance to teardown gracefully when its
899 * parent closes the command socket.
a80ed305
JG
900 */
901 switch (sig) {
902 case SIGINT:
903 signame = "SIGINT";
904 break;
905 case SIGTERM:
906 signame = "SIGTERM";
907 break;
908 default:
22d5e48e 909 signame = NULL;
a80ed305
JG
910 }
911
22d5e48e
JG
912 if (signame) {
913 DBG("run_as worker received signal %s", signame);
914 } else {
915 DBG("run_as_worker received signal %d", sig);
916 }
a80ed305
JG
917}
918
919static
920int set_worker_sighandlers(void)
921{
922 int ret = 0;
923 sigset_t sigset;
924 struct sigaction sa;
925
926 if ((ret = sigemptyset(&sigset)) < 0) {
927 PERROR("sigemptyset");
928 goto end;
929 }
930
931 sa.sa_handler = worker_sighandler;
932 sa.sa_mask = sigset;
933 sa.sa_flags = 0;
934 if ((ret = sigaction(SIGINT, &sa, NULL)) < 0) {
935 PERROR("sigaction SIGINT");
936 goto end;
937 }
938
939 if ((ret = sigaction(SIGTERM, &sa, NULL)) < 0) {
940 PERROR("sigaction SIGTERM");
941 goto end;
942 }
943
944 DBG("run_as signal handler set for SIGTERM and SIGINT");
945end:
946 return ret;
f8f66d38
JG
947}
948
7567352f
MD
949LTTNG_HIDDEN
950int run_as_create_worker(char *procname)
951{
952 pid_t pid;
953 int i, ret = 0;
954 ssize_t readlen;
955 struct run_as_ret recvret;
956 struct run_as_worker *worker;
957
749b7a0c
JG
958 pthread_mutex_lock(&worker_lock);
959 assert(!global_worker);
7567352f 960 if (!use_clone()) {
749b7a0c
JG
961 /*
962 * Don't initialize a worker, all run_as tasks will be performed
963 * in the current process.
964 */
7567352f
MD
965 ret = 0;
966 goto end;
967 }
968 worker = zmalloc(sizeof(*worker));
969 if (!worker) {
970 ret = -ENOMEM;
971 goto end;
972 }
973 worker->procname = procname;
974 /* Create unix socket. */
975 if (lttcomm_create_anon_unix_socketpair(worker->sockpair) < 0) {
976 ret = -1;
977 goto error_sock;
978 }
fe9f7760 979
7567352f
MD
980 /* Fork worker. */
981 pid = fork();
982 if (pid < 0) {
983 PERROR("fork");
984 ret = -1;
985 goto error_fork;
986 } else if (pid == 0) {
987 /* Child */
988
f8f66d38
JG
989 reset_sighandler();
990
a80ed305
JG
991 set_worker_sighandlers();
992
749b7a0c
JG
993 /* The child has no use for this lock. */
994 pthread_mutex_unlock(&worker_lock);
7567352f
MD
995 /* Just close, no shutdown. */
996 if (close(worker->sockpair[0])) {
997 PERROR("close");
998 exit(EXIT_FAILURE);
999 }
fe9f7760
FD
1000
1001 /*
1002 * Close all FDs aside from STDIN, STDOUT, STDERR and sockpair[1]
1003 * Sockpair[1] is used as a control channel with the master
1004 */
1005 for (i = 3; i < sysconf(_SC_OPEN_MAX); i++) {
1006 if (i != worker->sockpair[1]) {
1007 (void) close(i);
1008 }
1009 }
1010
7567352f
MD
1011 worker->sockpair[0] = -1;
1012 ret = run_as_worker(worker);
1013 if (lttcomm_close_unix_sock(worker->sockpair[1])) {
1014 PERROR("close");
1015 ret = -1;
1016 }
1017 worker->sockpair[1] = -1;
978d5d79 1018 LOG(ret ? PRINT_ERR : PRINT_DBG, "run_as worker exiting (ret = %d)", ret);
7567352f
MD
1019 exit(ret ? EXIT_FAILURE : EXIT_SUCCESS);
1020 } else {
1021 /* Parent */
1022
1023 /* Just close, no shutdown. */
1024 if (close(worker->sockpair[1])) {
1025 PERROR("close");
1026 ret = -1;
1027 goto error_fork;
1028 }
1029 worker->sockpair[1] = -1;
1030 worker->pid = pid;
1031 /* Wait for worker to become ready. */
1032 readlen = lttcomm_recv_unix_sock(worker->sockpair[0],
1033 &recvret, sizeof(recvret));
1034 if (readlen < sizeof(recvret)) {
1035 ERR("readlen: %zd", readlen);
1036 PERROR("Error reading response from run_as at creation");
1037 ret = -1;
1038 goto error_fork;
1039 }
1040 global_worker = worker;
1041 }
1042end:
749b7a0c 1043 pthread_mutex_unlock(&worker_lock);
7567352f
MD
1044 return ret;
1045
1046 /* Error handling. */
1047error_fork:
1048 for (i = 0; i < 2; i++) {
1049 if (worker->sockpair[i] < 0) {
1050 continue;
1051 }
1052 if (lttcomm_close_unix_sock(worker->sockpair[i])) {
1053 PERROR("close");
1054 }
1055 worker->sockpair[i] = -1;
1056 }
1057error_sock:
1058 free(worker);
749b7a0c 1059 pthread_mutex_unlock(&worker_lock);
7567352f
MD
1060 return ret;
1061}
1062
1063LTTNG_HIDDEN
1064void run_as_destroy_worker(void)
1065{
1066 struct run_as_worker *worker = global_worker;
7567352f 1067
978d5d79 1068 DBG("Destroying run_as worker");
749b7a0c 1069 pthread_mutex_lock(&worker_lock);
7567352f 1070 if (!worker) {
749b7a0c 1071 goto end;
7567352f
MD
1072 }
1073 /* Close unix socket */
978d5d79 1074 DBG("Closing run_as worker socket");
7567352f
MD
1075 if (lttcomm_close_unix_sock(worker->sockpair[0])) {
1076 PERROR("close");
1077 }
1078 worker->sockpair[0] = -1;
1079 /* Wait for worker. */
f8f66d38
JG
1080 for (;;) {
1081 int status;
1082 pid_t wait_ret;
1083
1084 wait_ret = waitpid(worker->pid, &status, 0);
1085 if (wait_ret < 0) {
1086 if (errno == EINTR) {
1087 continue;
1088 }
1089 PERROR("waitpid");
1090 break;
1091 }
1092
1093 if (WIFEXITED(status)) {
1094 LOG(WEXITSTATUS(status) == 0 ? PRINT_DBG : PRINT_ERR,
1095 DEFAULT_RUN_AS_WORKER_NAME " terminated with status code %d",
1096 WEXITSTATUS(status));
1097 break;
1098 } else if (WIFSIGNALED(status)) {
1099 ERR(DEFAULT_RUN_AS_WORKER_NAME " was killed by signal %d",
1100 WTERMSIG(status));
1101 break;
1102 }
7567352f
MD
1103 }
1104 free(worker);
1105 global_worker = NULL;
749b7a0c
JG
1106end:
1107 pthread_mutex_unlock(&worker_lock);
4628484a 1108}
This page took 0.095246 seconds and 4 git commands to generate.