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 | |
5 #include "sandbox/linux/seccomp-bpf/syscall.h" | 4 #include "sandbox/linux/seccomp-bpf/syscall.h" |
6 | 5 |
7 #include <asm/unistd.h> | 6 #include <asm/unistd.h> |
8 #include <errno.h> | 7 #include <errno.h> |
9 | 8 |
10 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
| 10 #include "sandbox/linux/seccomp-bpf/linux_seccomp.h" |
11 | 11 |
12 namespace sandbox { | 12 namespace sandbox { |
13 | 13 |
14 namespace { | 14 namespace { |
15 | 15 |
16 asm(// We need to be able to tell the kernel exactly where we made a | 16 asm(// We need to be able to tell the kernel exactly where we made a |
17 // system call. The C++ compiler likes to sometimes clone or | 17 // system call. The C++ compiler likes to sometimes clone or |
18 // inline code, which would inadvertently end up duplicating | 18 // inline code, which would inadvertently end up duplicating |
19 // the entry point. | 19 // the entry point. |
20 // "gcc" can suppress code duplication with suitable function | 20 // "gcc" can suppress code duplication with suitable function |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
163 // Restore the frame pointer. Also restore the program counter from | 163 // Restore the frame pointer. Also restore the program counter from |
164 // the link register; this makes us return to the caller. | 164 // the link register; this makes us return to the caller. |
165 #if defined(__thumb__) | 165 #if defined(__thumb__) |
166 "2:pop {r7, pc}\n" | 166 "2:pop {r7, pc}\n" |
167 ".cfi_endproc\n" | 167 ".cfi_endproc\n" |
168 #else | 168 #else |
169 "2:ldmfd sp!, {fp, pc}\n" | 169 "2:ldmfd sp!, {fp, pc}\n" |
170 #endif | 170 #endif |
171 ".fnend\n" | 171 ".fnend\n" |
172 "9:.size SyscallAsm, 9b-SyscallAsm\n" | 172 "9:.size SyscallAsm, 9b-SyscallAsm\n" |
| 173 #elif defined(__mips__) |
| 174 ".text\n" |
| 175 ".align 4\n" |
| 176 ".type SyscallAsm, @function\n" |
| 177 "SyscallAsm:.ent SyscallAsm\n" |
| 178 ".frame $sp, 32, $ra\n" |
| 179 ".set push\n" |
| 180 ".set noreorder\n" |
| 181 "addiu $sp, $sp, -32\n" |
| 182 "sw $ra, 28($sp)\n" |
| 183 // Check if "v0" is negative. If so, do not attempt to make a |
| 184 // system call. Instead, compute the return address that is visible |
| 185 // to the kernel after we execute "syscall". This address can be |
| 186 // used as a marker that BPF code inspects. |
| 187 "bgez $v0, 1f\n" |
| 188 " nop\n" |
| 189 "la $v0, 2f\n" |
| 190 "b 2f\n" |
| 191 " nop\n" |
| 192 // On MIPS first four arguments go to registers a0 - a3 and any |
| 193 // argument after that goes to stack. We can go ahead and directly |
| 194 // copy the entries from the arguments array into the appropriate |
| 195 // CPU registers and on the stack. |
| 196 "1:lw $t0, 20($a0)\n" |
| 197 "sw $t0, 20($sp)\n" |
| 198 "lw $t0, 16($a0)\n" |
| 199 "sw $t0, 16($sp)\n" |
| 200 "lw $a3, 12($a0)\n" |
| 201 "lw $a2, 8($a0)\n" |
| 202 "lw $a1, 4($a0)\n" |
| 203 "lw $a0, 0($a0)\n" |
| 204 // Enter the kernel |
| 205 "syscall\n" |
| 206 // This is our "magic" return address that the BPF filter sees. |
| 207 // Restore the return address from the stack. |
| 208 "2:lw $ra, 28($sp)\n" |
| 209 "jr $ra\n" |
| 210 " addiu $sp, $sp, 32\n" |
| 211 ".set pop\n" |
| 212 ".end SyscallAsm\n" |
| 213 ".size SyscallAsm,.-SyscallAsm\n" |
173 #endif | 214 #endif |
174 ); // asm | 215 ); // asm |
175 | 216 |
176 } // namespace | 217 } // namespace |
177 | 218 |
178 intptr_t Syscall::Call(int nr, | 219 intptr_t Syscall::Call(int nr, |
179 intptr_t p0, | 220 intptr_t p0, |
180 intptr_t p1, | 221 intptr_t p1, |
181 intptr_t p2, | 222 intptr_t p2, |
182 intptr_t p3, | 223 intptr_t p3, |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
252 // it. | 293 // it. |
253 // In ARM mode, we have a dedicated frame pointer register and "r7" is | 294 // In ARM mode, we have a dedicated frame pointer register and "r7" is |
254 // thus available as a general purpose register. We don't preserve it, | 295 // thus available as a general purpose register. We don't preserve it, |
255 // but instead mark it as clobbered. | 296 // but instead mark it as clobbered. |
256 , | 297 , |
257 "r7" | 298 "r7" |
258 #endif // !defined(__thumb__) | 299 #endif // !defined(__thumb__) |
259 ); | 300 ); |
260 ret = inout; | 301 ret = inout; |
261 } | 302 } |
| 303 #elif defined(__mips__) |
| 304 int err_status; |
| 305 intptr_t ret = Syscall::SandboxSyscallRaw(nr, args, &err_status); |
| 306 |
| 307 if (err_status) { |
| 308 // On error, MIPS returns errno from syscall instead of -errno. |
| 309 // The purpose of this negation is for SandboxSyscall() to behave |
| 310 // more like it would on other architectures. |
| 311 ret = -ret; |
| 312 } |
262 #else | 313 #else |
263 #error "Unimplemented architecture" | 314 #error "Unimplemented architecture" |
264 #endif | 315 #endif |
265 return ret; | 316 return ret; |
266 } | 317 } |
267 | 318 |
| 319 void Syscall::PutValueInUcontext(intptr_t ret_val, ucontext_t* ctx) { |
| 320 #if defined(__mips__) |
| 321 // Mips ABI states that on error a3 CPU register has non zero value and if |
| 322 // there is no error, it should be zero. |
| 323 if (ret_val <= -1 && ret_val >= -4095) { |
| 324 // |ret_val| followes the Syscall::Call() convention of being -errno on |
| 325 // errors. In order to write correct value to return register this sign |
| 326 // needs to be changed back. |
| 327 ret_val = -ret_val; |
| 328 SECCOMP_PARM4(ctx) = 1; |
| 329 } else |
| 330 SECCOMP_PARM4(ctx) = 0; |
| 331 #endif |
| 332 SECCOMP_RESULT(ctx) = static_cast<greg_t>(ret_val); |
| 333 } |
| 334 |
| 335 #if defined(__mips__) |
| 336 intptr_t Syscall::SandboxSyscallRaw(int nr, |
| 337 const intptr_t* args, |
| 338 intptr_t* err_ret) { |
| 339 register intptr_t ret __asm__("v0") = nr; |
| 340 // a3 register becomes non zero on error. |
| 341 register intptr_t err_stat __asm__("a3") = 0; |
| 342 { |
| 343 register const intptr_t* data __asm__("a0") = args; |
| 344 asm volatile( |
| 345 "la $t9, SyscallAsm\n" |
| 346 "jalr $t9\n" |
| 347 " nop\n" |
| 348 : "=r"(ret), "=r"(err_stat) |
| 349 : "0"(ret), |
| 350 "r"(data) |
| 351 // a2 is in the clober list so inline assembly can not change its |
| 352 // value. |
| 353 : "memory", "ra", "t9", "a2"); |
| 354 } |
| 355 |
| 356 // Set an error status so it can be used outside of this function |
| 357 *err_ret = err_stat; |
| 358 |
| 359 return ret; |
| 360 } |
| 361 #endif // defined(__mips__) |
| 362 |
268 } // namespace sandbox | 363 } // namespace sandbox |
OLD | NEW |