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

Side by Side Diff: sandbox/linux/seccomp/trusted_process.cc

Issue 3225010: Pull seccomp-sandbox in via DEPS rather than using an in-tree copy... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 10 years, 3 months 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
« no previous file with comments | « sandbox/linux/seccomp/tls.h ('k') | sandbox/linux/seccomp/trusted_thread.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 <dirent.h>
6 #include <map>
7
8 #include "debug.h"
9 #include "sandbox_impl.h"
10 #include "syscall_table.h"
11
12 namespace playground {
13
14 struct SandboxPolicy g_policy;
15
16 struct Thread {
17 int fdPub, fd;
18 SecureMem::Args* mem;
19 };
20
21 SecureMem::Args* Sandbox::getNewSecureMem() {
22 if (!secureMemPool_.empty()) {
23 SecureMem::Args* rc = secureMemPool_.back();
24 secureMemPool_.pop_back();
25 memset(rc->scratchPage, 0, sizeof(rc->scratchPage));
26 return rc;
27 }
28 return NULL;
29 }
30
31 void Sandbox::trustedProcess(int parentMapsFd, int processFdPub, int sandboxFd,
32 int cloneFd, SecureMem::Args* secureArena) {
33 // The trusted process doesn't have access to TLS. Zero out the segment
34 // registers so that we can later test that we are in the trusted process.
35 #if defined(__x86_64__)
36 asm volatile("mov %0, %%gs\n" : : "r"(0));
37 #elif defined(__i386__)
38 asm volatile("mov %0, %%fs\n" : : "r"(0));
39 #else
40 #error Unsupported target platform
41 #endif
42
43 std::map<long long, struct Thread> threads;
44 SysCalls sys;
45 long long cookie = 0;
46
47 // The very first entry in the secure memory arena has been assigned to the
48 // initial thread. The remaining entries are available for allocation.
49 SecureMem::Args* startAddress = secureArena;
50 SecureMem::Args* nextThread = startAddress;
51 for (int i = 0; i < kMaxThreads-1; i++) {
52 secureMemPool_.push_back(++startAddress);
53 }
54
55 newThreadCreated:
56 // Receive information from newly created thread
57 Thread *newThread = &threads[++cookie];
58 memset(newThread, 0, sizeof(Thread));
59 struct {
60 SecureMem::Args* self;
61 int tid;
62 int fdPub;
63 } __attribute__((packed)) data;
64
65 size_t dataLen = sizeof(data);
66 if (!getFd(cloneFd, &newThread->fdPub, &newThread->fd, &data, &dataLen) ||
67 dataLen != sizeof(data)) {
68 // We get here either because the sandbox got corrupted, or because our
69 // parent process has terminated.
70 if (newThread->fdPub || dataLen) {
71 die("Failed to receive new thread information");
72 }
73 die();
74 }
75 if (data.self != nextThread) {
76 // The only potentially security critical information received from the
77 // newly created thread is "self". The "tid" is for informational purposes
78 // (and for use in the new thread's TLS), and "fdPub" is uncritical as all
79 // file descriptors are considered untrusted.
80 // Thus, we only use "self" for a sanity check, but don't actually trust
81 // it beyond that.
82 die("Received corrupted thread information");
83 }
84 newThread->mem = nextThread;
85
86 // Set up TLS area and let thread know that the data is now ready
87 nextThread->cookie = cookie;
88 nextThread->threadId = data.tid;
89 nextThread->threadFdPub = data.fdPub;
90 write(sys, newThread->fd, "", 1);
91
92 // Dispatch system calls that have been forwarded from the trusted thread(s).
93 for (;;) {
94 struct {
95 unsigned int sysnum;
96 long long cookie;
97 } __attribute__((packed)) header;
98
99 int rc;
100 if ((rc = read(sys, sandboxFd, &header, sizeof(header))) !=sizeof(header)){
101 if (rc) {
102 die("Failed to read system call number and thread id");
103 }
104 die();
105 }
106 std::map<long long, struct Thread>::iterator iter =
107 threads.find(header.cookie);
108 if (iter == threads.end()) {
109 die("Received request from unknown thread");
110 }
111 struct Thread* currentThread = &iter->second;
112 if (header.sysnum > maxSyscall ||
113 !syscallTable[header.sysnum].trustedProcess) {
114 die("Trusted process encountered unexpected system call");
115 }
116
117 // Dispatch system call to handler function. Treat both exit() and clone()
118 // specially.
119 if (syscallTable[header.sysnum].trustedProcess(parentMapsFd,
120 sandboxFd,
121 currentThread->fdPub,
122 currentThread->fd,
123 currentThread->mem) &&
124 header.sysnum == __NR_clone) {
125 nextThread = currentThread->mem->newSecureMem;
126 goto newThreadCreated;
127 } else if (header.sysnum == __NR_exit) {
128 NOINTR_SYS(sys.close(iter->second.fdPub));
129 NOINTR_SYS(sys.close(iter->second.fd));
130 SecureMem::Args* secureMem = currentThread->mem;
131 threads.erase(iter);
132 secureMemPool_.push_back(secureMem);
133 }
134 }
135 }
136
137 int Sandbox::initializeProtectedMap(int fd) {
138 int mapsFd;
139 if (!getFd(fd, &mapsFd, NULL, NULL, NULL)) {
140 maps_failure:
141 die("Cannot access /proc/self/maps");
142 }
143
144 // Read the memory mappings as they were before the sandbox takes effect.
145 // These mappings cannot be changed by the sandboxed process.
146 char line[80];
147 FILE *fp = fdopen(mapsFd, "r");
148 for (bool truncated = false;;) {
149 if (fgets(line, sizeof(line), fp) == NULL) {
150 if (feof(fp) || errno != EINTR) {
151 break;
152 }
153 continue;
154 }
155 if (!truncated) {
156 unsigned long start, stop;
157 char *ptr = line;
158 errno = 0;
159 start = strtoul(ptr, &ptr, 16);
160 if (errno || *ptr++ != '-') {
161 parse_failure:
162 die("Failed to parse /proc/self/maps");
163 }
164 stop = strtoul(ptr, &ptr, 16);
165 if (errno || *ptr++ != ' ') {
166 goto parse_failure;
167 }
168 protectedMap_[reinterpret_cast<void *>(start)] = stop - start;
169 }
170 truncated = strchr(line, '\n') == NULL;
171 }
172
173 // Prevent low address memory allocations. Some buggy kernels allow those
174 if (protectedMap_[0] < (64 << 10)) {
175 protectedMap_[0] = 64 << 10;
176 }
177
178 // Let the sandbox know that we are done parsing the memory map.
179 SysCalls sys;
180 if (write(sys, fd, &mapsFd, sizeof(mapsFd)) != sizeof(mapsFd)) {
181 goto maps_failure;
182 }
183
184 return mapsFd;
185 }
186
187 SecureMem::Args* Sandbox::createTrustedProcess(int processFdPub, int sandboxFd,
188 int cloneFdPub, int cloneFd) {
189 // Allocate memory that will be used by an arena for storing the secure
190 // memory. While we allow this memory area to be empty at times (e.g. when
191 // not all threads are in use), we make sure that it never gets overwritten
192 // by user-allocated memory. This happens in initializeProtectedMap() and
193 // snapshotMemoryMappings().
194 SecureMem::Args* secureArena = reinterpret_cast<SecureMem::Args*>(
195 mmap(NULL, 8192*kMaxThreads, PROT_READ|PROT_WRITE,
196 MAP_SHARED|MAP_ANONYMOUS, -1, 0));
197 if (secureArena == MAP_FAILED) {
198 die("Failed to allocate secure memory arena");
199 }
200
201 // Set up the mutex to be accessible from the trusted process and from
202 // children of the trusted thread(s)
203 if (mmap(&syscall_mutex_, 4096, PROT_READ|PROT_WRITE,
204 MAP_SHARED|MAP_ANONYMOUS|MAP_FIXED, -1, 0) != &syscall_mutex_) {
205 die("Failed to initialize secure mutex");
206 }
207 syscall_mutex_ = 0x80000000;
208
209
210 // Create a trusted process that can evaluate system call parameters and
211 // decide whether a system call should execute. This process runs outside of
212 // the seccomp sandbox. It communicates with the sandbox'd process through
213 // a socketpair() and through securely shared memory.
214 pid_t pid = fork();
215 if (pid < 0) {
216 die("Failed to create trusted process");
217 }
218 if (!pid) {
219 // Close all file handles except for sandboxFd, cloneFd, and stdio
220 DIR *dir = opendir("/proc/self/fd");
221 if (dir == 0) {
222 // If we don't know the list of our open file handles, just try closing
223 // all valid ones.
224 for (int fd = sysconf(_SC_OPEN_MAX); --fd > 2; ) {
225 if (fd != sandboxFd && fd != cloneFd) {
226 close(fd);
227 }
228 }
229 } else {
230 // If available, if is much more efficient to just close the file
231 // handles that show up in /proc/self/fd/
232 struct dirent de, *res;
233 while (!readdir_r(dir, &de, &res) && res) {
234 if (res->d_name[0] < '0')
235 continue;
236 int fd = atoi(res->d_name);
237 if (fd > 2 &&
238 fd != sandboxFd && fd != cloneFd && fd != dirfd(dir)) {
239 close(fd);
240 }
241 }
242 closedir(dir);
243 }
244
245 // Initialize secure memory used for threads
246 for (int i = 0; i < kMaxThreads; i++) {
247 SecureMem::Args* args = secureArena + i;
248 args->self = args;
249 #ifndef NDEBUG
250 args->allowAllSystemCalls= Debug::isEnabled();
251 #endif
252 }
253
254 int parentMapsFd = initializeProtectedMap(sandboxFd);
255 trustedProcess(parentMapsFd, processFdPub, sandboxFd,
256 cloneFd, secureArena);
257 die();
258 }
259
260 // We are still in the untrusted code. Deny access to restricted resources.
261 mprotect(secureArena, 8192*kMaxThreads, PROT_NONE);
262 mprotect(&syscall_mutex_, 4096, PROT_NONE);
263 close(sandboxFd);
264
265 return secureArena;
266 }
267
268 } // namespace
OLDNEW
« no previous file with comments | « sandbox/linux/seccomp/tls.h ('k') | sandbox/linux/seccomp/trusted_thread.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698