seccomp-tools 1.4.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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