seccomp-tools 1.4.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +105 -17
  3. data/ext/ptrace/ptrace.c +56 -4
  4. data/lib/seccomp-tools/asm/asm.rb +8 -6
  5. data/lib/seccomp-tools/asm/compiler.rb +130 -224
  6. data/lib/seccomp-tools/asm/sasm.tab.rb +780 -0
  7. data/lib/seccomp-tools/asm/sasm.y +175 -0
  8. data/lib/seccomp-tools/asm/scalar.rb +129 -0
  9. data/lib/seccomp-tools/asm/scanner.rb +163 -0
  10. data/lib/seccomp-tools/asm/statement.rb +32 -0
  11. data/lib/seccomp-tools/asm/token.rb +29 -0
  12. data/lib/seccomp-tools/bpf.rb +31 -7
  13. data/lib/seccomp-tools/cli/asm.rb +3 -3
  14. data/lib/seccomp-tools/cli/base.rb +4 -4
  15. data/lib/seccomp-tools/cli/disasm.rb +27 -3
  16. data/lib/seccomp-tools/cli/dump.rb +4 -2
  17. data/lib/seccomp-tools/cli/emu.rb +1 -4
  18. data/lib/seccomp-tools/const.rb +37 -3
  19. data/lib/seccomp-tools/consts/sys_nr/aarch64.rb +284 -0
  20. data/lib/seccomp-tools/consts/sys_nr/amd64.rb +5 -1
  21. data/lib/seccomp-tools/consts/sys_nr/i386.rb +14 -14
  22. data/lib/seccomp-tools/consts/sys_nr/s390x.rb +365 -0
  23. data/lib/seccomp-tools/disasm/context.rb +2 -2
  24. data/lib/seccomp-tools/disasm/disasm.rb +16 -9
  25. data/lib/seccomp-tools/dumper.rb +12 -3
  26. data/lib/seccomp-tools/emulator.rb +5 -9
  27. data/lib/seccomp-tools/error.rb +31 -0
  28. data/lib/seccomp-tools/instruction/alu.rb +1 -1
  29. data/lib/seccomp-tools/instruction/base.rb +1 -1
  30. data/lib/seccomp-tools/instruction/jmp.rb +28 -10
  31. data/lib/seccomp-tools/instruction/ld.rb +5 -3
  32. data/lib/seccomp-tools/syscall.rb +23 -13
  33. data/lib/seccomp-tools/templates/asm.s390x.asm +26 -0
  34. data/lib/seccomp-tools/util.rb +3 -1
  35. data/lib/seccomp-tools/version.rb +1 -1
  36. metadata +38 -9
  37. data/lib/seccomp-tools/asm/tokenizer.rb +0 -169
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2726a64dc089ec7c492cedad9a98d500c656dce84ca593a505d95a42cd07906c
4
- data.tar.gz: c8d3eec04aa38ead5bac1727bb4a1a29199283e648b902edb38df2a7fc4e539f
3
+ metadata.gz: 898cc2a23df6443f39054c4b9027a576fb929729f74fc804ae82ae3b11c6772e
4
+ data.tar.gz: 0e07d2d1914ac7185135425d0e34f0dcb1b6100e977176d8bd9ce23f95a3f287
5
5
  SHA512:
6
- metadata.gz: 2639ed20158afda2cc96dfeb16899f417d50180da548b4a45a0024c12119d0b9908649979fb9ab00287d41478f507eb6740ffda855aa238cd82755d774ca82de
7
- data.tar.gz: 6e6df86398ee4bde9ff9c54647dc5af95eb03e40001cf6117077afeecf20ecaed12f6e3f53b47bda1e2908094632c12e9d7faee3ee72c2422d7665016e583eff
6
+ metadata.gz: ec604fca33e16dd6ca77e923e34629338245828abdf3c97e9974d205a2306aa9ae0f3bc074b90e056790a8de86ed6484ab17ce190524b30394f2fda2b5dd9432
7
+ data.tar.gz: 399e5e77fa99de23f3ad5013c442fc29a800a261d04150ab0bd467744a9302601ca7c60e5570e4e65f423cf4c93e4eb4428ae3f33b97d6a64c223af13b342e47
data/README.md CHANGED
@@ -1,26 +1,26 @@
1
- [![Build Status](https://travis-ci.org/david942j/seccomp-tools.svg?branch=master)](https://travis-ci.org/david942j/seccomp-tools)
2
- [![Dependabot Status](https://api.dependabot.com/badges/status?host=github&repo=david942j/seccomp-tools)](https://dependabot.com)
1
+ [![Build Status](https://github.com/david942j/seccomp-tools/workflows/build/badge.svg)](https://github.com/david942j/seccomp-tools/actions)
3
2
  [![Code Climate](https://codeclimate.com/github/david942j/seccomp-tools/badges/gpa.svg)](https://codeclimate.com/github/david942j/seccomp-tools)
4
3
  [![Issue Count](https://codeclimate.com/github/david942j/seccomp-tools/badges/issue_count.svg)](https://codeclimate.com/github/david942j/seccomp-tools)
5
4
  [![Test Coverage](https://codeclimate.com/github/david942j/seccomp-tools/badges/coverage.svg)](https://codeclimate.com/github/david942j/seccomp-tools/coverage)
6
5
  [![Inline docs](https://inch-ci.org/github/david942j/seccomp-tools.svg?branch=master)](https://inch-ci.org/github/david942j/seccomp-tools)
6
+ [![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](https://www.rubydoc.info/github/david942j/seccomp-tools/)
7
7
  [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](http://choosealicense.com/licenses/mit/)
8
8
 
9
9
  # Seccomp Tools
10
10
  Provide powerful tools for seccomp analysis.
11
11
 
12
- This project is targeted to (but not limited to) analyze seccomp sandbox in CTF pwn challenges.
13
- Some features might be CTF-specific, but still useful for analyzing seccomp in real-case.
12
+ This project targets to (but is not limited to) analyze seccomp sandbox in CTF pwn challenges.
13
+ Some features might be CTF-specific, but also useful for analyzing seccomp of real cases.
14
14
 
15
15
  ## Features
16
- * Dump - Automatically dumps seccomp-bpf from execution file(s).
17
- * Disasm - Converts bpf to human readable format.
18
- - Simple decompile.
19
- - Display syscall names and arguments when possible.
16
+ * Dump - Automatically dumps seccomp BPF from execution file(s).
17
+ * Disasm - Converts seccomp BPF to a human readable format.
18
+ - With simple decompilation.
19
+ - With syscall names and arguments whenever possible.
20
20
  - Colorful!
21
- * Asm - Write seccomp rules is so easy!
21
+ * Asm - Makes writing seccomp rules similar to writing codes.
22
22
  * Emu - Emulates seccomp rules.
23
- * Supports multi-architectures.
23
+ * Supports multi-architecture.
24
24
 
25
25
  ## Installation
26
26
 
@@ -54,6 +54,7 @@ $ seccomp-tools --help
54
54
 
55
55
  $ seccomp-tools dump --help
56
56
  # dump - Automatically dump seccomp bpf from execution file(s).
57
+ # NOTE : This function is only available on Linux.
57
58
  #
58
59
  # Usage: seccomp-tools dump [exec] [options]
59
60
  # -c, --sh-exec <command> Executes the given command (via sh).
@@ -75,8 +76,8 @@ $ seccomp-tools dump --help
75
76
 
76
77
  ### dump
77
78
 
78
- Dumps the seccomp bpf from an execution file.
79
- This work is done by the `ptrace` syscall.
79
+ Dumps the seccomp BPF from an execution file.
80
+ This work is done by utilizing the `ptrace` syscall.
80
81
 
81
82
  NOTICE: beware of the execution file will be executed.
82
83
  ```bash
@@ -123,7 +124,7 @@ $ seccomp-tools dump spec/binary/twctf-2016-diary -f raw | xxd
123
124
 
124
125
  ### disasm
125
126
 
126
- Disassembles the seccomp from raw bpf.
127
+ Disassembles the seccomp from raw BPF.
127
128
  ```bash
128
129
  $ xxd spec/data/twctf-2016-diary.bpf | head -n 3
129
130
  # 00000000: 2000 0000 0000 0000 1500 0001 0200 0000 ...............
@@ -169,7 +170,7 @@ $ seccomp-tools asm
169
170
  # -f, --format FORMAT Output format. FORMAT can only be one of <inspect|raw|c_array|c_source|assembly>.
170
171
  # Default: inspect
171
172
  # -a, --arch ARCH Specify architecture.
172
- # Supported architectures are <amd64|i386>.
173
+ # Supported architectures are <aarch64|amd64|i386|s390x>.
173
174
  # Default: amd64
174
175
 
175
176
  # Input file for asm
@@ -258,6 +259,83 @@ $ seccomp-tools asm spec/data/libseccomp.asm -f raw | seccomp-tools disasm -
258
259
 
259
260
  ```
260
261
 
262
+ Since v1.6.0 [not released yet], `asm` has switched to using a yacc-based syntax parser, hence supports more flexible and intuitive syntax!
263
+
264
+ ```bash
265
+ $ cat spec/data/example.asm
266
+ # # An example of supported assembly syntax
267
+ # if (A == X)
268
+ # goto next # 'next' is a reserved label, means the next statement ("A = args[0]" in this example)
269
+ # else
270
+ # goto err_label # custom defined label
271
+ # A = args[0]
272
+ # if (
273
+ # A # put a comment here is also valid
274
+ # == 0x123
275
+ # ) goto disallow
276
+ # if (! (A & 0x1337)) # support bang in if-conditions
277
+ # goto 0 # equivalent to 'goto next'
278
+ # else goto 2 # goto $ + 2, 'mem[0] = A' in this example
279
+ # A = sys_number
280
+ # A = instruction_pointer >> 32
281
+ # mem[0] = A
282
+ # A = data[4] # equivalent to 'A = arch'
283
+ # err_label: return ERRNO(1337)
284
+ # disallow:
285
+ # return KILL
286
+
287
+ $ seccomp-tools asm spec/data/example.asm -f raw | seccomp-tools disasm -
288
+ # line CODE JT JF K
289
+ # =================================
290
+ # 0000: 0x1d 0x00 0x07 0x00000000 if (A != X) goto 0008
291
+ # 0001: 0x20 0x00 0x00 0x00000010 A = args[0]
292
+ # 0002: 0x15 0x06 0x00 0x00000123 if (A == 0x123) goto 0009
293
+ # 0003: 0x45 0x02 0x00 0x00001337 if (A & 0x1337) goto 0006
294
+ # 0004: 0x20 0x00 0x00 0x00000000 A = sys_number
295
+ # 0005: 0x20 0x00 0x00 0x0000000c A = instruction_pointer >> 32
296
+ # 0006: 0x02 0x00 0x00 0x00000000 mem[0] = A
297
+ # 0007: 0x20 0x00 0x00 0x00000004 A = arch
298
+ # 0008: 0x06 0x00 0x00 0x00050539 return ERRNO(1337)
299
+ # 0009: 0x06 0x00 0x00 0x00000000 return KILL
300
+
301
+ ```
302
+
303
+ The output of `seccomp-tools disasm <file> --asm-able` is a valid input of `asm`:
304
+ ```bash
305
+ $ seccomp-tools disasm spec/data/x32.bpf --asm-able
306
+ # 0000: A = arch
307
+ # 0001: if (A != ARCH_X86_64) goto 0011
308
+ # 0002: A = sys_number
309
+ # 0003: if (A < 0x40000000) goto 0011
310
+ # 0004: if (A == x32_read) goto 0011
311
+ # 0005: if (A == x32_write) goto 0011
312
+ # 0006: if (A == x32_iopl) goto 0011
313
+ # 0007: if (A != x32_mmap) goto 0011
314
+ # 0008: A = args[0]
315
+ # 0009: if (A == 0x0) goto 0011
316
+ # 0010: return ERRNO(5)
317
+ # 0011: return ALLOW
318
+
319
+
320
+ # disasm then asm then disasm!
321
+ $ seccomp-tools disasm spec/data/x32.bpf --asm-able | seccomp-tools asm - -f raw | seccomp-tools disasm -
322
+ # line CODE JT JF K
323
+ # =================================
324
+ # 0000: 0x20 0x00 0x00 0x00000004 A = arch
325
+ # 0001: 0x15 0x00 0x09 0xc000003e if (A != ARCH_X86_64) goto 0011
326
+ # 0002: 0x20 0x00 0x00 0x00000000 A = sys_number
327
+ # 0003: 0x35 0x00 0x07 0x40000000 if (A < 0x40000000) goto 0011
328
+ # 0004: 0x15 0x06 0x00 0x40000000 if (A == x32_read) goto 0011
329
+ # 0005: 0x15 0x05 0x00 0x40000001 if (A == x32_write) goto 0011
330
+ # 0006: 0x15 0x04 0x00 0x400000ac if (A == x32_iopl) goto 0011
331
+ # 0007: 0x15 0x00 0x03 0x40000009 if (A != x32_mmap) goto 0011
332
+ # 0008: 0x20 0x00 0x00 0x00000010 A = addr # x32_mmap(addr, len, prot, flags, fd, pgoff)
333
+ # 0009: 0x15 0x01 0x00 0x00000000 if (A == 0x0) goto 0011
334
+ # 0010: 0x06 0x00 0x00 0x00050005 return ERRNO(5)
335
+ # 0011: 0x06 0x00 0x00 0x7fff0000 return ALLOW
336
+
337
+ ```
338
+
261
339
  ### Emu
262
340
 
263
341
  Emulates seccomp given `sys_nr`, `arg0`, `arg1`, etc.
@@ -267,7 +345,7 @@ $ seccomp-tools emu --help
267
345
  #
268
346
  # Usage: seccomp-tools emu [options] BPF_FILE [sys_nr [arg0 [arg1 ... arg5]]]
269
347
  # -a, --arch ARCH Specify architecture.
270
- # Supported architectures are <amd64|i386>.
348
+ # Supported architectures are <aarch64|amd64|i386|s390x>.
271
349
  # Default: amd64
272
350
  # -q, --[no-]quiet Run quietly, only show emulation result.
273
351
 
@@ -300,6 +378,16 @@ $ seccomp-tools emu spec/data/libseccomp.bpf write 0x3
300
378
 
301
379
  ![emu](https://github.com/david942j/seccomp-tools/blob/master/examples/emu-amigo.png?raw=true)
302
380
 
381
+ ## Supported Architectures
382
+
383
+ - [x] x86_64
384
+ - [x] x32
385
+ - [x] x86
386
+ - [x] arm64 (@saagarjha)
387
+ - [x] s390x (@iii-i)
388
+
389
+ Pull Requests of adding more architectures support are welcome!
390
+
303
391
  ## Development
304
392
 
305
393
  I recommend to use [rbenv](https://github.com/rbenv/rbenv) for your Ruby environment.
@@ -319,6 +407,6 @@ I recommend to use [rbenv](https://github.com/rbenv/rbenv) for your Ruby environ
319
407
 
320
408
  ## I Need You
321
409
 
322
- Any suggestion or feature request is welcome!
323
- Feel free to file an issue or send a pull request.
410
+ Any suggestions or feature requests are welcome!
411
+ Feel free to file issues or send pull requests.
324
412
  And, if you like this work, I'll be happy to be [starred](https://github.com/david942j/seccomp-tools/stargazers) :grimacing:
data/ext/ptrace/ptrace.c CHANGED
@@ -1,7 +1,15 @@
1
+ // ptrace is only available on Linux, therefore let this file be an empty
2
+ // object when installing on other platforms.
3
+ #if __linux__
4
+
5
+ #include <assert.h>
1
6
  #include <errno.h>
7
+ #include <linux/elf.h>
2
8
  #include <linux/filter.h>
9
+ #include <stdint.h>
3
10
  #include <sys/ptrace.h>
4
11
  #include <sys/signal.h>
12
+ #include <sys/uio.h>
5
13
  #include <sys/wait.h>
6
14
 
7
15
  #include "ruby.h"
@@ -19,10 +27,53 @@ ptrace_peekdata(VALUE _mod, VALUE pid, VALUE addr, VALUE _data) {
19
27
  return LONG2NUM(val);
20
28
  }
21
29
 
30
+ // aarch64 doesn't support PTRACE_PEEKUSER, but it does support
31
+ // PTRACE_GETREGSET which is fairly similar. Since i386 and x86_64 support it
32
+ // too, just use that unconditionally to present the same API for the registers
33
+ // we care about.
22
34
  static VALUE
23
- ptrace_peekuser(VALUE _mod, VALUE pid, VALUE off, VALUE _data) {
24
- long val = ptrace(PTRACE_PEEKUSER, NUM2LONG(pid), NUM2LONG(off), NULL);
25
- return LONG2NUM(val);
35
+ ptrace_peekuser(VALUE _mod, VALUE pid, VALUE off, VALUE _data, VALUE bits) {
36
+ size_t offset = NUM2LONG(off);
37
+ // Unless your registers fill an entire page, an offset greater than this is
38
+ // probably wrong.
39
+ if (offset >= 4096) {
40
+ return LONG2NUM(-1);
41
+ }
42
+ size_t width = NUM2LONG(bits);
43
+ if (width != 32 && width != 64) {
44
+ return LONG2NUM(-1);
45
+ }
46
+ width /= 8;
47
+ union {
48
+ uint32_t val32;
49
+ uint64_t val64;
50
+ } val;
51
+ // Dynamically allocate a buffer to store registers-well, at least enough
52
+ // registers to reach the offset we want. Normally we'd want to use
53
+ // user_pt_regs or similar, but it's difficult to find it available in the
54
+ // the same header across different versions of Linux or libcs, or even with
55
+ // the same *name*, so this is the compromise.
56
+ size_t size = offset + width;
57
+ char *regs = malloc(size);
58
+ if (!regs) {
59
+ return LONG2NUM(-1);
60
+ }
61
+ struct iovec vec = { regs, size };
62
+ if (ptrace(PTRACE_GETREGSET, NUM2LONG(pid), NT_PRSTATUS, &vec) != -1 && vec.iov_len >= size) {
63
+ memcpy(&val, regs + offset, width);
64
+ } else {
65
+ free(regs);
66
+ return LONG2NUM(-1);
67
+ }
68
+ free(regs);
69
+ if (width == sizeof(val.val32)) {
70
+ return LONG2NUM(val.val32);
71
+ } else if (width == sizeof(val.val64)) {
72
+ return LONG2NUM(val.val64);
73
+ } else {
74
+ assert(!"Unreachable");
75
+ return LONG2NUM(-1);
76
+ }
26
77
  }
27
78
 
28
79
  static VALUE
@@ -107,7 +158,7 @@ void Init_ptrace(void) {
107
158
  /* get data */
108
159
  rb_define_module_function(mPtrace, "peekdata", ptrace_peekdata, 3);
109
160
  /* get registers */
110
- rb_define_module_function(mPtrace, "peekuser", ptrace_peekuser, 3);
161
+ rb_define_module_function(mPtrace, "peekuser", ptrace_peekuser, 4);
111
162
  /* set ptrace options */
112
163
  rb_define_module_function(mPtrace, "setoptions", ptrace_setoptions, 3);
113
164
  /* wait for syscall */
@@ -124,3 +175,4 @@ void Init_ptrace(void) {
124
175
  rb_define_module_function(mPtrace, "detach", ptrace_detach, 1);
125
176
  }
126
177
 
178
+ #endif /* __linux__ */
@@ -10,16 +10,18 @@ module SeccompTools
10
10
 
11
11
  # Assembler of seccomp bpf.
12
12
  # @param [String] str
13
- # @param [:amd64, :i386] arch
13
+ # @param [String] filename
14
+ # Only used for error messages.
15
+ # @param [Symbol?] arch
14
16
  # @return [String]
15
- # Raw bpf bytes.
17
+ # Raw BPF bytes.
16
18
  # @example
17
19
  # SeccompTools::Asm.asm(<<-EOS)
18
20
  # # lines start with '#' are comments
19
21
  # A = sys_number # here's a comment, too
20
22
  # A >= 0x40000000 ? dead : next # 'next' is a keyword, denote the next instruction
21
23
  # A == read ? ok : next # custom defined label 'dead' and 'ok'
22
- # A == 1 ? ok : next # SYS_write = 1 in amd64
24
+ # A == 1 ? ok : next # SYS_write = 1 on amd64
23
25
  # return ERRNO(1)
24
26
  # dead:
25
27
  # return KILL
@@ -27,10 +29,10 @@ module SeccompTools
27
29
  # return ALLOW
28
30
  # EOS
29
31
  # #=> <raw binary bytes>
30
- def asm(str, arch: nil)
32
+ def asm(str, filename: '-', arch: nil)
33
+ filename = nil if filename == '-'
31
34
  arch = Util.system_arch if arch.nil?
32
- compiler = Compiler.new(arch)
33
- str.lines.each { |l| compiler.process(l) }
35
+ compiler = Compiler.new(str, filename, arch)
34
36
  compiler.compile!.map(&:asm).join
35
37
  end
36
38
  end