| OLD | NEW | 
|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/seccomp-bpf/syscall.h" | 5 #include "sandbox/linux/seccomp-bpf/syscall.h" | 
| 6 | 6 | 
| 7 #include <asm/unistd.h> | 7 #include <asm/unistd.h> | 
| 8 #include <errno.h> | 8 #include <errno.h> | 
| 9 | 9 | 
| 10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" | 
| 11 #include "base/logging.h" | 11 #include "base/logging.h" | 
|  | 12 #include "sandbox/linux/seccomp-bpf/linux_seccomp.h" | 
| 12 | 13 | 
| 13 namespace sandbox { | 14 namespace sandbox { | 
| 14 | 15 | 
| 15 namespace { | 16 namespace { | 
| 16 | 17 | 
| 17 asm(// We need to be able to tell the kernel exactly where we made a | 18 asm(// We need to be able to tell the kernel exactly where we made a | 
| 18     // system call. The C++ compiler likes to sometimes clone or | 19     // system call. The C++ compiler likes to sometimes clone or | 
| 19     // inline code, which would inadvertently end up duplicating | 20     // inline code, which would inadvertently end up duplicating | 
| 20     // the entry point. | 21     // the entry point. | 
| 21     // "gcc" can suppress code duplication with suitable function | 22     // "gcc" can suppress code duplication with suitable function | 
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 164 // Restore the frame pointer. Also restore the program counter from | 165 // Restore the frame pointer. Also restore the program counter from | 
| 165 // the link register; this makes us return to the caller. | 166 // the link register; this makes us return to the caller. | 
| 166 #if defined(__thumb__) | 167 #if defined(__thumb__) | 
| 167     "2:pop {r7, pc}\n" | 168     "2:pop {r7, pc}\n" | 
| 168     ".cfi_endproc\n" | 169     ".cfi_endproc\n" | 
| 169 #else | 170 #else | 
| 170     "2:ldmfd sp!, {fp, pc}\n" | 171     "2:ldmfd sp!, {fp, pc}\n" | 
| 171 #endif | 172 #endif | 
| 172     ".fnend\n" | 173     ".fnend\n" | 
| 173     "9:.size SyscallAsm, 9b-SyscallAsm\n" | 174     "9:.size SyscallAsm, 9b-SyscallAsm\n" | 
|  | 175 #elif defined(__mips__) | 
|  | 176     ".text\n" | 
|  | 177     ".align 4\n" | 
|  | 178     ".type SyscallAsm, @function\n" | 
|  | 179     "SyscallAsm:.ent SyscallAsm\n" | 
|  | 180     ".frame  $sp, 40, $ra\n" | 
|  | 181     ".set   push\n" | 
|  | 182     ".set   noreorder\n" | 
|  | 183     "addiu  $sp, $sp, -40\n" | 
|  | 184     "sw     $ra, 36($sp)\n" | 
|  | 185     // Check if "v0" is negative. If so, do not attempt to make a | 
|  | 186     // system call. Instead, compute the return address that is visible | 
|  | 187     // to the kernel after we execute "syscall". This address can be | 
|  | 188     // used as a marker that BPF code inspects. | 
|  | 189     "bgez   $v0, 1f\n" | 
|  | 190     " nop\n" | 
|  | 191     "la     $v0, 2f\n" | 
|  | 192     "b      2f\n" | 
|  | 193     " nop\n" | 
|  | 194     // On MIPS first four arguments go to registers a0 - a3 and any | 
|  | 195     // argument after that goes to stack. We can go ahead and directly | 
|  | 196     // copy the entries from the arguments array into the appropriate | 
|  | 197     // CPU registers and on the stack. | 
|  | 198     "1:lw     $a3, 28($a0)\n" | 
|  | 199     "lw     $a2, 24($a0)\n" | 
|  | 200     "lw     $a1, 20($a0)\n" | 
|  | 201     "lw     $t0, 16($a0)\n" | 
|  | 202     "sw     $a3, 28($sp)\n" | 
|  | 203     "sw     $a2, 24($sp)\n" | 
|  | 204     "sw     $a1, 20($sp)\n" | 
|  | 205     "sw     $t0, 16($sp)\n" | 
|  | 206     "lw     $a3, 12($a0)\n" | 
|  | 207     "lw     $a2, 8($a0)\n" | 
|  | 208     "lw     $a1, 4($a0)\n" | 
|  | 209     "lw     $a0, 0($a0)\n" | 
|  | 210     // Enter the kernel | 
|  | 211     "syscall\n" | 
|  | 212     // This is our "magic" return address that the BPF filter sees. | 
|  | 213     // Restore the return address from the stack. | 
|  | 214     "2:lw     $ra, 36($sp)\n" | 
|  | 215     "jr     $ra\n" | 
|  | 216     " addiu  $sp, $sp, 40\n" | 
|  | 217     ".set    pop\n" | 
|  | 218     ".end    SyscallAsm\n" | 
|  | 219     ".size   SyscallAsm,.-SyscallAsm\n" | 
| 174 #endif | 220 #endif | 
| 175     );  // asm | 221     );  // asm | 
| 176 | 222 | 
| 177 }  // namespace | 223 }  // namespace | 
| 178 | 224 | 
| 179 intptr_t Syscall::Call(int nr, | 225 intptr_t Syscall::Call(int nr, | 
| 180                        intptr_t p0, | 226                        intptr_t p0, | 
| 181                        intptr_t p1, | 227                        intptr_t p1, | 
| 182                        intptr_t p2, | 228                        intptr_t p2, | 
| 183                        intptr_t p3, | 229                        intptr_t p3, | 
| 184                        intptr_t p4, | 230                        intptr_t p4, | 
| 185                        intptr_t p5, | 231                        intptr_t p5, | 
| 186                        intptr_t p6, | 232                        intptr_t p6, | 
| 187                        intptr_t p7) { | 233                        intptr_t p7) { | 
| 188   // We rely on "intptr_t" to be the exact size as a "void *". This is | 234   // We rely on "intptr_t" to be the exact size as a "void *". This is | 
| 189   // typically true, but just in case, we add a check. The language | 235   // typically true, but just in case, we add a check. The language | 
| 190   // specification allows platforms some leeway in cases, where | 236   // specification allows platforms some leeway in cases, where | 
| 191   // "sizeof(void *)" is not the same as "sizeof(void (*)())". We expect | 237   // "sizeof(void *)" is not the same as "sizeof(void (*)())". We expect | 
| 192   // that this would only be an issue for IA64, which we are currently not | 238   // that this would only be an issue for IA64, which we are currently not | 
| 193   // planning on supporting. And it is even possible that this would work | 239   // planning on supporting. And it is even possible that this would work | 
| 194   // on IA64, but for lack of actual hardware, I cannot test. | 240   // on IA64, but for lack of actual hardware, I cannot test. | 
| 195   COMPILE_ASSERT(sizeof(void*) == sizeof(intptr_t), | 241   COMPILE_ASSERT(sizeof(void*) == sizeof(intptr_t), | 
| 196                  pointer_types_and_intptr_must_be_exactly_the_same_size); | 242                  pointer_types_and_intptr_must_be_exactly_the_same_size); | 
| 197 | 243 | 
| 198   // TODO(nedeljko): Enable use of more than six parameters on architectures | 244   // TODO(nedeljko): Enable use of more than six parameters on architectures | 
| 199   //                 where that makes sense. | 245   //                 where that makes sense. | 
|  | 246 #if defined(__mips__) | 
|  | 247   const intptr_t args[8] = {p0, p1, p2, p3, p4, p5, p6, p7}; | 
|  | 248 #else | 
| 200   DCHECK_EQ(p6, 0) << " Support for syscalls with more than six arguments not " | 249   DCHECK_EQ(p6, 0) << " Support for syscalls with more than six arguments not " | 
| 201                       "added for this architecture"; | 250                       "added for this architecture"; | 
| 202   DCHECK_EQ(p7, 0) << " Support for syscalls with more than six arguments not " | 251   DCHECK_EQ(p7, 0) << " Support for syscalls with more than six arguments not " | 
| 203                       "added for this architecture"; | 252                       "added for this architecture"; | 
| 204   const intptr_t args[6] = {p0, p1, p2, p3, p4, p5}; | 253   const intptr_t args[6] = {p0, p1, p2, p3, p4, p5}; | 
|  | 254 #endif  // defined(__mips__) | 
| 205 | 255 | 
| 206 // Invoke our file-scope assembly code. The constraints have been picked | 256 // Invoke our file-scope assembly code. The constraints have been picked | 
| 207 // carefully to match what the rest of the assembly code expects in input, | 257 // carefully to match what the rest of the assembly code expects in input, | 
| 208 // output, and clobbered registers. | 258 // output, and clobbered registers. | 
| 209 #if defined(__i386__) | 259 #if defined(__i386__) | 
| 210   intptr_t ret = nr; | 260   intptr_t ret = nr; | 
| 211   asm volatile( | 261   asm volatile( | 
| 212       "call SyscallAsm\n" | 262       "call SyscallAsm\n" | 
| 213       // N.B. These are not the calling conventions normally used by the ABI. | 263       // N.B. These are not the calling conventions normally used by the ABI. | 
| 214       : "=a"(ret) | 264       : "=a"(ret) | 
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 261           // it. | 311           // it. | 
| 262           // In ARM mode, we have a dedicated frame pointer register and "r7" is | 312           // In ARM mode, we have a dedicated frame pointer register and "r7" is | 
| 263           // thus available as a general purpose register. We don't preserve it, | 313           // thus available as a general purpose register. We don't preserve it, | 
| 264           // but instead mark it as clobbered. | 314           // but instead mark it as clobbered. | 
| 265           , | 315           , | 
| 266           "r7" | 316           "r7" | 
| 267 #endif  // !defined(__thumb__) | 317 #endif  // !defined(__thumb__) | 
| 268         ); | 318         ); | 
| 269     ret = inout; | 319     ret = inout; | 
| 270   } | 320   } | 
|  | 321 #elif defined(__mips__) | 
|  | 322   int err_status; | 
|  | 323   intptr_t ret = Syscall::SandboxSyscallRaw(nr, args, &err_status); | 
|  | 324 | 
|  | 325   if (err_status) { | 
|  | 326     // On error, MIPS returns errno from syscall instead of -errno. | 
|  | 327     // The purpose of this negation is for SandboxSyscall() to behave | 
|  | 328     // more like it would on other architectures. | 
|  | 329     ret = -ret; | 
|  | 330   } | 
| 271 #else | 331 #else | 
| 272 #error "Unimplemented architecture" | 332 #error "Unimplemented architecture" | 
| 273 #endif | 333 #endif | 
| 274   return ret; | 334   return ret; | 
| 275 } | 335 } | 
| 276 | 336 | 
|  | 337 void Syscall::PutValueInUcontext(intptr_t ret_val, ucontext_t* ctx) { | 
|  | 338 #if defined(__mips__) | 
|  | 339   // Mips ABI states that on error a3 CPU register has non zero value and if | 
|  | 340   // there is no error, it should be zero. | 
|  | 341   if (ret_val <= -1 && ret_val >= -4095) { | 
|  | 342     // |ret_val| followes the Syscall::Call() convention of being -errno on | 
|  | 343     // errors. In order to write correct value to return register this sign | 
|  | 344     // needs to be changed back. | 
|  | 345     ret_val = -ret_val; | 
|  | 346     SECCOMP_PARM4(ctx) = 1; | 
|  | 347   } else | 
|  | 348     SECCOMP_PARM4(ctx) = 0; | 
|  | 349 #endif | 
|  | 350   SECCOMP_RESULT(ctx) = static_cast<greg_t>(ret_val); | 
|  | 351 } | 
|  | 352 | 
|  | 353 #if defined(__mips__) | 
|  | 354 intptr_t Syscall::SandboxSyscallRaw(int nr, | 
|  | 355                                     const intptr_t* args, | 
|  | 356                                     intptr_t* err_ret) { | 
|  | 357   register intptr_t ret __asm__("v0") = nr; | 
|  | 358   // a3 register becomes non zero on error. | 
|  | 359   register intptr_t err_stat __asm__("a3") = 0; | 
|  | 360   { | 
|  | 361     register const intptr_t* data __asm__("a0") = args; | 
|  | 362     asm volatile( | 
|  | 363         "la $t9, SyscallAsm\n" | 
|  | 364         "jalr $t9\n" | 
|  | 365         " nop\n" | 
|  | 366         : "=r"(ret), "=r"(err_stat) | 
|  | 367         : "0"(ret), | 
|  | 368           "r"(data) | 
|  | 369           // a2 is in the clober list so inline assembly can not change its | 
|  | 370           // value. | 
|  | 371         : "memory", "ra", "t9", "a2"); | 
|  | 372   } | 
|  | 373 | 
|  | 374   // Set an error status so it can be used outside of this function | 
|  | 375   *err_ret = err_stat; | 
|  | 376 | 
|  | 377   return ret; | 
|  | 378 } | 
|  | 379 #endif  // defined(__mips__) | 
|  | 380 | 
| 277 }  // namespace sandbox | 381 }  // namespace sandbox | 
| OLD | NEW | 
|---|