Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(255)

Side by Side Diff: sandbox/linux/seccomp-bpf/syscall.cc

Issue 11416326: SECCOMP-BPF: Fix SandboxSyscall() (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 <asm/unistd.h> 5 #include <asm/unistd.h>
6 #include <bits/wordsize.h> 6 #include <bits/wordsize.h>
7 #include <errno.h> 7 #include <errno.h>
8 #include <stdarg.h>
9 8
10 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" 9 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
11 #include "sandbox/linux/seccomp-bpf/syscall.h" 10 #include "sandbox/linux/seccomp-bpf/syscall.h"
12 11
13 12
14 namespace playground2 { 13 namespace playground2 {
15 14
16 asm( // We need to be able to tell the kernel exactly where we made a 15 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 16 // system call. The C++ compiler likes to sometimes clone or
18 // inline code, which would inadvertently end up duplicating 17 // inline code, which would inadvertently end up duplicating
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
166 "2:pop {r7, pc}\n" 165 "2:pop {r7, pc}\n"
167 ".cfi_endproc\n" 166 ".cfi_endproc\n"
168 #else 167 #else
169 "2:ldmfd sp!, {fp, pc}\n" 168 "2:ldmfd sp!, {fp, pc}\n"
170 #endif 169 #endif
171 ".fnend\n" 170 ".fnend\n"
172 "9:.size SyscallAsm, 9b-SyscallAsm\n" 171 "9:.size SyscallAsm, 9b-SyscallAsm\n"
173 #endif 172 #endif
174 ); // asm 173 ); // asm
175 174
176 #if defined(ADDRESS_SANITIZER) 175 intptr_t SandboxSyscall(int nr,
177 // ASAN will complain because we look at 6 arguments on the stack no matter 176 intptr_t p0, intptr_t p1, intptr_t p2,
178 // what. This is probably ok for a debugging feature, see crbug.com/162925. 177 intptr_t p3, intptr_t p4, intptr_t p5) {
179 __attribute__((no_address_safety_analysis)) 178 // We rely on "intptr_t" to be the exact size as a "void *". This is
180 #endif 179 // typically true, but just in case, we add a check. The language
181 intptr_t SandboxSyscall(int nr, ...) { 180 // specification allows platforms some leeway in cases, where
182 // It is most convenient for the caller to pass a variadic list of arguments. 181 // "sizeof(void *)" is not the same as "sizeof(void (*)())". We expect
183 // But this is difficult to handle in assembly code without making 182 // that this would only be an issue for IA64, which we are currently not
Jeffrey Yasskin 2012/12/03 22:40:16 Apparently intptr_t is _not_ required to be big en
Markus (顧孟勤) 2012/12/04 00:54:39 I am actually somewhat positive this would work on
Jeffrey Yasskin 2012/12/04 01:18:48 I don't know for sure what IA64 does for function
184 // assumptions about internal implementation details of "va_list". So, we 183 // planning on supporting. And it is even possible that this would work
185 // first use C code to copy all the arguments into an array, where they are 184 // on IA64, but for lack of actual hardware, I cannot test.
186 // easily accessible to asm(). 185 // N.B. This check will never actually print a message, as doing so requires
187 // This is preferable over copying them into individual variables, which 186 // a recursive call to SandboxSyscall(). Expect to see a stack overflow with
188 // can result in too much register pressure. 187 // a very obvious call signature.
189 if (sizeof(void *)*8 != __WORDSIZE) { 188 if (sizeof(void *) != sizeof(intptr_t)) {
Jeffrey Yasskin 2012/12/03 22:27:35 You can compile-assert this. If you don't have COM
Markus (顧孟勤) 2012/12/04 00:54:39 Sweet. Yes, that's exactly what I needed here. I h
190 SANDBOX_DIE("This can't happen! " 189 SANDBOX_DIE("This can't happen! "
191 "__WORDSIZE doesn't agree with actual size"); 190 "\"void *\" and \"intptr_t\" have different width.");
192 } 191 }
193 void *args[6]; 192 const intptr_t args[6] = { p0, p1, p2, p3, p4, p5 };
Jeffrey Yasskin 2012/12/03 22:27:35 If the kernel could ever write on one of these arg
Markus (顧孟勤) 2012/12/04 00:54:39 If you carefully look at the assembly code, you'll
Jeffrey Yasskin 2012/12/04 01:18:48 Ok, sounds good.
194 va_list ap;
195
196 // System calls take a system call number (typically passed in %eax or
197 // %rax) and up to six arguments (passed in general-purpose CPU registers).
198 //
199 // On 32bit systems, all variadic arguments are passed on the stack as 32bit
200 // quantities. We can use an arbitrary 32bit type to retrieve them with
201 // va_arg() and then forward them to the kernel in the appropriate CPU
202 // register. We do not need to know whether this is an integer or a pointer
203 // value.
204 //
205 // On 64bit systems, variadic arguments can be either 32bit or 64bit wide,
206 // which would seem to make it more important that we pass the correct type
207 // to va_arg(). And we really can't know what this type is unless we have a
208 // table with function signatures for all system calls.
209 //
210 // Fortunately, on x86-64 this is less critical. The first six function
211 // arguments will be passed in CPU registers, no matter whether they were
212 // named or variadic. This only leaves us with a single argument (if present)
213 // that could be passed on the stack. And since x86-64 is little endian,
214 // it will have the correct value both for 32bit and 64bit quantities.
215 //
216 // N.B. Because of how the x86-64 ABI works, it is possible that 32bit
217 // quantities will have undefined garbage bits in the upper 32 bits of a
218 // 64bit register. This is relatively unlikely for the first five system
219 // call arguments, as the processor does automatic sign extensions and zero
220 // filling so frequently, there rarely is garbage in CPU registers. But it
221 // is quite likely for the last argument, which is passed on the stack.
222 // That's generally OK, because the kernel has the correct function
223 // signatures and knows to only inspect the LSB of a 32bit value.
224 // But callers must be careful in cases, where the compiler cannot tell
225 // the difference (e.g. when passing NULL to any system call, it must
226 // always be cast to a pointer type).
227 // The glibc implementation of syscall() has the exact same issues.
228 // In the unlikely event that this ever becomes a problem, we could add
229 // code that handles six-argument system calls specially. The number of
230 // system calls that take six arguments and expect a 32bit value in the
231 // sixth argument is very limited.
232 va_start(ap, nr);
233 args[0] = va_arg(ap, void *);
234 args[1] = va_arg(ap, void *);
235 args[2] = va_arg(ap, void *);
236 args[3] = va_arg(ap, void *);
237 args[4] = va_arg(ap, void *);
238 args[5] = va_arg(ap, void *);
239 va_end(ap);
240 193
241 // Invoke our file-scope assembly code. The constraints have been picked 194 // Invoke our file-scope assembly code. The constraints have been picked
242 // carefully to match what the rest of the assembly code expects in input, 195 // carefully to match what the rest of the assembly code expects in input,
243 // output, and clobbered registers. 196 // output, and clobbered registers.
244 #if defined(__i386__) 197 #if defined(__i386__)
245 intptr_t ret = nr; 198 intptr_t ret = nr;
246 asm volatile( 199 asm volatile(
247 "call SyscallAsm\n" 200 "call SyscallAsm\n"
248 // N.B. These are not the calling conventions normally used by the ABI. 201 // N.B. These are not the calling conventions normally used by the ABI.
249 : "=a"(ret) 202 : "=a"(ret)
250 : "0"(ret), "D"(args) 203 : "0"(ret), "D"(args)
251 : "esp", "memory", "ecx", "edx"); 204 : "esp", "memory", "ecx", "edx");
252 #elif defined(__x86_64__) 205 #elif defined(__x86_64__)
253 intptr_t ret = nr; 206 intptr_t ret = nr;
254 { 207 {
255 register void **data __asm__("r12") = args; 208 register const intptr_t *data __asm__("r12") = args;
256 asm volatile( 209 asm volatile(
257 "call SyscallAsm\n" 210 "call SyscallAsm\n"
258 // N.B. These are not the calling conventions normally used by the ABI. 211 // N.B. These are not the calling conventions normally used by the ABI.
259 : "=a"(ret) 212 : "=a"(ret)
260 : "0"(ret), "r"(data) 213 : "0"(ret), "r"(data)
261 : "rsp", "memory", 214 : "rsp", "memory",
262 "rcx", "rdi", "rsi", "rdx", "r8", "r9", "r10", "r11"); 215 "rcx", "rdi", "rsi", "rdx", "r8", "r9", "r10", "r11");
263 } 216 }
264 #elif defined(__arm__) 217 #elif defined(__arm__)
265 intptr_t ret; 218 intptr_t ret;
266 { 219 {
267 register intptr_t inout __asm__("r0") = nr; 220 register intptr_t inout __asm__("r0") = nr;
268 register void **data __asm__("r6") = args; 221 register const intptr_t *data __asm__("r6") = args;
269 asm volatile( 222 asm volatile(
270 "bl SyscallAsm\n" 223 "bl SyscallAsm\n"
271 // N.B. These are not the calling conventions normally used by the ABI. 224 // N.B. These are not the calling conventions normally used by the ABI.
272 : "=r"(inout) 225 : "=r"(inout)
273 : "0"(inout), "r"(data) 226 : "0"(inout), "r"(data)
274 : "lr", "memory", "r1", "r2", "r3", "r4", "r5" 227 : "lr", "memory", "r1", "r2", "r3", "r4", "r5"
275 #if !defined(__arm__) 228 #if !defined(__arm__)
276 // In thumb mode, we cannot use "r7" as a general purpose register, as 229 // In thumb mode, we cannot use "r7" as a general purpose register, as
277 // it is our frame pointer. We have to manually manage and preserve it. 230 // it is our frame pointer. We have to manually manage and preserve it.
278 // In ARM mode, we have a dedicated frame pointer register and "r7" is 231 // In ARM mode, we have a dedicated frame pointer register and "r7" is
279 // thus available as a general purpose register. We don't preserve it, 232 // thus available as a general purpose register. We don't preserve it,
280 // but instead mark it as clobbered. 233 // but instead mark it as clobbered.
281 , "r7" 234 , "r7"
282 #endif 235 #endif
283 ); 236 );
284 ret = inout; 237 ret = inout;
285 } 238 }
286 #else 239 #else
287 errno = ENOSYS; 240 errno = ENOSYS;
288 intptr_t ret = -1; 241 intptr_t ret = -1;
289 #endif 242 #endif
290 return ret; 243 return ret;
291 } 244 }
292 245
293 } // namespace 246 } // namespace
OLDNEW
« sandbox/linux/seccomp-bpf/syscall.h ('K') | « sandbox/linux/seccomp-bpf/syscall.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698