execute.c 49.5 KB
Newer Older
1
2
/*-*- Mode: C; c-basic-offset: 8 -*-*/

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/***
  This file is part of systemd.

  Copyright 2010 Lennart Poettering

  systemd is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  systemd is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/

22
#include <assert.h>
23
24
25
26
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
Lennart Poettering's avatar
Lennart Poettering committed
27
#include <string.h>
28
#include <signal.h>
29
30
#include <sys/socket.h>
#include <sys/un.h>
31
#include <sys/prctl.h>
32
#include <linux/sched.h>
33
34
#include <sys/types.h>
#include <sys/stat.h>
35
36
#include <grp.h>
#include <pwd.h>
37
#include <sys/mount.h>
Kay Sievers's avatar
Kay Sievers committed
38
#include <linux/fs.h>
39
40
41
42
43

#include "execute.h"
#include "strv.h"
#include "macro.h"
#include "util.h"
44
#include "log.h"
45
#include "ioprio.h"
46
#include "securebits.h"
47
#include "cgroup.h"
48
#include "namespace.h"
49
#include "tcpwrap.h"
50

51
52
53
/* This assumes there is a 'tty' group */
#define TTY_MODE 0620

54
55
56
57
58
59
static int shift_fds(int fds[], unsigned n_fds) {
        int start, restart_from;

        if (n_fds <= 0)
                return 0;

60
61
        /* Modifies the fds array! (sorts it) */

62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
        assert(fds);

        start = 0;
        for (;;) {
                int i;

                restart_from = -1;

                for (i = start; i < (int) n_fds; i++) {
                        int nfd;

                        /* Already at right index? */
                        if (fds[i] == i+3)
                                continue;

                        if ((nfd = fcntl(fds[i], F_DUPFD, i+3)) < 0)
                                return -errno;

Lennart Poettering's avatar
Lennart Poettering committed
80
                        close_nointr_nofail(fds[i]);
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
                        fds[i] = nfd;

                        /* Hmm, the fd we wanted isn't free? Then
                         * let's remember that and try again from here*/
                        if (nfd != i+3 && restart_from < 0)
                                restart_from = i;
                }

                if (restart_from < 0)
                        break;

                start = restart_from;
        }

        return 0;
}

98
static int flags_fds(const int fds[], unsigned n_fds, bool nonblock) {
99
        unsigned i;
100
        int r;
101
102
103
104
105
106

        if (n_fds <= 0)
                return 0;

        assert(fds);

107
        /* Drops/Sets O_NONBLOCK and FD_CLOEXEC from the file flags */
108
109
110

        for (i = 0; i < n_fds; i++) {

111
112
                if ((r = fd_nonblock(fds[i], nonblock)) < 0)
                        return r;
113

114
115
116
                /* We unconditionally drop FD_CLOEXEC from the fds,
                 * since after all we want to pass these fds to our
                 * children */
117

118
119
                if ((r = fd_cloexec(fds[i], false)) < 0)
                        return r;
120
121
122
123
124
        }

        return 0;
}

Lennart Poettering's avatar
Lennart Poettering committed
125
126
127
128
129
130
131
132
133
134
135
static const char *tty_path(const ExecContext *context) {
        assert(context);

        if (context->tty_path)
                return context->tty_path;

        return "/dev/console";
}

static int open_null_as(int flags, int nfd) {
        int fd, r;
136

Lennart Poettering's avatar
Lennart Poettering committed
137
        assert(nfd >= 0);
138

Lennart Poettering's avatar
Lennart Poettering committed
139
        if ((fd = open("/dev/null", flags|O_NOCTTY)) < 0)
140
141
                return -errno;

Lennart Poettering's avatar
Lennart Poettering committed
142
143
        if (fd != nfd) {
                r = dup2(fd, nfd) < 0 ? -errno : nfd;
Lennart Poettering's avatar
Lennart Poettering committed
144
                close_nointr_nofail(fd);
Lennart Poettering's avatar
Lennart Poettering committed
145
146
        } else
                r = nfd;
147

Lennart Poettering's avatar
Lennart Poettering committed
148
        return r;
149
150
}

Lennart Poettering's avatar
Lennart Poettering committed
151
152
153
154
155
156
static int connect_logger_as(const ExecContext *context, ExecOutput output, const char *ident, int nfd) {
        int fd, r;
        union {
                struct sockaddr sa;
                struct sockaddr_un un;
        } sa;
157
158

        assert(context);
Lennart Poettering's avatar
Lennart Poettering committed
159
160
161
        assert(output < _EXEC_OUTPUT_MAX);
        assert(ident);
        assert(nfd >= 0);
162

Lennart Poettering's avatar
Lennart Poettering committed
163
164
        if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
                return -errno;
165

Lennart Poettering's avatar
Lennart Poettering committed
166
167
168
        zero(sa);
        sa.sa.sa_family = AF_UNIX;
        strncpy(sa.un.sun_path+1, LOGGER_SOCKET, sizeof(sa.un.sun_path)-1);
169

Lennart Poettering's avatar
Lennart Poettering committed
170
171
172
173
        if (connect(fd, &sa.sa, sizeof(sa)) < 0) {
                close_nointr_nofail(fd);
                return -errno;
        }
174

Lennart Poettering's avatar
Lennart Poettering committed
175
176
177
178
        if (shutdown(fd, SHUT_RD) < 0) {
                close_nointr_nofail(fd);
                return -errno;
        }
179

Lennart Poettering's avatar
Lennart Poettering committed
180
181
182
183
184
185
186
187
188
189
190
        /* We speak a very simple protocol between log server
         * and client: one line for the log destination (kmsg
         * or syslog), followed by the priority field,
         * followed by the process name. Since we replaced
         * stdin/stderr we simple use stdio to write to
         * it. Note that we use stderr, to minimize buffer
         * flushing issues. */

        dprintf(fd,
                "%s\n"
                "%i\n"
191
192
                "%s\n"
                "%i\n",
193
                output == EXEC_OUTPUT_KMSG ? "kmsg" : "syslog",
Lennart Poettering's avatar
Lennart Poettering committed
194
                context->syslog_priority,
195
196
                context->syslog_identifier ? context->syslog_identifier : ident,
                !context->syslog_no_prefix);
Lennart Poettering's avatar
Lennart Poettering committed
197
198
199

        if (fd != nfd) {
                r = dup2(fd, nfd) < 0 ? -errno : nfd;
Lennart Poettering's avatar
Lennart Poettering committed
200
                close_nointr_nofail(fd);
Lennart Poettering's avatar
Lennart Poettering committed
201
202
        } else
                r = nfd;
203

Lennart Poettering's avatar
Lennart Poettering committed
204
205
206
207
        return r;
}
static int open_terminal_as(const char *path, mode_t mode, int nfd) {
        int fd, r;
208

Lennart Poettering's avatar
Lennart Poettering committed
209
210
        assert(path);
        assert(nfd >= 0);
211

Lennart Poettering's avatar
Lennart Poettering committed
212
213
        if ((fd = open_terminal(path, mode | O_NOCTTY)) < 0)
                return fd;
214

Lennart Poettering's avatar
Lennart Poettering committed
215
216
217
218
219
        if (fd != nfd) {
                r = dup2(fd, nfd) < 0 ? -errno : nfd;
                close_nointr_nofail(fd);
        } else
                r = nfd;
220

Lennart Poettering's avatar
Lennart Poettering committed
221
222
        return r;
}
223

Lennart Poettering's avatar
Lennart Poettering committed
224
225
226
227
228
229
static bool is_terminal_input(ExecInput i) {
        return
                i == EXEC_INPUT_TTY ||
                i == EXEC_INPUT_TTY_FORCE ||
                i == EXEC_INPUT_TTY_FAIL;
}
230

231
static int fixup_input(ExecInput std_input, int socket_fd) {
232

233
        if (std_input == EXEC_INPUT_SOCKET && socket_fd < 0)
234
235
                return EXEC_INPUT_NULL;

236
        return std_input;
237
238
}

239
static int fixup_output(ExecOutput std_output, int socket_fd) {
240

241
        if (std_output == EXEC_OUTPUT_SOCKET && socket_fd < 0)
242
243
                return EXEC_OUTPUT_INHERIT;

244
        return std_output;
245
246
247
248
249
250
251
}

static int setup_input(const ExecContext *context, int socket_fd) {
        ExecInput i;

        assert(context);

252
        i = fixup_input(context->std_input, socket_fd);
253
254

        switch (i) {
255

Lennart Poettering's avatar
Lennart Poettering committed
256
257
258
259
260
261
262
        case EXEC_INPUT_NULL:
                return open_null_as(O_RDONLY, STDIN_FILENO);

        case EXEC_INPUT_TTY:
        case EXEC_INPUT_TTY_FORCE:
        case EXEC_INPUT_TTY_FAIL: {
                int fd, r;
263

Lennart Poettering's avatar
Lennart Poettering committed
264
265
                if ((fd = acquire_terminal(
                                     tty_path(context),
266
                                     i == EXEC_INPUT_TTY_FAIL,
267
268
                                     i == EXEC_INPUT_TTY_FORCE,
                                     false)) < 0)
Lennart Poettering's avatar
Lennart Poettering committed
269
270
271
272
                        return fd;

                if (fd != STDIN_FILENO) {
                        r = dup2(fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO;
273
                        close_nointr_nofail(fd);
Lennart Poettering's avatar
Lennart Poettering committed
274
275
276
277
278
279
                } else
                        r = STDIN_FILENO;

                return r;
        }

280
281
282
        case EXEC_INPUT_SOCKET:
                return dup2(socket_fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO;

Lennart Poettering's avatar
Lennart Poettering committed
283
284
285
286
287
        default:
                assert_not_reached("Unknown input type");
        }
}

288
289
290
291
static int setup_output(const ExecContext *context, int socket_fd, const char *ident) {
        ExecOutput o;
        ExecInput i;

Lennart Poettering's avatar
Lennart Poettering committed
292
293
294
        assert(context);
        assert(ident);

295
296
        i = fixup_input(context->std_input, socket_fd);
        o = fixup_output(context->std_output, socket_fd);
297

Lennart Poettering's avatar
Lennart Poettering committed
298
299
        /* This expects the input is already set up */

300
        switch (o) {
301

Lennart Poettering's avatar
Lennart Poettering committed
302
303
304
        case EXEC_OUTPUT_INHERIT:

                /* If the input is connected to a terminal, inherit that... */
305
                if (i != EXEC_INPUT_NULL)
Lennart Poettering's avatar
Lennart Poettering committed
306
                        return dup2(STDIN_FILENO, STDOUT_FILENO) < 0 ? -errno : STDOUT_FILENO;
307

308
                /* For PID 1 stdout is always connected to /dev/null,
309
310
                 * hence reopen the console if out parent is PID1. */
                if (getppid() == 1)
311
312
313
                        return open_terminal_as(tty_path(context), O_WRONLY, STDOUT_FILENO);

                return STDOUT_FILENO;
Lennart Poettering's avatar
Lennart Poettering committed
314
315
316
317

        case EXEC_OUTPUT_NULL:
                return open_null_as(O_WRONLY, STDOUT_FILENO);

318
319
        case EXEC_OUTPUT_TTY:
                if (is_terminal_input(i))
Lennart Poettering's avatar
Lennart Poettering committed
320
321
322
323
                        return dup2(STDIN_FILENO, STDOUT_FILENO) < 0 ? -errno : STDOUT_FILENO;

                /* We don't reset the terminal if this is just about output */
                return open_terminal_as(tty_path(context), O_WRONLY, STDOUT_FILENO);
324

Lennart Poettering's avatar
Lennart Poettering committed
325
        case EXEC_OUTPUT_SYSLOG:
326
        case EXEC_OUTPUT_KMSG:
327
328
329
330
331
                return connect_logger_as(context, o, ident, STDOUT_FILENO);

        case EXEC_OUTPUT_SOCKET:
                assert(socket_fd >= 0);
                return dup2(socket_fd, STDOUT_FILENO) < 0 ? -errno : STDOUT_FILENO;
Lennart Poettering's avatar
Lennart Poettering committed
332

333
334
        default:
                assert_not_reached("Unknown output type");
335
        }
336
337
}

338
339
340
341
static int setup_error(const ExecContext *context, int socket_fd, const char *ident) {
        ExecOutput o, e;
        ExecInput i;

342
        assert(context);
343
        assert(ident);
344

345
346
347
        i = fixup_input(context->std_input, socket_fd);
        o = fixup_output(context->std_output, socket_fd);
        e = fixup_output(context->std_error, socket_fd);
348

Lennart Poettering's avatar
Lennart Poettering committed
349
        /* This expects the input and output are already set up */
350

Lennart Poettering's avatar
Lennart Poettering committed
351
352
        /* Don't change the stderr file descriptor if we inherit all
         * the way and are not on a tty */
353
354
        if (e == EXEC_OUTPUT_INHERIT &&
            o == EXEC_OUTPUT_INHERIT &&
355
            i != EXEC_INPUT_NULL &&
356
            getppid () != 1)
Lennart Poettering's avatar
Lennart Poettering committed
357
                return STDERR_FILENO;
358

Lennart Poettering's avatar
Lennart Poettering committed
359
        /* Duplicate form stdout if possible */
360
        if (e == o || e == EXEC_OUTPUT_INHERIT)
Lennart Poettering's avatar
Lennart Poettering committed
361
                return dup2(STDOUT_FILENO, STDERR_FILENO) < 0 ? -errno : STDERR_FILENO;
362

363
        switch (e) {
Lennart Poettering's avatar
Lennart Poettering committed
364
365
366
367
368

        case EXEC_OUTPUT_NULL:
                return open_null_as(O_WRONLY, STDERR_FILENO);

        case EXEC_OUTPUT_TTY:
369
                if (is_terminal_input(i))
Lennart Poettering's avatar
Lennart Poettering committed
370
371
372
373
374
375
                        return dup2(STDIN_FILENO, STDERR_FILENO) < 0 ? -errno : STDERR_FILENO;

                /* We don't reset the terminal if this is just about output */
                return open_terminal_as(tty_path(context), O_WRONLY, STDERR_FILENO);

        case EXEC_OUTPUT_SYSLOG:
376
        case EXEC_OUTPUT_KMSG:
377
378
379
380
381
                return connect_logger_as(context, e, ident, STDERR_FILENO);

        case EXEC_OUTPUT_SOCKET:
                assert(socket_fd >= 0);
                return dup2(socket_fd, STDERR_FILENO) < 0 ? -errno : STDERR_FILENO;
382
383

        default:
Lennart Poettering's avatar
Lennart Poettering committed
384
                assert_not_reached("Unknown error type");
385
        }
386
387
}

388
389
390
391
392
393
static int chown_terminal(int fd, uid_t uid) {
        struct stat st;

        assert(fd >= 0);

        /* This might fail. What matters are the results. */
Lennart Poettering's avatar
Lennart Poettering committed
394
395
        (void) fchown(fd, uid, -1);
        (void) fchmod(fd, TTY_MODE);
396
397
398
399

        if (fstat(fd, &st) < 0)
                return -errno;

400
        if (st.st_uid != uid || (st.st_mode & 0777) != TTY_MODE)
401
402
403
404
405
                return -EPERM;

        return 0;
}

Lennart Poettering's avatar
Lennart Poettering committed
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
static int setup_confirm_stdio(const ExecContext *context,
                               int *_saved_stdin,
                               int *_saved_stdout) {
        int fd = -1, saved_stdin, saved_stdout = -1, r;

        assert(context);
        assert(_saved_stdin);
        assert(_saved_stdout);

        /* This returns positive EXIT_xxx return values instead of
         * negative errno style values! */

        if ((saved_stdin = fcntl(STDIN_FILENO, F_DUPFD, 3)) < 0)
                return EXIT_STDIN;

        if ((saved_stdout = fcntl(STDOUT_FILENO, F_DUPFD, 3)) < 0) {
                r = EXIT_STDOUT;
                goto fail;
        }

        if ((fd = acquire_terminal(
                             tty_path(context),
                             context->std_input == EXEC_INPUT_TTY_FAIL,
429
430
                             context->std_input == EXEC_INPUT_TTY_FORCE,
                             false)) < 0) {
Lennart Poettering's avatar
Lennart Poettering committed
431
432
433
434
                r = EXIT_STDIN;
                goto fail;
        }

435
436
437
438
439
        if (chown_terminal(fd, getuid()) < 0) {
                r = EXIT_STDIN;
                goto fail;
        }

Lennart Poettering's avatar
Lennart Poettering committed
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
        if (dup2(fd, STDIN_FILENO) < 0) {
                r = EXIT_STDIN;
                goto fail;
        }

        if (dup2(fd, STDOUT_FILENO) < 0) {
                r = EXIT_STDOUT;
                goto fail;
        }

        if (fd >= 2)
                close_nointr_nofail(fd);

        *_saved_stdin = saved_stdin;
        *_saved_stdout = saved_stdout;

        return 0;

fail:
        if (saved_stdout >= 0)
                close_nointr_nofail(saved_stdout);

        if (saved_stdin >= 0)
                close_nointr_nofail(saved_stdin);

        if (fd >= 0)
                close_nointr_nofail(fd);

        return r;
}

Lennart Poettering's avatar
Lennart Poettering committed
471
static int restore_confirm_stdio(const ExecContext *context,
Lennart Poettering's avatar
Lennart Poettering committed
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
                                 int *saved_stdin,
                                 int *saved_stdout,
                                 bool *keep_stdin,
                                 bool *keep_stdout) {

        assert(context);
        assert(saved_stdin);
        assert(*saved_stdin >= 0);
        assert(saved_stdout);
        assert(*saved_stdout >= 0);

        /* This returns positive EXIT_xxx return values instead of
         * negative errno style values! */

        if (is_terminal_input(context->std_input)) {

                /* The service wants terminal input. */

                *keep_stdin = true;
                *keep_stdout =
                        context->std_output == EXEC_OUTPUT_INHERIT ||
                        context->std_output == EXEC_OUTPUT_TTY;

        } else {
                /* If the service doesn't want a controlling terminal,
                 * then we need to get rid entirely of what we have
                 * already. */

                if (release_terminal() < 0)
                        return EXIT_STDIN;

                if (dup2(*saved_stdin, STDIN_FILENO) < 0)
                        return EXIT_STDIN;

                if (dup2(*saved_stdout, STDOUT_FILENO) < 0)
                        return EXIT_STDOUT;

                *keep_stdout = *keep_stdin = false;
        }

        return 0;
}

515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
static int get_group_creds(const char *groupname, gid_t *gid) {
        struct group *g;
        unsigned long lu;

        assert(groupname);
        assert(gid);

        /* We enforce some special rules for gid=0: in order to avoid
         * NSS lookups for root we hardcode its data. */

        if (streq(groupname, "root") || streq(groupname, "0")) {
                *gid = 0;
                return 0;
        }

        if (safe_atolu(groupname, &lu) >= 0) {
                errno = 0;
                g = getgrgid((gid_t) lu);
        } else {
                errno = 0;
                g = getgrnam(groupname);
        }

        if (!g)
                return errno != 0 ? -errno : -ESRCH;

        *gid = g->gr_gid;
        return 0;
}

static int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home) {
        struct passwd *p;
        unsigned long lu;

        assert(username);
        assert(*username);
        assert(uid);
        assert(gid);
        assert(home);

        /* We enforce some special rules for uid=0: in order to avoid
         * NSS lookups for root we hardcode its data. */

        if (streq(*username, "root") || streq(*username, "0")) {
                *username = "root";
                *uid = 0;
                *gid = 0;
                *home = "/root";
                return 0;
        }

        if (safe_atolu(*username, &lu) >= 0) {
                errno = 0;
                p = getpwuid((uid_t) lu);

                /* If there are multiple users with the same id, make
                 * sure to leave $USER to the configured value instead
                 * of the first occurence in the database. However if
                 * the uid was configured by a numeric uid, then let's
                 * pick the real username from /etc/passwd. */
                if (*username && p)
                        *username = p->pw_name;
        } else {
                errno = 0;
                p = getpwnam(*username);
        }

        if (!p)
                return errno != 0 ? -errno : -ESRCH;

        *uid = p->pw_uid;
        *gid = p->pw_gid;
        *home = p->pw_dir;
        return 0;
}

static int enforce_groups(const ExecContext *context, const char *username, gid_t gid) {
        bool keep_groups = false;
        int r;

        assert(context);

        /* Lookup and ser GID and supplementary group list. Here too
         * we avoid NSS lookups for gid=0. */

        if (context->group || username) {

                if (context->group)
                        if ((r = get_group_creds(context->group, &gid)) < 0)
                                return r;

                /* First step, initialize groups from /etc/groups */
                if (username && gid != 0) {
                        if (initgroups(username, gid) < 0)
                                return -errno;

                        keep_groups = true;
                }

                /* Second step, set our gids */
                if (setresgid(gid, gid, gid) < 0)
                        return -errno;
        }

        if (context->supplementary_groups) {
                int ngroups_max, k;
                gid_t *gids;
                char **i;

                /* Final step, initialize any manually set supplementary groups */
                ngroups_max = (int) sysconf(_SC_NGROUPS_MAX);

                if (!(gids = new(gid_t, ngroups_max)))
                        return -ENOMEM;

                if (keep_groups) {
                        if ((k = getgroups(ngroups_max, gids)) < 0) {
                                free(gids);
                                return -errno;
                        }
                } else
                        k = 0;

                STRV_FOREACH(i, context->supplementary_groups) {

                        if (k >= ngroups_max) {
                                free(gids);
                                return -E2BIG;
                        }

                        if ((r = get_group_creds(*i, gids+k)) < 0) {
                                free(gids);
                                return r;
                        }

                        k++;
                }

                if (setgroups(k, gids) < 0) {
                        free(gids);
                        return -errno;
                }

                free(gids);
        }

        return 0;
}

static int enforce_user(const ExecContext *context, uid_t uid) {
        int r;
        assert(context);

        /* Sets (but doesn't lookup) the uid and make sure we keep the
         * capabilities while doing so. */

        if (context->capabilities) {
                cap_t d;
                static const cap_value_t bits[] = {
                        CAP_SETUID,   /* Necessary so that we can run setresuid() below */
                        CAP_SETPCAP   /* Necessary so that we can set PR_SET_SECUREBITS later on */
                };

                /* First step: If we need to keep capabilities but
                 * drop privileges we need to make sure we keep our
                 * caps, whiel we drop priviliges. */
681
682
683
684
685
686
687
                if (uid != 0) {
                        int sb = context->secure_bits|SECURE_KEEP_CAPS;

                        if (prctl(PR_GET_SECUREBITS) != sb)
                                if (prctl(PR_SET_SECUREBITS, sb) < 0)
                                        return -errno;
                }
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722

                /* Second step: set the capabilites. This will reduce
                 * the capabilities to the minimum we need. */

                if (!(d = cap_dup(context->capabilities)))
                        return -errno;

                if (cap_set_flag(d, CAP_EFFECTIVE, ELEMENTSOF(bits), bits, CAP_SET) < 0 ||
                    cap_set_flag(d, CAP_PERMITTED, ELEMENTSOF(bits), bits, CAP_SET) < 0) {
                        r = -errno;
                        cap_free(d);
                        return r;
                }

                if (cap_set_proc(d) < 0) {
                        r = -errno;
                        cap_free(d);
                        return r;
                }

                cap_free(d);
        }

        /* Third step: actually set the uids */
        if (setresuid(uid, uid, uid) < 0)
                return -errno;

        /* At this point we should have all necessary capabilities but
           are otherwise a normal user. However, the caps might got
           corrupted due to the setresuid() so we need clean them up
           later. This is done outside of this call. */

        return 0;
}

723
int exec_spawn(ExecCommand *command,
724
               char **argv,
725
               const ExecContext *context,
726
               int fds[], unsigned n_fds,
727
               char **environment,
728
729
               bool apply_permissions,
               bool apply_chroot,
Lennart Poettering's avatar
Lennart Poettering committed
730
               bool confirm_spawn,
731
               CGroupBonding *cgroup_bondings,
732
733
               pid_t *ret) {

734
        pid_t pid;
735
        int r;
736
        char *line;
737
        int socket_fd;
738

739
740
741
        assert(command);
        assert(context);
        assert(ret);
742
743
        assert(fds || n_fds <= 0);

744
745
746
747
748
749
750
751
752
753
754
755
756
757
        if (context->std_input == EXEC_INPUT_SOCKET ||
            context->std_output == EXEC_OUTPUT_SOCKET ||
            context->std_error == EXEC_OUTPUT_SOCKET) {

                if (n_fds != 1)
                        return -EINVAL;

                socket_fd = fds[0];

                fds = NULL;
                n_fds = 0;
        } else
                socket_fd = -1;

758
759
760
761
        if (!argv)
                argv = command->argv;

        if (!(line = exec_command_line(argv)))
762
763
764
765
                return -ENOMEM;

        log_debug("About to execute: %s", line);
        free(line);
766

767
768
769
770
        if (cgroup_bondings)
                if ((r = cgroup_bonding_realize_list(cgroup_bondings)))
                        return r;

771
772
773
774
        if ((pid = fork()) < 0)
                return -errno;

        if (pid == 0) {
775
                int i;
776
                sigset_t ss;
777
778
779
780
781
                const char *username = NULL, *home = NULL;
                uid_t uid = (uid_t) -1;
                gid_t gid = (gid_t) -1;
                char **our_env = NULL, **final_env = NULL;
                unsigned n_env = 0;
Lennart Poettering's avatar
Lennart Poettering committed
782
783
                int saved_stdout = -1, saved_stdin = -1;
                bool keep_stdout = false, keep_stdin = false;
784

785
                /* child */
786

Lennart Poettering's avatar
Lennart Poettering committed
787
788
789
790
791
792
                /* We reset exactly these signals, since they are the
                 * only ones we set to SIG_IGN in the main daemon. All
                 * others we leave untouched because we set them to
                 * SIG_DFL or a valid handler initially, both of which
                 * will be demoted to SIG_DFL. */
                default_signals(SIGNALS_CRASH_HANDLER,
793
                                SIGNALS_IGNORE, -1);
794

795
796
797
798
799
800
                if (sigemptyset(&ss) < 0 ||
                    sigprocmask(SIG_SETMASK, &ss, NULL) < 0) {
                        r = EXIT_SIGNAL_MASK;
                        goto fail;
                }

801
802
803
804
805
                if (!context->no_setsid)
                        if (setsid() < 0) {
                                r = EXIT_SETSID;
                                goto fail;
                        }
Lennart Poettering's avatar
Lennart Poettering committed
806

807
808
809
810
811
812
                if (socket_fd >= 0 && context->tcpwrap_name)
                        if (!socket_tcpwrap(socket_fd, context->tcpwrap_name)) {
                                r = EXIT_TCPWRAP;
                                goto fail;
                        }

Lennart Poettering's avatar
Lennart Poettering committed
813
814
815
816
817
818
819
820
821
                if (confirm_spawn) {
                        char response;

                        /* Set up terminal for the question */
                        if ((r = setup_confirm_stdio(context,
                                                     &saved_stdin, &saved_stdout)))
                                goto fail;

                        /* Now ask the question. */
822
                        if (!(line = exec_command_line(argv))) {
Lennart Poettering's avatar
Lennart Poettering committed
823
                                r = EXIT_MEMORY;
824
825
                                goto fail;
                        }
Lennart Poettering's avatar
Lennart Poettering committed
826
827
828
829
830
831
832
833
834

                        r = ask(&response, "yns", "Execute %s? [Yes, No, Skip] ", line);
                        free(line);

                        if (r < 0 || response == 'n') {
                                r = EXIT_CONFIRM;
                                goto fail;
                        } else if (response == 's') {
                                r = 0;
835
836
                                goto fail;
                        }
Lennart Poettering's avatar
Lennart Poettering committed
837
838

                        /* Release terminal for the question */
Lennart Poettering's avatar
Lennart Poettering committed
839
                        if ((r = restore_confirm_stdio(context,
Lennart Poettering's avatar
Lennart Poettering committed
840
841
842
                                                       &saved_stdin, &saved_stdout,
                                                       &keep_stdin, &keep_stdout)))
                                goto fail;
843
844
                }

Lennart Poettering's avatar
Lennart Poettering committed
845
                if (!keep_stdin)
846
                        if (setup_input(context, socket_fd) < 0) {
Lennart Poettering's avatar
Lennart Poettering committed
847
848
849
                                r = EXIT_STDIN;
                                goto fail;
                        }
850

Lennart Poettering's avatar
Lennart Poettering committed
851
                if (!keep_stdout)
852
                        if (setup_output(context, socket_fd, file_name_from_path(command->path)) < 0) {
Lennart Poettering's avatar
Lennart Poettering committed
853
854
855
                                r = EXIT_STDOUT;
                                goto fail;
                        }
856

857
                if (setup_error(context, socket_fd, file_name_from_path(command->path)) < 0) {
Lennart Poettering's avatar
Lennart Poettering committed
858
                        r = EXIT_STDERR;
859
860
861
                        goto fail;
                }

862
863
864
865
866
867
                if (cgroup_bondings)
                        if ((r = cgroup_bonding_install_list(cgroup_bondings, 0)) < 0) {
                                r = EXIT_CGROUP;
                                goto fail;
                        }

868
869
                if (context->oom_adjust_set) {
                        char t[16];
870

871
872
                        snprintf(t, sizeof(t), "%i", context->oom_adjust);
                        char_array_0(t);
873

874
875
876
877
                        if (write_one_line_file("/proc/self/oom_adj", t) < 0) {
                                r = EXIT_OOM_ADJUST;
                                goto fail;
                        }
878
879
                }

880
881
882
883
884
885
                if (context->nice_set)
                        if (setpriority(PRIO_PROCESS, 0, context->nice) < 0) {
                                r = EXIT_NICE;
                                goto fail;
                        }

886
887
888
889
890
891
                if (context->cpu_sched_set) {
                        struct sched_param param;

                        zero(param);
                        param.sched_priority = context->cpu_sched_priority;

892
893
                        if (sched_setscheduler(0, context->cpu_sched_policy |
                                               (context->cpu_sched_reset_on_fork ? SCHED_RESET_ON_FORK : 0), &param) < 0) {
894
895
896
897
898
899
900
901
902
903
904
                                r = EXIT_SETSCHEDULER;
                                goto fail;
                        }
                }

                if (context->cpu_affinity_set)
                        if (sched_setaffinity(0, sizeof(context->cpu_affinity), &context->cpu_affinity) < 0) {
                                r = EXIT_CPUAFFINITY;
                                goto fail;
                        }

905
906
907
908
909
910
                if (context->ioprio_set)
                        if (ioprio_set(IOPRIO_WHO_PROCESS, 0, context->ioprio) < 0) {
                                r = EXIT_IOPRIO;
                                goto fail;
                        }

911
912
913
914
915
916
                if (context->timer_slack_ns_set)
                        if (prctl(PR_SET_TIMERSLACK, context->timer_slack_ns_set) < 0) {
                                r = EXIT_TIMERSLACK;
                                goto fail;
                        }

917
918
919
920
921
922
                if (context->user) {
                        username = context->user;
                        if (get_user_creds(&username, &uid, &gid, &home) < 0) {
                                r = EXIT_USER;
                                goto fail;
                        }
923
924
925
926
927
928

                        if (is_terminal_input(context->std_input))
                                if (chown_terminal(STDIN_FILENO, uid) < 0) {
                                        r = EXIT_STDIN;
                                        goto fail;
                                }
929
930
931
932
933
934
935
936
                }

                if (apply_permissions)
                        if (enforce_groups(context, username, uid) < 0) {
                                r = EXIT_GROUP;
                                goto fail;
                        }

937
938
                umask(context->umask);

939
940
941
942
943
944
945
946
947
948
949
950
951
                if (strv_length(context->read_write_dirs) > 0 ||
                    strv_length(context->read_only_dirs) > 0 ||
                    strv_length(context->inaccessible_dirs) > 0 ||
                    context->mount_flags != MS_SHARED ||
                    context->private_tmp)
                        if ((r = setup_namespace(
                                             context->read_write_dirs,
                                             context->read_only_dirs,
                                             context->inaccessible_dirs,
                                             context->private_tmp,
                                             context->mount_flags)) < 0)
                                goto fail;

952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
                if (apply_chroot) {
                        if (context->root_directory)
                                if (chroot(context->root_directory) < 0) {
                                        r = EXIT_CHROOT;
                                        goto fail;
                                }

                        if (chdir(context->working_directory ? context->working_directory : "/") < 0) {
                                r = EXIT_CHDIR;
                                goto fail;
                        }
                } else {

                        char *d;

                        if (asprintf(&d, "%s/%s",
                                     context->root_directory ? context->root_directory : "",
                                     context->working_directory ? context->working_directory : "") < 0) {
                                r = EXIT_MEMORY;
                                goto fail;
                        }

                        if (chdir(d) < 0) {
                                free(d);
                                r = EXIT_CHDIR;
                                goto fail;
                        }

                        free(d);
                }

983
                if (close_all_fds(fds, n_fds) < 0 ||
984
                    shift_fds(fds, n_fds) < 0 ||
985
                    flags_fds(fds, n_fds, context->non_blocking) < 0) {
986
987
988
989
                        r = EXIT_FDS;
                        goto fail;
                }

990
                if (apply_permissions) {
991

992
993
994
995
996
997
998
999
                        for (i = 0; i < RLIMIT_NLIMITS; i++) {
                                if (!context->rlimit[i])
                                        continue;

                                if (setrlimit(i, context->rlimit[i]) < 0) {
                                        r = EXIT_LIMITS;
                                        goto fail;
                                }
1000
                        }
For faster browsing, not all history is shown. View entire blame