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 |