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

Side by Side Diff: sandbox/linux/seccomp-bpf/sandbox_bpf.h

Issue 10833044: Refactored ErrorCode into it's own class (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Made changes requested by reviewer (jln) Created 8 years, 4 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
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 #ifndef SANDBOX_BPF_H__ 5 #ifndef SANDBOX_BPF_H__
6 #define SANDBOX_BPF_H__ 6 #define SANDBOX_BPF_H__
7 7
8 #include <endian.h> 8 #include <endian.h>
9 #include <errno.h> 9 #include <errno.h>
10 #include <fcntl.h> 10 #include <fcntl.h>
(...skipping 27 matching lines...) Expand all
38 #include <map> 38 #include <map>
39 #include <utility> 39 #include <utility>
40 #include <vector> 40 #include <vector>
41 41
42 #ifndef SECCOMP_BPF_STANDALONE 42 #ifndef SECCOMP_BPF_STANDALONE
43 #include "base/basictypes.h" 43 #include "base/basictypes.h"
44 #include "base/eintr_wrapper.h" 44 #include "base/eintr_wrapper.h"
45 #include "base/logging.h" 45 #include "base/logging.h"
46 #endif 46 #endif
47 47
48 #ifdef SECCOMP_BPF_VALGRIND_HACKS
jln (very slow on Chromium) 2012/07/30 18:50:39 In theory this should be #if defined(SECCOMP....).
49 #ifndef SECCOMP_BPF_STANDALONE
50 #include "base/third_party/valgrind/valgrind.h"
51 #endif
52 #endif
53
54 #include "sandbox/linux/seccomp-bpf/errorcode.h"
55
56
48 // The Seccomp2 kernel ABI is not part of older versions of glibc. 57 // The Seccomp2 kernel ABI is not part of older versions of glibc.
49 // As we can't break compilation with these versions of the library, 58 // As we can't break compilation with these versions of the library,
50 // we explicitly define all missing symbols. 59 // we explicitly define all missing symbols.
51 60
52 #ifndef PR_SET_NO_NEW_PRIVS 61 #ifndef PR_SET_NO_NEW_PRIVS
53 #define PR_SET_NO_NEW_PRIVS 38 62 #define PR_SET_NO_NEW_PRIVS 38
54 #define PR_GET_NO_NEW_PRIVS 39 63 #define PR_GET_NO_NEW_PRIVS 39
55 #endif 64 #endif
56 #ifndef IPC_64 65 #ifndef IPC_64
57 #define IPC_64 0x0100 66 #define IPC_64 0x0100
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 #define REG_PARM1 REG_RDI 111 #define REG_PARM1 REG_RDI
103 #define REG_PARM2 REG_RSI 112 #define REG_PARM2 REG_RSI
104 #define REG_PARM3 REG_RDX 113 #define REG_PARM3 REG_RDX
105 #define REG_PARM4 REG_R10 114 #define REG_PARM4 REG_R10
106 #define REG_PARM5 REG_R8 115 #define REG_PARM5 REG_R8
107 #define REG_PARM6 REG_R9 116 #define REG_PARM6 REG_R9
108 #else 117 #else
109 #error Unsupported target platform 118 #error Unsupported target platform
110 #endif 119 #endif
111 120
121
122 namespace playground2 {
123
112 struct arch_seccomp_data { 124 struct arch_seccomp_data {
113 int nr; 125 int nr;
114 uint32_t arch; 126 uint32_t arch;
115 uint64_t instruction_pointer; 127 uint64_t instruction_pointer;
116 uint64_t args[6]; 128 uint64_t args[6];
117 }; 129 };
118 130
119 struct arch_sigsys { 131 struct arch_sigsys {
120 void *ip; 132 void *ip;
121 int nr; 133 int nr;
122 unsigned int arch; 134 unsigned int arch;
123 }; 135 };
124 136
125 #ifdef SECCOMP_BPF_STANDALONE 137 #ifdef SECCOMP_BPF_STANDALONE
126 #define arraysize(x) sizeof(x)/sizeof(*(x))) 138 #define arraysize(x) sizeof(x)/sizeof(*(x)))
127 #define HANDLE_EINTR TEMP_FAILURE_RETRY 139 #define HANDLE_EINTR TEMP_FAILURE_RETRY
128 #define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ 140 #define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
129 TypeName(); \ 141 TypeName(); \
130 TypeName(const TypeName&); \ 142 TypeName(const TypeName&); \
131 void operator=(const TypeName&) 143 void operator=(const TypeName&)
132 #endif 144 #endif
133 145
134
135 namespace playground2 {
136
137 class Sandbox { 146 class Sandbox {
138 public: 147 public:
139 enum SandboxStatus { 148 enum SandboxStatus {
140 STATUS_UNKNOWN, // Status prior to calling supportsSeccompSandbox() 149 STATUS_UNKNOWN, // Status prior to calling supportsSeccompSandbox()
141 STATUS_UNSUPPORTED, // The kernel does not appear to support sandboxing 150 STATUS_UNSUPPORTED, // The kernel does not appear to support sandboxing
142 STATUS_UNAVAILABLE, // Currently unavailable but might work again later 151 STATUS_UNAVAILABLE, // Currently unavailable but might work again later
143 STATUS_AVAILABLE, // Sandboxing is available but not currently active 152 STATUS_AVAILABLE, // Sandboxing is available but not currently active
144 STATUS_ENABLED // The sandbox is now active 153 STATUS_ENABLED // The sandbox is now active
145 }; 154 };
146 155
147 enum {
148 SB_INVALID = -1,
149 SB_ALLOWED = 0x0000,
150 SB_INSPECT_ARG_1 = 0x8001,
151 SB_INSPECT_ARG_2 = 0x8002,
152 SB_INSPECT_ARG_3 = 0x8004,
153 SB_INSPECT_ARG_4 = 0x8008,
154 SB_INSPECT_ARG_5 = 0x8010,
155 SB_INSPECT_ARG_6 = 0x8020
156 };
157
158 // TrapFnc is a pointer to a function that handles Seccomp traps in 156 // TrapFnc is a pointer to a function that handles Seccomp traps in
159 // user-space. The seccomp policy can request that a trap handler gets 157 // user-space. The seccomp policy can request that a trap handler gets
160 // installed; it does so by returning a suitable ErrorCode() from the 158 // installed; it does so by returning a suitable ErrorCode() from the
161 // syscallEvaluator. See the ErrorCode() constructor for how to pass in 159 // syscallEvaluator. See the ErrorCode() constructor for how to pass in
162 // the function pointer. 160 // the function pointer.
163 // Please note that TrapFnc is executed from signal context and must be 161 // Please note that TrapFnc is executed from signal context and must be
164 // async-signal safe: 162 // async-signal safe:
165 // http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html 163 // http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html
166 typedef intptr_t (*TrapFnc)(const struct arch_seccomp_data& args, void *aux); 164 typedef intptr_t (*TrapFnc)(const struct arch_seccomp_data& args, void *aux);
167 165
168 class ErrorCode {
169 friend class Sandbox;
170 public:
171 // We can either wrap a symbolic ErrorCode (i.e. enum values), an errno
172 // value (in the range 1..4095), or a pointer to a TrapFnc callback
173 // handling a SECCOMP_RET_TRAP trap.
174 // All of these different values are stored in the "err_" field. So, code
175 // that is using the ErrorCode class typically operates on a single 32bit
176 // field.
177 // This is not only quiet efficient, it also makes the API really easy to
178 // use.
179 ErrorCode(int err = SB_INVALID)
180 : id_(0),
181 fnc_(NULL),
182 aux_(NULL) {
183 switch (err) {
184 case SB_INVALID:
185 err_ = SECCOMP_RET_INVALID;
186 break;
187 case SB_ALLOWED:
188 err_ = SECCOMP_RET_ALLOW;
189 break;
190 case SB_INSPECT_ARG_1...SB_INSPECT_ARG_6:
191 die("Not implemented");
192 break;
193 case 1 ... 4095:
194 err_ = SECCOMP_RET_ERRNO + err;
195 break;
196 default:
197 die("Invalid use of ErrorCode object");
198 }
199 }
200
201 // If we are wrapping a callback, we must assign a unique id. This id is
202 // how the kernel tells us which one of our different SECCOMP_RET_TRAP
203 // cases has been triggered.
204 // The getTrapId() function assigns one unique id (starting at 1) for
205 // each distinct pair of TrapFnc and auxiliary data.
206 ErrorCode(TrapFnc fnc, const void *aux, int id = 0) :
207 id_(id ? id : getTrapId(fnc, aux)),
208 fnc_(fnc),
209 aux_(const_cast<void *>(aux)),
210 err_(SECCOMP_RET_TRAP + id_) {
211 }
212
213 // Destructor doesn't need to do anything.
214 ~ErrorCode() { }
215
216 // Always return the value that goes into the BPF filter program.
217 operator uint32_t() const { return err_; }
218
219 protected:
220 // Fields needed for SECCOMP_RET_TRAP callbacks
221 int id_;
222 TrapFnc fnc_;
223 void *aux_;
224
225 // 32bit field used for all possible types of ErrorCode values
226 uint32_t err_;
227 };
228
229 enum Operation { 166 enum Operation {
230 OP_NOP, OP_EQUAL, OP_NOTEQUAL, OP_LESS, 167 OP_NOP, OP_EQUAL, OP_NOTEQUAL, OP_LESS,
231 OP_LESS_EQUAL, OP_GREATER, OP_GREATER_EQUAL, 168 OP_LESS_EQUAL, OP_GREATER, OP_GREATER_EQUAL,
232 OP_HAS_BITS, OP_DOES_NOT_HAVE_BITS 169 OP_HAS_BITS, OP_DOES_NOT_HAVE_BITS
233 }; 170 };
234 171
235 struct Constraint { 172 struct Constraint {
236 bool is32bit; 173 bool is32bit;
237 Operation op; 174 Operation op;
238 uint32_t value; 175 uint32_t value;
(...skipping 27 matching lines...) Expand all
266 // of system call argument(s) by returning a suitable combination of 203 // of system call argument(s) by returning a suitable combination of
267 // SB_INSPECT_ARG_x bits. 204 // SB_INSPECT_ARG_x bits.
268 // The system argument evaluator is called (if needed) to query additional 205 // The system argument evaluator is called (if needed) to query additional
269 // constraints for the system call arguments. In the vast majority of 206 // constraints for the system call arguments. In the vast majority of
270 // cases, it will set a "Constraint" that forces a new "errno" value. 207 // cases, it will set a "Constraint" that forces a new "errno" value.
271 // But for more complex filters, it is possible to return another mask 208 // But for more complex filters, it is possible to return another mask
272 // of SB_INSPECT_ARG_x bits. 209 // of SB_INSPECT_ARG_x bits.
273 static void setSandboxPolicy(EvaluateSyscall syscallEvaluator, 210 static void setSandboxPolicy(EvaluateSyscall syscallEvaluator,
274 EvaluateArguments argumentEvaluator); 211 EvaluateArguments argumentEvaluator);
275 212
213 // We can use ErrorCode to request calling of a trap handler. This method
214 // performs the required wrapping of the callback function into an
215 // ErrorCode object.
216 static ErrorCode Trap(ErrorCode::TrapFnc fnc, const void *aux);
217
218 // Kill the program and print an error message.
219 static ErrorCode Kill(const char *msg);
220
276 // This is the main public entry point. It finds all system calls that 221 // This is the main public entry point. It finds all system calls that
277 // need rewriting, sets up the resources needed by the sandbox, and 222 // need rewriting, sets up the resources needed by the sandbox, and
278 // enters Seccomp mode. 223 // enters Seccomp mode.
279 static void startSandbox(); 224 static void startSandbox();
280 225
281 protected:
282 // Print an error message and terminate the program. Used for fatal errors.
283 static void die(const char *msg) __attribute__((noreturn)) {
284 if (msg) {
285 #ifndef SECCOMP_BPF_STANDALONE
286 if (!dryRun_) {
287 // LOG(FATAL) is not neccessarily async-signal safe. It would be
288 // better to always use the code for the SECCOMP_BPF_STANDALONE case.
289 // But that prevents the logging and reporting infrastructure from
290 // picking up sandbox related crashes.
291 // For now, in picking between two evils, we decided in favor of
292 // LOG(FATAL). In the long run, we probably want to rewrite this code
293 // to be async-signal safe.
294 LOG(FATAL) << msg;
295 } else
296 #endif
297 {
298 // If there is no logging infrastructure in place, we just write error
299 // messages to stderr.
300 // We also write to stderr, if we are called in a child process from
301 // supportsSeccompSandbox(). This makes sure we can actually do the
302 // correct logging from the parent process, which is more likely to
303 // have access to logging infrastructure.
304 if (HANDLE_EINTR(write(2, msg, strlen(msg)))) { }
305 if (HANDLE_EINTR(write(2, "\n", 1))) { }
306 }
307 }
308 for (;;) {
309 // exit_group() should exit our program. After all, it is defined as a
310 // function that doesn't return. But things can theoretically go wrong.
311 // Especially, since we are dealing with system call filters. Continuing
312 // execution would be very bad in most cases where die() gets called.
313 // So, if there is no way for us to ask for the program to exit, the next
314 // best thing we can do is to loop indefinitely. Maybe, somebody will
315 // notice and file a bug...
316 syscall(__NR_exit_group, 1);
317 _exit(1);
318 }
319 }
320
321 // Get a file descriptor pointing to "/proc", if currently available.
322 static int getProcFd() { return proc_fd_; }
323
324 private: 226 private:
227 friend class ErrorCode;
325 friend class Util; 228 friend class Util;
326 friend class Verifier; 229 friend class Verifier;
230
231
327 struct Range { 232 struct Range {
328 Range(uint32_t f, uint32_t t, const ErrorCode& e) : 233 Range(uint32_t f, uint32_t t, const ErrorCode& e) :
329 from(f), 234 from(f),
330 to(t), 235 to(t),
331 err(e) { 236 err(e) {
332 } 237 }
333 uint32_t from, to; 238 uint32_t from, to;
334 ErrorCode err; 239 ErrorCode err;
335 }; 240 };
336 struct FixUp { 241 struct FixUp {
337 FixUp(unsigned int a, bool j) : 242 FixUp(unsigned int a, bool j) :
338 jt(j), addr(a) { } 243 jt(j), addr(a) { }
339 bool jt:1; 244 bool jt:1;
340 unsigned addr:31; 245 unsigned addr:31;
341 }; 246 };
342 typedef std::vector<Range> Ranges; 247 typedef std::vector<Range> Ranges;
343 typedef std::map<uint32_t, std::vector<FixUp> > RetInsns; 248 typedef std::map<uint32_t, std::vector<FixUp> > RetInsns;
344 typedef std::vector<struct sock_filter> Program; 249 typedef std::vector<struct sock_filter> Program;
250 typedef std::map<uint32_t, ErrorCode> ErrMap;
345 typedef std::vector<ErrorCode> Traps; 251 typedef std::vector<ErrorCode> Traps;
346 typedef std::map<std::pair<TrapFnc, const void *>, int> TrapIds; 252 typedef std::map<std::pair<TrapFnc, const void *>, int> TrapIds;
347 253
348 static ErrorCode probeEvaluator(int signo) __attribute__((const)); 254 static ErrorCode probeEvaluator(int signo) __attribute__((const));
349 static void probeProcess(void); 255 static void probeProcess(void);
350 static ErrorCode allowAllEvaluator(int signo); 256 static ErrorCode allowAllEvaluator(int signo);
351 static void tryVsyscallProcess(void); 257 static void tryVsyscallProcess(void);
352 static bool kernelSupportSeccompBPF(int proc_fd); 258 static bool kernelSupportSeccompBPF(int proc_fd);
353 static bool RunFunctionInPolicy(void (*function)(), 259 static bool RunFunctionInPolicy(void (*function)(),
354 EvaluateSyscall syscallEvaluator, 260 EvaluateSyscall syscallEvaluator,
355 int proc_fd); 261 int proc_fd);
356 static bool isSingleThreaded(int proc_fd); 262 static bool isSingleThreaded(int proc_fd);
263 static bool isDenied(const ErrorCode& code);
357 static bool disableFilesystem(); 264 static bool disableFilesystem();
358 static void policySanityChecks(EvaluateSyscall syscallEvaluator, 265 static void policySanityChecks(EvaluateSyscall syscallEvaluator,
359 EvaluateArguments argumentEvaluator); 266 EvaluateArguments argumentEvaluator);
360 static void installFilter(); 267 static void installFilter();
361 static void findRanges(Ranges *ranges); 268 static void findRanges(Ranges *ranges);
362 static void emitJumpStatements(Program *program, RetInsns *rets, 269 static void emitJumpStatements(Program *program, RetInsns *rets,
363 Ranges::const_iterator start, 270 Ranges::const_iterator start,
364 Ranges::const_iterator stop); 271 Ranges::const_iterator stop);
365 static void emitReturnStatements(Program *prog, const RetInsns& rets); 272 static void emitReturnStatements(Program *prog, const RetInsns& rets);
366 static void sigSys(int nr, siginfo_t *info, void *void_context); 273 static void sigSys(int nr, siginfo_t *info, void *void_context);
367 static intptr_t bpfFailure(const struct arch_seccomp_data& data, void *aux); 274 static intptr_t bpfFailure(const struct arch_seccomp_data& data, void *aux);
368 static int getTrapId(TrapFnc fnc, const void *aux); 275 static int getTrapId(TrapFnc fnc, const void *aux);
369 276
277 // Get a file descriptor pointing to "/proc", if currently available.
278 static int proc_fd() { return proc_fd_; }
279
280 // Print an error message and terminate the program. Used for fatal errors.
281 static void die(const char *msg) __attribute__((noreturn)) {
282 if (msg) {
283 #ifndef SECCOMP_BPF_STANDALONE
284 if (!dryRun_) {
285 // LOG(FATAL) is not neccessarily async-signal safe. It would be
286 // better to always use the code for the SECCOMP_BPF_STANDALONE case.
287 // But that prevents the logging and reporting infrastructure from
288 // picking up sandbox related crashes.
289 // For now, in picking between two evils, we decided in favor of
290 // LOG(FATAL). In the long run, we probably want to rewrite this code
291 // to be async-signal safe.
292 LOG(FATAL) << msg;
293 } else
294 #endif
295 {
296 // If there is no logging infrastructure in place, we just write error
297 // messages to stderr.
298 // We also write to stderr, if we are called in a child process from
299 // supportsSeccompSandbox(). This makes sure we can actually do the
300 // correct logging from the parent process, which is more likely to
301 // have access to logging infrastructure.
302 if (HANDLE_EINTR(write(2, msg, strlen(msg)))) { }
303 if (HANDLE_EINTR(write(2, "\n", 1))) { }
304 }
305 }
306 for (;;) {
307 // exit_group() should exit our program. After all, it is defined as a
308 // function that doesn't return. But things can theoretically go wrong.
309 // Especially, since we are dealing with system call filters. Continuing
310 // execution would be very bad in most cases where die() gets called.
311 // So, if there is no way for us to ask for the program to exit, the next
312 // best thing we can do is to loop indefinitely. Maybe, somebody will
313 // notice and file a bug...
314 syscall(__NR_exit_group, 1);
315 _exit(1);
316 }
317 }
318
319
370 static bool dryRun_; 320 static bool dryRun_;
371 static SandboxStatus status_; 321 static SandboxStatus status_;
372 static int proc_fd_; 322 static int proc_fd_;
373 static Evaluators evaluators_; 323 static Evaluators evaluators_;
324 static ErrMap errMap_;
374 static Traps *traps_; 325 static Traps *traps_;
375 static TrapIds trapIds_; 326 static TrapIds trapIds_;
376 static ErrorCode *trapArray_; 327 static ErrorCode *trapArray_;
377 static size_t trapArraySize_; 328 static size_t trapArraySize_;
378 DISALLOW_IMPLICIT_CONSTRUCTORS(Sandbox); 329 DISALLOW_IMPLICIT_CONSTRUCTORS(Sandbox);
379 }; 330 };
380 331
381 } // namespace 332 } // namespace
382 333
383 #endif // SANDBOX_BPF_H__ 334 #endif // SANDBOX_BPF_H__
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698