15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://code.google.com/p/chromium/wiki/LinuxSUIDSandbox
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "sandbox/linux/suid/common/sandbox.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define _GNU_SOURCE
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <asm/unistd.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <limits.h>
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sched.h>
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <signal.h>
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdarg.h>
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdbool.h>
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdint.h>
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h>
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/prctl.h>
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/resource.h>
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/socket.h>
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/stat.h>
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/time.h>
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/types.h>
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/vfs.h>
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/wait.h>
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unistd.h>
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
32a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "sandbox/linux/suid/common/suid_unsafe_environment_variables.h"
33a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "sandbox/linux/suid/process_util.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(CLONE_NEWPID)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CLONE_NEWPID 0x20000000
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(CLONE_NEWNET)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CLONE_NEWNET 0x40000000
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool DropRoot();
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define HANDLE_EINTR(x) TEMP_FAILURE_RETRY(x)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
46a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochstatic void FatalError(const char* msg, ...)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    __attribute__((noreturn, format(printf, 1, 2)));
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
49a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochstatic void FatalError(const char* msg, ...) {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  va_list ap;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  va_start(ap, msg);
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  vfprintf(stderr, msg, ap);
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fprintf(stderr, ": %s\n", strerror(errno));
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fflush(stderr);
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  va_end(ap);
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _exit(1);
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)static void ExitWithErrorSignalHandler(int signal) {
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const char msg[] = "\nThe setuid sandbox got signaled, exiting.\n";
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (-1 == write(2, msg, sizeof(msg) - 1)) {
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Do nothing.
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  _exit(1);
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We will chroot() to the helper's /proc/self directory. Anything there will
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// not exist anymore if we make sure to wait() for the helper.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// /proc/self/fdinfo or /proc/self/fd are especially safe and will be empty
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// even if the helper survives as a zombie.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// There is very little reason to use fdinfo/ instead of fd/ but we are
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// paranoid. fdinfo/ only exists since 2.6.22 so we allow fallback to fd/
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SAFE_DIR "/proc/self/fdinfo"
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SAFE_DIR2 "/proc/self/fd"
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool SpawnChrootHelper() {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int sv[2];
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    perror("socketpair");
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
87a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  char* safedir = NULL;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct stat sdir_stat;
89a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (!stat(SAFE_DIR, &sdir_stat) && S_ISDIR(sdir_stat.st_mode)) {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    safedir = SAFE_DIR;
91a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  } else if (!stat(SAFE_DIR2, &sdir_stat) && S_ISDIR(sdir_stat.st_mode)) {
92a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    safedir = SAFE_DIR2;
93a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  } else {
94a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    fprintf(stderr, "Could not find %s\n", SAFE_DIR2);
95a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    return false;
96a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  }
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
98a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  const pid_t pid = syscall(__NR_clone, CLONE_FS | SIGCHLD, 0, 0, 0);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pid == -1) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    perror("clone");
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    close(sv[0]);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    close(sv[1]);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pid == 0) {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We share our files structure with an untrusted process. As a security in
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // depth measure, we make sure that we can't open anything by mistake.
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(agl): drop CAP_SYS_RESOURCE / use SECURE_NOROOT
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const struct rlimit nofile = {0, 0};
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (setrlimit(RLIMIT_NOFILE, &nofile))
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FatalError("Setting RLIMIT_NOFILE");
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (close(sv[1]))
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FatalError("close");
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // wait for message
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char msg;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ssize_t bytes;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    do {
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bytes = read(sv[0], &msg, 1);
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } while (bytes == -1 && errno == EINTR);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (bytes == 0)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      _exit(0);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (bytes != 1)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FatalError("read");
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // do chrooting
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (msg != kMsgChrootMe)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FatalError("Unknown message from sandboxed process");
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // sanity check
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (chdir(safedir))
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FatalError("Cannot chdir into /proc/ directory");
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (chroot(safedir))
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FatalError("Cannot chroot into /proc/ directory");
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (chdir("/"))
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FatalError("Cannot chdir to / after chroot");
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char reply = kMsgChrootSuccessful;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    do {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bytes = write(sv[0], &reply, 1);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } while (bytes == -1 && errno == EINTR);
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (bytes != 1)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FatalError("Writing reply");
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    _exit(0);
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We now become a zombie. /proc/self/fd(info) is now an empty dir and we
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // are chrooted there.
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Our (unprivileged) parent should not even be able to open "." or "/"
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // since they would need to pass the ptrace() check. If our parent wait()
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // for us, our root directory will completely disappear.
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (close(sv[0])) {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    close(sv[1]);
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    perror("close");
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In the parent process, we install an environment variable containing the
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // number of the file descriptor.
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char desc_str[64];
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int printed = snprintf(desc_str, sizeof(desc_str), "%u", sv[1]);
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (printed < 0 || printed >= (int)sizeof(desc_str)) {
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fprintf(stderr, "Failed to snprintf\n");
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (setenv(kSandboxDescriptorEnvironmentVarName, desc_str, 1)) {
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    perror("setenv");
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    close(sv[1]);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We also install an environment variable containing the pid of the child
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char helper_pid_str[64];
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  printed = snprintf(helper_pid_str, sizeof(helper_pid_str), "%u", pid);
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (printed < 0 || printed >= (int)sizeof(helper_pid_str)) {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fprintf(stderr, "Failed to snprintf\n");
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (setenv(kSandboxHelperPidEnvironmentVarName, helper_pid_str, 1)) {
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    perror("setenv");
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    close(sv[1]);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Block until child_pid exits, then exit. Try to preserve the exit code.
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void WaitForChildAndExit(pid_t child_pid) {
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int exit_code = -1;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  siginfo_t reaped_child_info;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Don't "Core" on SIGABRT. SIGABRT is sent by the Chrome OS session manager
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // when things are hanging.
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Here, the current process is going to waitid() and _exit(), so there is no
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // point in generating a crash report. The child process is the one
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // blocking us.
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (signal(SIGABRT, ExitWithErrorSignalHandler) == SIG_ERR) {
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    FatalError("Failed to change signal handler");
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int wait_ret =
214a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      HANDLE_EINTR(waitid(P_PID, child_pid, &reaped_child_info, WEXITED));
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!wait_ret && reaped_child_info.si_pid == child_pid) {
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (reaped_child_info.si_code == CLD_EXITED) {
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      exit_code = reaped_child_info.si_status;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Exit with code 0 if the child got signaled.
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      exit_code = 0;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _exit(exit_code);
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool MoveToNewNamespaces() {
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // These are the sets of flags which we'll try, in order.
229a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  const int kCloneExtraFlags[] = {CLONE_NEWPID | CLONE_NEWNET, CLONE_NEWPID, };
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We need to close kZygoteIdFd before the child can continue. We use this
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // socketpair to tell the child when to continue;
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int sync_fds[2];
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (socketpair(AF_UNIX, SOCK_STREAM, 0, sync_fds)) {
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FatalError("Failed to create a socketpair");
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
238a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  for (size_t i = 0; i < sizeof(kCloneExtraFlags) / sizeof(kCloneExtraFlags[0]);
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i++) {
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pid_t pid = syscall(__NR_clone, SIGCHLD | kCloneExtraFlags[i], 0, 0, 0);
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const int clone_errno = errno;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (pid > 0) {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!DropRoot()) {
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FatalError("Could not drop privileges");
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (close(sync_fds[0]) || shutdown(sync_fds[1], SHUT_RD))
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FatalError("Could not close socketpair");
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // The kZygoteIdFd needs to be closed in the parent before
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Zygote gets started.
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (close(kZygoteIdFd))
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FatalError("close");
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Tell our child to continue
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (HANDLE_EINTR(send(sync_fds[1], "C", 1, MSG_NOSIGNAL)) != 1)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FatalError("send");
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (close(sync_fds[1]))
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FatalError("close");
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // We want to keep a full process tree and we don't want our childs to
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // be reparented to (the outer PID namespace) init. So we wait for it.
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        WaitForChildAndExit(pid);
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // NOTREACHED
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FatalError("Not reached");
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (pid == 0) {
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (close(sync_fds[1]) || shutdown(sync_fds[0], SHUT_WR))
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FatalError("Could not close socketpair");
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Wait for the parent to confirm it closed kZygoteIdFd before we
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // continue
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      char should_continue;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (HANDLE_EINTR(read(sync_fds[0], &should_continue, 1)) != 1)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FatalError("Read on socketpair");
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (close(sync_fds[0]))
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FatalError("close");
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (kCloneExtraFlags[i] & CLONE_NEWPID) {
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        setenv(kSandboxPIDNSEnvironmentVarName, "", 1 /* overwrite */);
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        unsetenv(kSandboxPIDNSEnvironmentVarName);
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (kCloneExtraFlags[i] & CLONE_NEWNET) {
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        setenv(kSandboxNETNSEnvironmentVarName, "", 1 /* overwrite */);
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        unsetenv(kSandboxNETNSEnvironmentVarName);
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // If EINVAL then the system doesn't support the requested flags, so
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // continue to try a different set.
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // On any other errno value the system *does* support these flags but
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // something went wrong, hence we bail with an error message rather then
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // provide less security.
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (errno != EINVAL) {
299c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      fprintf(stderr, "Failed to move to new namespace:");
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (kCloneExtraFlags[i] & CLONE_NEWPID) {
301c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        fprintf(stderr, " PID namespaces supported,");
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (kCloneExtraFlags[i] & CLONE_NEWNET) {
304c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        fprintf(stderr, " Network namespace supported,");
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
306c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      fprintf(stderr, " but failed: errno = %s\n", strerror(clone_errno));
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the system doesn't support NEWPID then we carry on anyway.
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool DropRoot() {
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0)) {
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    perror("prctl(PR_SET_DUMPABLE)");
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) {
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    perror("Still dumpable after prctl(PR_SET_DUMPABLE)");
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gid_t rgid, egid, sgid;
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (getresgid(&rgid, &egid, &sgid)) {
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    perror("getresgid");
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (setresgid(rgid, rgid, rgid)) {
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    perror("setresgid");
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uid_t ruid, euid, suid;
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (getresuid(&ruid, &euid, &suid)) {
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    perror("getresuid");
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (setresuid(ruid, ruid, ruid)) {
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    perror("setresuid");
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool SetupChildEnvironment() {
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned i;
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ld.so may have cleared several environment variables because we are SUID.
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // However, the child process might need them so zygote_host_linux.cc saves a
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // copy in SANDBOX_$x. This is safe because we have dropped root by this
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // point, so we can only exec a binary with the permissions of the user who
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ran us in the first place.
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (i = 0; kSUIDUnsafeEnvironmentVariables[i]; ++i) {
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* const envvar = kSUIDUnsafeEnvironmentVariables[i];
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char* const saved_envvar = SandboxSavedEnvironmentVariable(envvar);
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!saved_envvar)
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* const value = getenv(saved_envvar);
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (value) {
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      setenv(envvar, value, 1 /* overwrite */);
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unsetenv(saved_envvar);
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    free(saved_envvar);
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CheckAndExportApiVersion() {
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check the environment to see if a specific API version was requested.
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // assume version 0 if none.
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  long api_number = -1;
382a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  char* api_string = getenv(kSandboxEnvironmentApiRequest);
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!api_string) {
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    api_number = 0;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    errno = 0;
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char* endptr = NULL;
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    api_number = strtol(api_string, &endptr, 10);
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!endptr || *endptr || errno != 0)
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Warn only for now.
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (api_number != kSUIDSandboxApiNumber) {
395a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    fprintf(
396a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        stderr,
397a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        "The setuid sandbox provides API version %ld, "
398a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        "but you need %ld\n"
399a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        "Please read "
400a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        "https://code.google.com/p/chromium/wiki/LinuxSUIDSandboxDevelopment."
401a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        "\n\n",
402a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        kSUIDSandboxApiNumber,
403a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        api_number);
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Export our version so that the sandboxed process can verify it did not
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // use an old sandbox.
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char version_string[64];
409a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  snprintf(
410a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      version_string, sizeof(version_string), "%ld", kSUIDSandboxApiNumber);
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (setenv(kSandboxEnvironmentApiProvides, version_string, 1)) {
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    perror("setenv");
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
419a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochint main(int argc, char** argv) {
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (argc <= 1) {
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (argc <= 0) {
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 1;
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fprintf(stderr, "Usage: %s <renderer process> <args...>\n", argv[0]);
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1;
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Allow someone to query our API version
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (argc == 2 && 0 == strcmp(argv[1], kSuidSandboxGetApiSwitch)) {
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    printf("%ld\n", kSUIDSandboxApiNumber);
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // We cannot adjust /proc/pid/oom_adj for sandboxed renderers
4361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // because those files are owned by root. So we need a helper here.
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (argc == 4 && (0 == strcmp(argv[1], kAdjustOOMScoreSwitch))) {
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char* endptr = NULL;
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    long score;
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    errno = 0;
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned long pid_ul = strtoul(argv[2], &endptr, 10);
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (pid_ul == ULONG_MAX || !endptr || *endptr || errno != 0)
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 1;
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pid_t pid = pid_ul;
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    endptr = NULL;
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    errno = 0;
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    score = strtol(argv[3], &endptr, 10);
448a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    if (score == LONG_MAX || score == LONG_MIN || !endptr || *endptr ||
449a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        errno != 0) {
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 1;
451a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    }
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return AdjustOOMScore(pid, score);
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Protect the core setuid sandbox functionality with an API version
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!CheckAndExportApiVersion()) {
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1;
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
460c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (geteuid() != 0) {
461c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    fprintf(stderr,
462a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch            "The setuid sandbox is not running as root. Common causes:\n"
463a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch            "  * An unprivileged process using ptrace on it, like a debugger.\n"
464a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch            "  * A parent process set prctl(PR_SET_NO_NEW_PRIVS, ...)\n");
465c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
466c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!MoveToNewNamespaces())
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1;
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!SpawnChrootHelper())
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1;
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!DropRoot())
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1;
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!SetupChildEnvironment())
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1;
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  execv(argv[1], &argv[1]);
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FatalError("execv failed");
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 1;
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
481