| OLD | NEW | 
|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "sandbox/linux/services/syscall_wrappers.h" | 5 #include "sandbox/linux/services/syscall_wrappers.h" | 
| 6 | 6 | 
| 7 #include <pthread.h> | 7 #include <pthread.h> | 
| 8 #include <sched.h> | 8 #include <sched.h> | 
| 9 #include <setjmp.h> | 9 #include <setjmp.h> | 
| 10 #include <sys/resource.h> | 10 #include <sys/resource.h> | 
| (...skipping 11 matching lines...) Expand all  Loading... | 
| 22 namespace sandbox { | 22 namespace sandbox { | 
| 23 | 23 | 
| 24 pid_t sys_getpid(void) { | 24 pid_t sys_getpid(void) { | 
| 25   return syscall(__NR_getpid); | 25   return syscall(__NR_getpid); | 
| 26 } | 26 } | 
| 27 | 27 | 
| 28 pid_t sys_gettid(void) { | 28 pid_t sys_gettid(void) { | 
| 29   return syscall(__NR_gettid); | 29   return syscall(__NR_gettid); | 
| 30 } | 30 } | 
| 31 | 31 | 
| 32 namespace { | 32 long sys_clone(unsigned long flags, | 
| 33 | 33                decltype(nullptr) child_stack, | 
| 34 bool CloneArgumentsValid(unsigned long flags, pid_t* ptid, pid_t* ctid) { | 34                pid_t* ptid, | 
|  | 35                pid_t* ctid, | 
|  | 36                decltype(nullptr) tls) { | 
| 35   const bool clone_tls_used = flags & CLONE_SETTLS; | 37   const bool clone_tls_used = flags & CLONE_SETTLS; | 
| 36   const bool invalid_ctid = | 38   const bool invalid_ctid = | 
| 37       (flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) && !ctid; | 39       (flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) && !ctid; | 
| 38   const bool invalid_ptid = (flags & CLONE_PARENT_SETTID) && !ptid; | 40   const bool invalid_ptid = (flags & CLONE_PARENT_SETTID) && !ptid; | 
| 39 | 41 | 
| 40   // We do not support CLONE_VM. | 42   // We do not support CLONE_VM. | 
| 41   const bool clone_vm_used = flags & CLONE_VM; | 43   const bool clone_vm_used = flags & CLONE_VM; | 
| 42 | 44   if (clone_tls_used || invalid_ctid || invalid_ptid || clone_vm_used) { | 
| 43   return !(clone_tls_used || invalid_ctid || invalid_ptid || clone_vm_used); |  | 
| 44 } |  | 
| 45 |  | 
| 46 bool IsRunningOnValgrind() { |  | 
| 47   return RUNNING_ON_VALGRIND; |  | 
| 48 } |  | 
| 49 |  | 
| 50 // This function runs on the stack specified on the clone call. It uses longjmp |  | 
| 51 // to switch back to the original stack so the child can return from sys_clone. |  | 
| 52 int CloneHelper(void* arg) { |  | 
| 53   jmp_buf* env_ptr = reinterpret_cast<jmp_buf*>(arg); |  | 
| 54   longjmp(*env_ptr, 1); |  | 
| 55 |  | 
| 56   // Should not be reached. |  | 
| 57   RAW_CHECK(false); |  | 
| 58   return 1; |  | 
| 59 } |  | 
| 60 |  | 
| 61 // This function is noinline to ensure that stack_buf is below the stack pointer |  | 
| 62 // that is saved when setjmp is called below. This is needed because when |  | 
| 63 // compiled with FORTIFY_SOURCE, glibc's longjmp checks that the stack is moved |  | 
| 64 // upwards. See crbug.com/442912 for more details. |  | 
| 65 #if defined(ADDRESS_SANITIZER) |  | 
| 66 // Disable AddressSanitizer instrumentation for this function to make sure |  | 
| 67 // |stack_buf| is allocated on thread stack instead of ASan's fake stack. |  | 
| 68 // Under ASan longjmp() will attempt to clean up the area between the old and |  | 
| 69 // new stack pointers and print a warning that may confuse the user. |  | 
| 70 __attribute__((no_sanitize_address)) |  | 
| 71 #endif |  | 
| 72 NOINLINE pid_t CloneAndLongjmpInChild(unsigned long flags, |  | 
| 73                                      pid_t* ptid, |  | 
| 74                                      pid_t* ctid, |  | 
| 75                                      jmp_buf* env) { |  | 
| 76   // We use the libc clone wrapper instead of making the syscall |  | 
| 77   // directly because making the syscall may fail to update the libc's |  | 
| 78   // internal pid cache. The libc interface unfortunately requires |  | 
| 79   // specifying a new stack, so we use setjmp/longjmp to emulate |  | 
| 80   // fork-like behavior. |  | 
| 81   char stack_buf[PTHREAD_STACK_MIN]; |  | 
| 82 #if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) || \ |  | 
| 83     defined(ARCH_CPU_MIPS64_FAMILY) || defined(ARCH_CPU_MIPS_FAMILY) |  | 
| 84   // The stack grows downward. |  | 
| 85   void* stack = stack_buf + sizeof(stack_buf); |  | 
| 86 #else |  | 
| 87 #error "Unsupported architecture" |  | 
| 88 #endif |  | 
| 89   return clone(&CloneHelper, stack, flags, env, ptid, nullptr, ctid); |  | 
| 90 } |  | 
| 91 |  | 
| 92 }  // namespace |  | 
| 93 |  | 
| 94 long sys_clone(unsigned long flags, |  | 
| 95                decltype(nullptr) child_stack, |  | 
| 96                pid_t* ptid, |  | 
| 97                pid_t* ctid, |  | 
| 98                decltype(nullptr) tls) { |  | 
| 99 |  | 
| 100   if (!CloneArgumentsValid(flags, ptid, ctid)) { |  | 
| 101     RAW_LOG(FATAL, "Invalid usage of sys_clone"); | 45     RAW_LOG(FATAL, "Invalid usage of sys_clone"); | 
| 102   } | 46   } | 
| 103 | 47 | 
| 104   // See kernel/fork.c in Linux. There is different ordering of sys_clone | 48   // See kernel/fork.c in Linux. There is different ordering of sys_clone | 
| 105   // parameters depending on CONFIG_CLONE_BACKWARDS* configuration options. | 49   // parameters depending on CONFIG_CLONE_BACKWARDS* configuration options. | 
| 106 #if defined(ARCH_CPU_X86_64) | 50 #if defined(ARCH_CPU_X86_64) | 
| 107   return syscall(__NR_clone, flags, child_stack, ptid, ctid, tls); | 51   return syscall(__NR_clone, flags, child_stack, ptid, ctid, tls); | 
| 108 #elif defined(ARCH_CPU_X86) || defined(ARCH_CPU_ARM_FAMILY) || \ | 52 #elif defined(ARCH_CPU_X86) || defined(ARCH_CPU_ARM_FAMILY) || \ | 
| 109     defined(ARCH_CPU_MIPS_FAMILY) || defined(ARCH_CPU_MIPS64_FAMILY) | 53     defined(ARCH_CPU_MIPS_FAMILY) || defined(ARCH_CPU_MIPS64_FAMILY) | 
| 110   // CONFIG_CLONE_BACKWARDS defined. | 54   // CONFIG_CLONE_BACKWARDS defined. | 
| 111   return syscall(__NR_clone, flags, child_stack, ptid, tls, ctid); | 55   return syscall(__NR_clone, flags, child_stack, ptid, tls, ctid); | 
| 112 #endif | 56 #endif | 
| 113 } | 57 } | 
| 114 | 58 | 
| 115 long sys_clone(unsigned long flags) { | 59 long sys_clone(unsigned long flags) { | 
| 116   return sys_clone(flags, nullptr, nullptr, nullptr, nullptr); | 60   return sys_clone(flags, nullptr, nullptr, nullptr, nullptr); | 
| 117 } | 61 } | 
| 118 | 62 | 
| 119 pid_t ForkWithFlags(unsigned long flags, pid_t* ptid, pid_t* ctid) { |  | 
| 120   if (!CloneArgumentsValid(flags, ptid, ctid)) { |  | 
| 121     RAW_LOG(FATAL, "Invalid usage of ForkWithFlags"); |  | 
| 122   } |  | 
| 123 |  | 
| 124   // Valgrind's clone implementation does not support specifiying a child_stack |  | 
| 125   // without CLONE_VM, so we cannot use libc's clone wrapper when running under |  | 
| 126   // Valgrind. As a result, the libc pid cache may be incorrect under Valgrind. |  | 
| 127   // See crbug.com/442817 for more details. |  | 
| 128   if (IsRunningOnValgrind()) { |  | 
| 129     return sys_clone(flags, nullptr, ptid, ctid, nullptr); |  | 
| 130   } |  | 
| 131 |  | 
| 132   jmp_buf env; |  | 
| 133   if (setjmp(env) == 0) { |  | 
| 134     return CloneAndLongjmpInChild(flags, ptid, ctid, &env); |  | 
| 135   } |  | 
| 136 |  | 
| 137   return 0; |  | 
| 138 } |  | 
| 139 |  | 
| 140 void sys_exit_group(int status) { | 63 void sys_exit_group(int status) { | 
| 141   syscall(__NR_exit_group, status); | 64   syscall(__NR_exit_group, status); | 
| 142 } | 65 } | 
| 143 | 66 | 
| 144 int sys_seccomp(unsigned int operation, | 67 int sys_seccomp(unsigned int operation, | 
| 145                 unsigned int flags, | 68                 unsigned int flags, | 
| 146                 const struct sock_fprog* args) { | 69                 const struct sock_fprog* args) { | 
| 147   return syscall(__NR_seccomp, operation, flags, args); | 70   return syscall(__NR_seccomp, operation, flags, args); | 
| 148 } | 71 } | 
| 149 | 72 | 
| 150 int sys_prlimit64(pid_t pid, | 73 int sys_prlimit64(pid_t pid, | 
| 151                   int resource, | 74                   int resource, | 
| 152                   const struct rlimit64* new_limit, | 75                   const struct rlimit64* new_limit, | 
| 153                   struct rlimit64* old_limit) { | 76                   struct rlimit64* old_limit) { | 
| 154   return syscall(__NR_prlimit64, pid, resource, new_limit, old_limit); | 77   return syscall(__NR_prlimit64, pid, resource, new_limit, old_limit); | 
| 155 } | 78 } | 
| 156 | 79 | 
| 157 }  // namespace sandbox | 80 }  // namespace sandbox | 
| OLD | NEW | 
|---|