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