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" |
11 | 10 |
12 namespace sandbox { | 11 namespace sandbox { |
13 | 12 |
14 asm( // We need to be able to tell the kernel exactly where we made a | 13 asm( // We need to be able to tell the kernel exactly where we made a |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
161 // Restore the frame pointer. Also restore the program counter from | 160 // Restore the frame pointer. Also restore the program counter from |
162 // the link register; this makes us return to the caller. | 161 // the link register; this makes us return to the caller. |
163 #if defined(__thumb__) | 162 #if defined(__thumb__) |
164 "2:pop {r7, pc}\n" | 163 "2:pop {r7, pc}\n" |
165 ".cfi_endproc\n" | 164 ".cfi_endproc\n" |
166 #else | 165 #else |
167 "2:ldmfd sp!, {fp, pc}\n" | 166 "2:ldmfd sp!, {fp, pc}\n" |
168 #endif | 167 #endif |
169 ".fnend\n" | 168 ".fnend\n" |
170 "9:.size SyscallAsm, 9b-SyscallAsm\n" | 169 "9:.size SyscallAsm, 9b-SyscallAsm\n" |
| 170 #elif defined(__mips__) |
| 171 ".text\n" |
| 172 ".align 4\n" |
| 173 ".type SyscallAsm, @function\n" |
| 174 "SyscallAsm:.ent SyscallAsm\n" |
| 175 ".frame $sp, 32, $ra\n" |
| 176 ".set push\n" |
| 177 ".set noreorder\n" |
| 178 "addiu $sp, $sp, -32\n" |
| 179 "sw $ra, 28($sp)\n" |
| 180 // Check if "v0" is negative. If so, do not attempt to make a |
| 181 // system call. Instead, compute the return address that is visible |
| 182 // to the kernel after we execute "syscall". This address can be |
| 183 // used as a marker that BPF code inspects. |
| 184 "bgez $v0, 1f\n" |
| 185 " nop\n" |
| 186 "la $v0, 2f\n" |
| 187 "b 2f\n" |
| 188 " nop\n" |
| 189 // On MIPS first four arguments go to registers a0 - a3 and any |
| 190 // argument after that goes to stack. We can go ahead and directly |
| 191 // copy the entries from the arguments array into the appropriate |
| 192 // CPU registers and on the stack. |
| 193 "1:lw $t0, 20($a0)\n" |
| 194 "sw $t0, 20($sp)\n" |
| 195 "lw $t0, 16($a0)\n" |
| 196 "sw $t0, 16($sp)\n" |
| 197 "lw $a3, 12($a0)\n" |
| 198 "lw $a2, 8($a0)\n" |
| 199 "lw $a1, 4($a0)\n" |
| 200 "lw $a0, 0($a0)\n" |
| 201 // Enter the kernel |
| 202 "syscall\n" |
| 203 // This is our "magic" return address that the BPF filter sees. |
| 204 // Restore the return address from the stack. |
| 205 "2:lw $ra, 28($sp)\n" |
| 206 "jr $ra\n" |
| 207 " addiu $sp, $sp, 32\n" |
| 208 ".set pop\n" |
| 209 ".end SyscallAsm\n" |
| 210 ".size SyscallAsm,.-SyscallAsm\n" |
171 #endif | 211 #endif |
172 ); // asm | 212 ); // asm |
173 | 213 |
174 intptr_t SandboxSyscall(int nr, | 214 intptr_t SandboxSyscall(int nr, |
175 intptr_t p0, intptr_t p1, intptr_t p2, | 215 intptr_t p0, intptr_t p1, intptr_t p2, |
176 intptr_t p3, intptr_t p4, intptr_t p5) { | 216 intptr_t p3, intptr_t p4, intptr_t p5) { |
177 // We rely on "intptr_t" to be the exact size as a "void *". This is | 217 // We rely on "intptr_t" to be the exact size as a "void *". This is |
178 // typically true, but just in case, we add a check. The language | 218 // typically true, but just in case, we add a check. The language |
179 // specification allows platforms some leeway in cases, where | 219 // specification allows platforms some leeway in cases, where |
180 // "sizeof(void *)" is not the same as "sizeof(void (*)())". We expect | 220 // "sizeof(void *)" is not the same as "sizeof(void (*)())". We expect |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
226 // In thumb mode, we cannot use "r7" as a general purpose register, as | 266 // In thumb mode, we cannot use "r7" as a general purpose register, as |
227 // it is our frame pointer. We have to manually manage and preserve it. | 267 // it is our frame pointer. We have to manually manage and preserve it. |
228 // In ARM mode, we have a dedicated frame pointer register and "r7" is | 268 // In ARM mode, we have a dedicated frame pointer register and "r7" is |
229 // thus available as a general purpose register. We don't preserve it, | 269 // thus available as a general purpose register. We don't preserve it, |
230 // but instead mark it as clobbered. | 270 // but instead mark it as clobbered. |
231 , "r7" | 271 , "r7" |
232 #endif // !defined(__thumb__) | 272 #endif // !defined(__thumb__) |
233 ); | 273 ); |
234 ret = inout; | 274 ret = inout; |
235 } | 275 } |
| 276 #elif defined(__mips__) |
| 277 int err_status; |
| 278 intptr_t ret = SandboxSyscallRaw(nr, args, &err_status); |
| 279 |
| 280 if (err_status) { |
| 281 // On error, MIPS returns errno from syscall instead of -errno. |
| 282 // The purpose of this negation is for SandboxSyscall() to behave |
| 283 // more like it would on other architectures. |
| 284 ret = -ret; |
| 285 } |
236 #else | 286 #else |
237 errno = ENOSYS; | 287 errno = ENOSYS; |
238 intptr_t ret = -1; | 288 intptr_t ret = -1; |
239 #endif | 289 #endif |
240 return ret; | 290 return ret; |
241 } | 291 } |
242 | 292 |
| 293 #if defined(__mips__) |
| 294 intptr_t SandboxSyscallRaw(int nr, |
| 295 const intptr_t* args, intptr_t* err_ret) { |
| 296 register intptr_t ret __asm__("v0") = nr; |
| 297 // a3 register becomes non zero on error. |
| 298 register intptr_t err_stat __asm__("a3") = 0; |
| 299 { |
| 300 register const intptr_t* data __asm__("a0") = args; |
| 301 asm volatile( |
| 302 "la $t9, SyscallAsm\n" |
| 303 "jalr $t9\n" |
| 304 " nop\n" |
| 305 : "=r"(ret), "=r"(err_stat) |
| 306 : "0"(ret), "r"(data) |
| 307 // a2 is in the clober list so inline assembly can not change its value. |
| 308 : "memory", "ra", "t9", "a2" |
| 309 ); |
| 310 } |
| 311 |
| 312 // Set an error status so it can be used outside of this function |
| 313 *err_ret = err_stat; |
| 314 |
| 315 return ret; |
| 316 } |
| 317 #endif // defined(__mips__) |
| 318 |
243 } // namespace sandbox | 319 } // namespace sandbox |
OLD | NEW |