OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "debug.h" | |
6 #include "sandbox_impl.h" | |
7 | |
8 namespace playground { | |
9 | |
10 long Sandbox::sandbox_clone(int flags, char* stack, int* pid, int* ctid, | |
11 void* tls, void *wrapper_sp) { | |
12 long long tm; | |
13 Debug::syscall(&tm, __NR_clone, "Executing handler"); | |
14 struct { | |
15 int sysnum; | |
16 long long cookie; | |
17 Clone clone_req; | |
18 } __attribute__((packed)) request; | |
19 request.sysnum = __NR_clone; | |
20 request.cookie = cookie(); | |
21 request.clone_req.flags = flags; | |
22 request.clone_req.stack = stack; | |
23 request.clone_req.pid = pid; | |
24 request.clone_req.ctid = ctid; | |
25 request.clone_req.tls = tls; | |
26 | |
27 // TODO(markus): Passing stack == 0 currently does not do the same thing | |
28 // that the kernel would do without the sandbox. This is just going to | |
29 // cause a crash. We should detect this case, and replace the stack pointer | |
30 // with the correct value, instead. | |
31 // This is complicated by the fact that we will temporarily be executing | |
32 // both threads from the same stack. Some synchronization will be necessary. | |
33 // Fortunately, this complication also explains why hardly anybody ever | |
34 // does this. | |
35 // See trusted_thread.cc for more information. | |
36 long rc; | |
37 if (stack == 0) { | |
38 rc = -EINVAL; | |
39 } else { | |
40 // Pass along the address on the stack where syscallWrapper() stored the | |
41 // original CPU registers. These registers will be restored in the newly | |
42 // created thread prior to returning from the wrapped system call. | |
43 #if defined(__x86_64__) | |
44 memcpy(&request.clone_req.regs64, wrapper_sp, | |
45 sizeof(request.clone_req.regs64) + sizeof(void *)); | |
46 #elif defined(__i386__) | |
47 memcpy(&request.clone_req.regs32, wrapper_sp, | |
48 sizeof(request.clone_req.regs32) + sizeof(void *)); | |
49 #else | |
50 #error Unsupported target platform | |
51 #endif | |
52 | |
53 // In order to unblock the signal mask in the newly created thread and | |
54 // after entering Seccomp mode, we have to call sigreturn(). But that | |
55 // requires access to a proper stack frame describing a valid signal. | |
56 // We trigger a signal now and make sure the stack frame ends up on the | |
57 // new stack. Our segv() handler (in sandbox.cc) does that for us. | |
58 // See trusted_thread.cc for more details on how threads get created. | |
59 // | |
60 // In general we rely on the kernel for generating the signal stack | |
61 // frame, as the exact binary format has been extended several times over | |
62 // the course of the kernel's development. Fortunately, the kernel | |
63 // developers treat the initial part of the stack frame as a stable part | |
64 // of the ABI. So, we can rely on fixed, well-defined offsets for accessing | |
65 // register values and for accessing the signal mask. | |
66 #if defined(__x86_64__) | |
67 // Red zone compensation. The instrumented system call will remove 128 | |
68 // bytes from the thread's stack prior to returning to the original | |
69 // call site. | |
70 stack -= 128; | |
71 request.clone_req.stack = stack; | |
72 void *dummy; | |
73 asm volatile("mov %%rsp, %%rcx\n" | |
74 "mov %3, %%rsp\n" | |
75 "int $0\n" | |
76 "mov %%rcx, %%rsp\n" | |
77 : "=a"(request.clone_req.stack), "=&c"(dummy) | |
78 : "a"(__NR_clone + 0xF000), "m"(request.clone_req.stack) | |
79 : "memory"); | |
80 #elif defined(__i386__) | |
81 void *dummy; | |
82 asm volatile("mov %%esp, %%ecx\n" | |
83 "mov %3, %%esp\n" | |
84 "int $0\n" | |
85 "mov %%ecx, %%esp\n" | |
86 : "=a"(request.clone_req.stack), "=&c"(dummy) | |
87 : "a"(__NR_clone + 0xF000), "m"(request.clone_req.stack) | |
88 : "memory"); | |
89 #else | |
90 #error Unsupported target platform | |
91 #endif | |
92 | |
93 // Adjust the signal stack frame so that it contains the correct stack | |
94 // pointer upon returning from sigreturn(). | |
95 #if defined(__x86_64__) | |
96 *(char **)(request.clone_req.stack + 0xA0) = stack; | |
97 #elif defined(__i386__) | |
98 *(char **)(request.clone_req.stack + 0x1C) = stack; | |
99 #else | |
100 #error Unsupported target platform | |
101 #endif | |
102 | |
103 SysCalls sys; | |
104 if (write(sys, processFdPub(), &request, sizeof(request)) != | |
105 sizeof(request) || | |
106 read(sys, threadFdPub(), &rc, sizeof(rc)) != sizeof(rc)) { | |
107 die("Failed to forward clone() request [sandbox]"); | |
108 } | |
109 } | |
110 Debug::elapsed(tm, __NR_clone); | |
111 return rc; | |
112 } | |
113 | |
114 bool Sandbox::process_clone(int parentMapsFd, int sandboxFd, int threadFdPub, | |
115 int threadFd, SecureMem::Args* mem) { | |
116 // Read request | |
117 Clone clone_req; | |
118 SysCalls sys; | |
119 if (read(sys, sandboxFd, &clone_req, sizeof(clone_req)) !=sizeof(clone_req)){ | |
120 die("Failed to read parameters for clone() [process]"); | |
121 } | |
122 | |
123 // TODO(markus): add policy restricting parameters for clone | |
124 if ((clone_req.flags & ~CLONE_DETACHED) != (CLONE_VM|CLONE_FS|CLONE_FILES| | |
125 CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS| | |
126 CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID)) { | |
127 SecureMem::abandonSystemCall(threadFd, -EPERM); | |
128 return false; | |
129 } else { | |
130 SecureMem::Args* newMem = getNewSecureMem(); | |
131 if (!newMem) { | |
132 SecureMem::abandonSystemCall(threadFd, -ENOMEM); | |
133 return false; | |
134 } else { | |
135 // clone() has unusual semantics. We don't want to return back into the | |
136 // trusted thread, but instead we need to continue execution at the IP | |
137 // where we got called initially. | |
138 SecureMem::lockSystemCall(parentMapsFd, mem); | |
139 mem->ret = clone_req.ret; | |
140 #if defined(__x86_64__) | |
141 mem->rbp = clone_req.regs64.rbp; | |
142 mem->rbx = clone_req.regs64.rbx; | |
143 mem->rcx = clone_req.regs64.rcx; | |
144 mem->rdx = clone_req.regs64.rdx; | |
145 mem->rsi = clone_req.regs64.rsi; | |
146 mem->rdi = clone_req.regs64.rdi; | |
147 mem->r8 = clone_req.regs64.r8; | |
148 mem->r9 = clone_req.regs64.r9; | |
149 mem->r10 = clone_req.regs64.r10; | |
150 mem->r11 = clone_req.regs64.r11; | |
151 mem->r12 = clone_req.regs64.r12; | |
152 mem->r13 = clone_req.regs64.r13; | |
153 mem->r14 = clone_req.regs64.r14; | |
154 mem->r15 = clone_req.regs64.r15; | |
155 #elif defined(__i386__) | |
156 mem->ebp = clone_req.regs32.ebp; | |
157 mem->edi = clone_req.regs32.edi; | |
158 mem->esi = clone_req.regs32.esi; | |
159 mem->edx = clone_req.regs32.edx; | |
160 mem->ecx = clone_req.regs32.ecx; | |
161 mem->ebx = clone_req.regs32.ebx; | |
162 #else | |
163 #error Unsupported target platform | |
164 #endif | |
165 newMem->sequence = 0; | |
166 newMem->shmId = -1; | |
167 mem->newSecureMem = newMem; | |
168 mem->processFdPub = processFdPub_; | |
169 mem->cloneFdPub = cloneFdPub_; | |
170 | |
171 SecureMem::sendSystemCall(threadFdPub, true, parentMapsFd, mem, | |
172 __NR_clone, clone_req.flags, clone_req.stack, | |
173 clone_req.pid, clone_req.ctid, clone_req.tls); | |
174 return true; | |
175 } | |
176 } | |
177 } | |
178 | |
179 } // namespace | |
OLD | NEW |