seccomp-tools 1.2.0 → 1.3.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 (40) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +84 -17
  3. data/bin/seccomp-tools +1 -0
  4. data/ext/ptrace/ptrace.c +8 -1
  5. data/lib/seccomp-tools.rb +2 -0
  6. data/lib/seccomp-tools/asm/asm.rb +4 -1
  7. data/lib/seccomp-tools/asm/compiler.rb +61 -10
  8. data/lib/seccomp-tools/asm/tokenizer.rb +15 -3
  9. data/lib/seccomp-tools/bpf.rb +2 -0
  10. data/lib/seccomp-tools/cli/asm.rb +14 -4
  11. data/lib/seccomp-tools/cli/base.rb +5 -0
  12. data/lib/seccomp-tools/cli/cli.rb +6 -3
  13. data/lib/seccomp-tools/cli/disasm.rb +5 -1
  14. data/lib/seccomp-tools/cli/dump.rb +4 -1
  15. data/lib/seccomp-tools/cli/emu.rb +15 -2
  16. data/lib/seccomp-tools/const.rb +25 -19
  17. data/lib/seccomp-tools/consts/sys_arg.rb +432 -0
  18. data/lib/seccomp-tools/consts/{amd64.rb → sys_nr/amd64.rb} +4 -2
  19. data/lib/seccomp-tools/consts/{i386.rb → sys_nr/i386.rb} +5 -2
  20. data/lib/seccomp-tools/disasm/context.rb +125 -34
  21. data/lib/seccomp-tools/disasm/disasm.rb +4 -2
  22. data/lib/seccomp-tools/dumper.rb +4 -0
  23. data/lib/seccomp-tools/emulator.rb +10 -0
  24. data/lib/seccomp-tools/instruction/alu.rb +6 -1
  25. data/lib/seccomp-tools/instruction/base.rb +4 -2
  26. data/lib/seccomp-tools/instruction/instruction.rb +2 -0
  27. data/lib/seccomp-tools/instruction/jmp.rb +12 -2
  28. data/lib/seccomp-tools/instruction/ld.rb +27 -11
  29. data/lib/seccomp-tools/instruction/ldx.rb +2 -0
  30. data/lib/seccomp-tools/instruction/misc.rb +2 -0
  31. data/lib/seccomp-tools/instruction/ret.rb +3 -0
  32. data/lib/seccomp-tools/instruction/st.rb +3 -1
  33. data/lib/seccomp-tools/instruction/stx.rb +2 -0
  34. data/lib/seccomp-tools/syscall.rb +5 -1
  35. data/lib/seccomp-tools/templates/asm.amd64.asm +26 -0
  36. data/lib/seccomp-tools/templates/asm.c +17 -0
  37. data/lib/seccomp-tools/templates/asm.i386.asm +33 -0
  38. data/lib/seccomp-tools/util.rb +16 -1
  39. data/lib/seccomp-tools/version.rb +3 -1
  40. metadata +18 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 5c6965417440352f339d587caf0ee612604d7d0e
4
- data.tar.gz: 294d2c627f26b1bf03581675d35412d13296f27b
2
+ SHA256:
3
+ metadata.gz: 5d0a3997904616df1a40c2a8131ec70fb83511477e155de8e6d0de9c3a445cf9
4
+ data.tar.gz: eb7970f0de4a89ac13e41626950dbee92ca141b5bc4342e804a799076a61ac53
5
5
  SHA512:
6
- metadata.gz: cfc63e0881c0cb4c7852051a4a0b98f93935523674582a75d5fb4f904cbd81673cb86d0be9f31cb76ce2515fa29a42f53a8e81321f3063d0bddce3257cac9b95
7
- data.tar.gz: '090dd0f577b52bc5494121420d8600b12018f857bcccd05be15849fd774de4e02abfdc1c36610d8908910f79cfe4153b2f0dd613d015e5aaa86e2f984844ab1f'
6
+ metadata.gz: 5ce8984f8b3ada51158a181de2ab5e12d291ff12cf3515467763c77ab58870416c4927fce3e362c3775d3749e8a5939d54971681ec85da96adfb38210a51ca90
7
+ data.tar.gz: 2611058a57579fb1806f9bcc6ca05d203f36fa34f5d6aa0434b71b0dbc815f14b513b9907d60a4cbc59a8e648c8880e39e5339a1d85113a98cd147728223e65e
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
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)
2
3
  [![Code Climate](https://codeclimate.com/github/david942j/seccomp-tools/badges/gpa.svg)](https://codeclimate.com/github/david942j/seccomp-tools)
3
4
  [![Issue Count](https://codeclimate.com/github/david942j/seccomp-tools/badges/issue_count.svg)](https://codeclimate.com/github/david942j/seccomp-tools)
4
5
  [![Test Coverage](https://codeclimate.com/github/david942j/seccomp-tools/badges/coverage.svg)](https://codeclimate.com/github/david942j/seccomp-tools/coverage)
@@ -12,15 +13,14 @@ This project is targeted to (but not limited to) analyze seccomp sandbox in CTF
12
13
  Some features might be CTF-specific, but still useful for analyzing seccomp in real-case.
13
14
 
14
15
  ## Features
15
- * Dump - Automatically dump seccomp-bpf from execution file(s).
16
- * Disasm - Convert bpf to human readable format.
16
+ * Dump - Automatically dumps seccomp-bpf from execution file(s).
17
+ * Disasm - Converts bpf to human readable format.
17
18
  - Simple decompile.
18
- - Show syscall names.
19
+ - Display syscall names and arguments when possible.
19
20
  - Colorful!
20
21
  * Asm - Write seccomp rules is so easy!
21
- * Emu - Emulate seccomp rules.
22
- * (TODO) Solve constraints for executing syscalls (e.g. `execve/open/read/write`).
23
- * Support multi-architectures.
22
+ * Emu - Emulates seccomp rules.
23
+ * Supports multi-architectures.
24
24
 
25
25
  ## Installation
26
26
 
@@ -29,6 +29,12 @@ Available on RubyGems.org!
29
29
  $ gem install seccomp-tools
30
30
  ```
31
31
 
32
+ If you failed when compiling, try:
33
+ ```
34
+ sudo apt install gcc ruby-dev
35
+ ```
36
+ and install seccomp-tools again.
37
+
32
38
  ## Command Line Interface
33
39
 
34
40
  ### seccomp-tools
@@ -67,13 +73,13 @@ $ seccomp-tools dump --help
67
73
 
68
74
  ### dump
69
75
 
70
- Dump the seccomp bpf from an execution file.
76
+ Dumps the seccomp bpf from an execution file.
71
77
  This work is done by the `ptrace` syscall.
72
78
 
73
79
  NOTICE: beware of the execution file will be executed.
74
80
  ```bash
75
81
  $ file spec/binary/twctf-2016-diary
76
- # spec/binary/twctf-2016-diary: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=3648e29153ac0259a0b7c3e25537a5334f50107f, not stripped
82
+ # spec/binary/twctf-2016-diary: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 2.6.24, BuildID[sha1]=3648e29153ac0259a0b7c3e25537a5334f50107f, not stripped
77
83
 
78
84
  $ seccomp-tools dump spec/binary/twctf-2016-diary
79
85
  # line CODE JT JF K
@@ -115,7 +121,7 @@ $ seccomp-tools dump spec/binary/twctf-2016-diary -f raw | xxd
115
121
 
116
122
  ### disasm
117
123
 
118
- Disassemble the seccomp from raw bpf.
124
+ Disassembles the seccomp from raw bpf.
119
125
  ```bash
120
126
  $ xxd spec/data/twctf-2016-diary.bpf | head -n 3
121
127
  # 00000000: 2000 0000 0000 0000 1500 0001 0200 0000 ...............
@@ -148,17 +154,17 @@ $ seccomp-tools disasm spec/data/twctf-2016-diary.bpf
148
154
 
149
155
  ### asm
150
156
 
151
- Assemble the seccomp rules into raw bytes.
152
- Very useful when want to write custom seccomp rules.
157
+ Assembles the seccomp rules into raw bytes.
158
+ It's very useful when one wants to write custom seccomp rules.
153
159
 
154
- Supports labels for jumping and use syscall names directly. See example below.
160
+ Supports labels for jumping and uses syscall names directly. See examples below.
155
161
  ```bash
156
162
  $ seccomp-tools asm
157
163
  # asm - Seccomp bpf assembler.
158
164
  #
159
165
  # Usage: seccomp-tools asm IN_FILE [options]
160
166
  # -o, --output FILE Output result into FILE instead of stdout.
161
- # -f, --format FORMAT Output format. FORMAT can only be one of <inspect|raw|carray>.
167
+ # -f, --format FORMAT Output format. FORMAT can only be one of <inspect|raw|c_array|c_source|assembly>.
162
168
  # Default: inspect
163
169
  # -a, --arch ARCH Specify architecture.
164
170
  # Supported architectures are <amd64|i386>.
@@ -183,8 +189,52 @@ $ cat spec/data/libseccomp.asm
183
189
  $ seccomp-tools asm spec/data/libseccomp.asm
184
190
  # " \x00\x00\x00\x04\x00\x00\x00\x15\x00\x00\b>\x00\x00\xC0 \x00\x00\x00\x00\x00\x00\x005\x00\x06\x00\x00\x00\x00@\x15\x00\x04\x00\x01\x00\x00\x00\x15\x00\x03\x00\x03\x00\x00\x00\x15\x00\x02\x00 \x00\x00\x00\x15\x00\x01\x00<\x00\x00\x00\x06\x00\x00\x00\x05\x00\x05\x00\x06\x00\x00\x00\x00\x00\xFF\x7F\x06\x00\x00\x00\x00\x00\x00\x00"
185
191
 
186
- $ seccomp-tools asm spec/data/libseccomp.asm -f carray
187
- # unsigned char bpf[] = {32,0,0,0,4,0,0,0,21,0,0,8,62,0,0,192,32,0,0,0,0,0,0,0,53,0,6,0,0,0,0,64,21,0,4,0,1,0,0,0,21,0,3,0,3,0,0,0,21,0,2,0,32,0,0,0,21,0,1,0,60,0,0,0,6,0,0,0,5,0,5,0,6,0,0,0,0,0,255,127,6,0,0,0,0,0,0,0};
192
+ $ seccomp-tools asm spec/data/libseccomp.asm -f c_source
193
+ # #include <linux/seccomp.h>
194
+ # #include <stdio.h>
195
+ # #include <stdlib.h>
196
+ # #include <sys/prctl.h>
197
+ #
198
+ # static void install_seccomp() {
199
+ # static unsigned char filter[] = {32,0,0,0,4,0,0,0,21,0,0,8,62,0,0,192,32,0,0,0,0,0,0,0,53,0,6,0,0,0,0,64,21,0,4,0,1,0,0,0,21,0,3,0,3,0,0,0,21,0,2,0,32,0,0,0,21,0,1,0,60,0,0,0,6,0,0,0,5,0,5,0,6,0,0,0,0,0,255,127,6,0,0,0,0,0,0,0};
200
+ # struct prog {
201
+ # unsigned short len;
202
+ # unsigned char *filter;
203
+ # } rule = {
204
+ # .len = sizeof(filter) >> 3,
205
+ # .filter = filter
206
+ # };
207
+ # if(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) { perror("prctl(PR_SET_NO_NEW_PRIVS)"); exit(2); }
208
+ # if(prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &rule) < 0) { perror("prctl(PR_SET_SECCOMP)"); exit(2); }
209
+ # }
210
+
211
+ $ seccomp-tools asm spec/data/libseccomp.asm -f assembly
212
+ # install_seccomp:
213
+ # push rbp
214
+ # mov rbp, rsp
215
+ # push 38
216
+ # pop rdi
217
+ # push 0x1
218
+ # pop rsi
219
+ # xor eax, eax
220
+ # mov al, 0x9d
221
+ # syscall
222
+ # push 22
223
+ # pop rdi
224
+ # lea rdx, [rip + _filter]
225
+ # push rdx /* .filter */
226
+ # push _filter_end - _filter >> 3 /* .len */
227
+ # mov rdx, rsp
228
+ # push 0x2
229
+ # pop rsi
230
+ # xor eax, eax
231
+ # mov al, 0x9d
232
+ # syscall
233
+ # leave
234
+ # ret
235
+ # _filter:
236
+ # .ascii "\040\000\000\000\004\000\000\000\025\000\000\010\076\000\000\300\040\000\000\000\000\000\000\000\065\000\006\000\000\000\000\100\025\000\004\000\001\000\000\000\025\000\003\000\003\000\000\000\025\000\002\000\040\000\000\000\025\000\001\000\074\000\000\000\006\000\000\000\005\000\005\000\006\000\000\000\000\000\377\177\006\000\000\000\000\000\000\000"
237
+ # _filter_end:
188
238
 
189
239
 
190
240
  # let's asm then disasm!
@@ -207,7 +257,7 @@ $ seccomp-tools asm spec/data/libseccomp.asm -f raw | seccomp-tools disasm -
207
257
 
208
258
  ### Emu
209
259
 
210
- Emulate seccomp given `sys_nr`, `arg0`, `arg1`, etc.
260
+ Emulates seccomp given `sys_nr`, `arg0`, `arg1`, etc.
211
261
  ```bash
212
262
  $ seccomp-tools emu --help
213
263
  # emu - Emulate seccomp rules.
@@ -217,7 +267,7 @@ $ seccomp-tools emu --help
217
267
  # Supported architectures are <amd64|i386>.
218
268
  # -q, --[no-]quiet Run quietly, only show emulation result.
219
269
 
220
- $ seccomp-tools emu spec/data/libseccomp.bpf 0x3
270
+ $ seccomp-tools emu spec/data/libseccomp.bpf write 0x3
221
271
  # line CODE JT JF K
222
272
  # =================================
223
273
  # 0000: 0x20 0x00 0x00 0x00000004 A = arch
@@ -246,6 +296,23 @@ $ seccomp-tools emu spec/data/libseccomp.bpf 0x3
246
296
 
247
297
  ![emu](https://github.com/david942j/seccomp-tools/blob/master/examples/emu-amigo.png?raw=true)
248
298
 
299
+ ## Development
300
+
301
+ I recommend to use [rbenv](https://github.com/rbenv/rbenv) for your Ruby environment.
302
+
303
+ ### Setup
304
+
305
+ - Install bundler
306
+ - `$ gem install bundler`
307
+ - Clone the source
308
+ - `$ git clone https://github.com/david942j/seccomp-tools && cd seccomp-tools`
309
+ - Install dependencies
310
+ - `$ bundle install`
311
+
312
+ ### Run tests
313
+
314
+ `$ bundle exec rake`
315
+
249
316
  ## I Need You
250
317
 
251
318
  Any suggestion or feature request is welcome!
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'seccomp-tools/cli/cli'
4
5
 
@@ -53,6 +53,7 @@ ptrace_traceme_and_stop(VALUE mod) {
53
53
 
54
54
  void Init_ptrace(void) {
55
55
  VALUE mSeccompTools = rb_define_module("SeccompTools");
56
+ /* The module to wrap ptrace syscall */
56
57
  VALUE mPtrace = rb_define_module_under(mSeccompTools, "Ptrace");
57
58
 
58
59
  /* consts */
@@ -64,13 +65,19 @@ void Init_ptrace(void) {
64
65
  rb_define_const(mPtrace, "O_TRACESYSGOOD", UINT2NUM(PTRACE_O_TRACESYSGOOD));
65
66
  rb_define_const(mPtrace, "O_TRACEVFORK", UINT2NUM(PTRACE_O_TRACEVFORK));
66
67
 
67
- /* ptrace wrapper */
68
+ /* geteventmsg */
68
69
  rb_define_module_function(mPtrace, "geteventmsg", ptrace_geteventmsg, 1);
70
+ /* get data */
69
71
  rb_define_module_function(mPtrace, "peekdata", ptrace_peekdata, 3);
72
+ /* get registers */
70
73
  rb_define_module_function(mPtrace, "peekuser", ptrace_peekuser, 3);
74
+ /* set ptrace options */
71
75
  rb_define_module_function(mPtrace, "setoptions", ptrace_setoptions, 3);
76
+ /* wait for syscall */
72
77
  rb_define_module_function(mPtrace, "syscall", ptrace_syscall, 3);
78
+ /* wait for its parent to attach */
73
79
  rb_define_module_function(mPtrace, "traceme", ptrace_traceme, 0);
80
+ /* stop itself before parent attaching */
74
81
  rb_define_module_function(mPtrace, "traceme_and_stop", ptrace_traceme_and_stop, 0);
75
82
  }
76
83
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # @author david942j
2
4
 
3
5
  # Main module.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'seccomp-tools/asm/compiler'
2
4
  require 'seccomp-tools/util'
3
5
 
@@ -8,10 +10,11 @@ module SeccompTools
8
10
 
9
11
  # Assembler of seccomp bpf.
10
12
  # @param [String] str
13
+ # @param [:amd64, :i386] arch
11
14
  # @return [String]
12
15
  # Raw bpf bytes.
13
16
  # @example
14
- # asm(<<EOS)
17
+ # SeccompTools::Asm.asm(<<-EOS)
15
18
  # # lines start with '#' are comments
16
19
  # A = sys_number # here's a comment, too
17
20
  # A >= 0x40000000 ? dead : next # 'next' is a keyword, denote the next instruction
@@ -1,15 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'seccomp-tools/asm/tokenizer'
2
4
  require 'seccomp-tools/bpf'
3
5
  require 'seccomp-tools/const'
4
6
 
5
7
  module SeccompTools
6
8
  module Asm
9
+ # @private
10
+ #
7
11
  # Compile seccomp rules.
8
12
  class Compiler
13
+ # Instantiate a {Compiler} object.
14
+ #
15
+ # @param [Symbol] arch
16
+ # Architecture.
9
17
  def initialize(arch)
10
18
  @arch = arch
11
19
  @insts = []
12
20
  @labels = {}
21
+ @insts_linenum = {}
13
22
  @input = []
14
23
  end
15
24
 
@@ -24,6 +33,7 @@ module SeccompTools
24
33
  line = remove_comment(line)
25
34
  @token = Tokenizer.new(line)
26
35
  return if line.empty?
36
+
27
37
  begin
28
38
  res = case line
29
39
  when /\?/ then cmp
@@ -32,6 +42,7 @@ module SeccompTools
32
42
  when /^(A|X)\s*=[^=]/ then assign
33
43
  when /^mem\[\d+\]\s*=\s*(A|X)/ then store
34
44
  when /^A\s*.{1,2}=/ then alu
45
+ when /^(goto|jmp|jump)/ then jmp_abs
35
46
  end
36
47
  rescue ArgumentError => e
37
48
  invalid(@input.size - 1, e.message)
@@ -41,10 +52,16 @@ module SeccompTools
41
52
  @labels[res.last] = @insts.size
42
53
  else
43
54
  @insts << res
55
+ @insts_linenum[@insts.size - 1] = @input.size - 1
44
56
  end
45
57
  end
46
58
 
59
+ # Compiles the processed instructions.
60
+ #
47
61
  # @return [Array<SeccompTools::BPF>]
62
+ # Returns the compiled {BPF} array.
63
+ # @raise [ArgumentError]
64
+ # Raises the error found during compilation.
48
65
  def compile!
49
66
  @insts.map.with_index do |inst, idx|
50
67
  @line = idx
@@ -53,17 +70,22 @@ module SeccompTools
53
70
  when :alu then compile_alu(inst[1], inst[2])
54
71
  when :ret then compile_ret(inst[1])
55
72
  when :cmp then compile_cmp(inst[1], inst[2], inst[3], inst[4])
73
+ when :jmp_abs then compile_jmp_abs(inst[1])
56
74
  end
57
75
  end
58
76
  rescue ArgumentError => e
59
- invalid(@line, e.message)
77
+ invalid(@insts_linenum[@line], e.message)
60
78
  end
61
79
 
62
80
  private
63
81
 
82
+ # Emits a raw BPF object.
83
+ #
84
+ # @return [BPF]
85
+ # Returns the emitted {BPF} object.
64
86
  def emit(*args, k: 0, jt: 0, jf: 0)
65
87
  code = 0
66
- # bad idea, while keys are not duplicated so this is ok.
88
+ # bad idea, but keys are not duplicated so this is ok.
67
89
  args.each do |a|
68
90
  code |= Const::BPF::COMMAND.fetch(a, 0)
69
91
  code |= Const::BPF::JMP.fetch(a, 0)
@@ -76,24 +98,27 @@ module SeccompTools
76
98
  end
77
99
 
78
100
  # A = X / X = A
79
- # <A|X> = mem[i]
101
+ # mem[i] = <A|X>
80
102
  # <A|X> = 123|sys_const
81
- # A = args[i]|sys_number|arch
103
+ # A = len
104
+ # <A|X> = mem[i]
105
+ # A = args_h[i]|args[i]|sys_number|arch
82
106
  # A = data[4 * i]
83
- # mem[i] = <A|X>
84
107
  def compile_assign(dst, src)
85
108
  # misc txa / tax
86
109
  return compile_assign_misc(dst, src) if (dst == :a && src == :x) || (dst == :x && src == :a)
87
110
  # case of st / stx
88
111
  return emit(src == :x ? :stx : :st, k: dst.last) if dst.is_a?(Array) && dst.first == :mem
112
+
89
113
  src = evaluate(src)
90
114
  ld = dst == :x ? :ldx : :ld
91
115
  # <A|X> = <immi>
92
116
  return emit(ld, :imm, k: src) if src.is_a?(Integer)
93
- # now src must be in form [:mem/:data, num]
94
- return emit(ld, :mem, k: src.last) if src.first == :mem
117
+ # now src must be in form [:len/:mem/:data, num]
118
+ return emit(ld, src.first, k: src.last) if src.first == :mem || src.first == :len
95
119
  # check if num is multiple of 4
96
- raise ArgumentError, 'Index of data[] must be multiplication of 4' if src.last % 4 != 0
120
+ raise ArgumentError, 'Index of data[] must be a multiple of 4' if src.last % 4 != 0
121
+
97
122
  emit(ld, :abs, k: src.last)
98
123
  end
99
124
 
@@ -116,6 +141,12 @@ module SeccompTools
116
141
  emit(:ret, src, k: val)
117
142
  end
118
143
 
144
+ def compile_jmp_abs(target)
145
+ targ = label_offset(target)
146
+ emit(:jmp, :ja, k: targ)
147
+ end
148
+
149
+ # Compiles comparsion.
119
150
  def compile_cmp(op, val, jt, jf)
120
151
  jt = label_offset(jt)
121
152
  jf = label_offset(jf)
@@ -129,30 +160,48 @@ module SeccompTools
129
160
  return label if label.is_a?(Integer)
130
161
  return 0 if label == 'next'
131
162
  raise ArgumentError, "Undefined label #{label.inspect}" if @labels[label].nil?
163
+ raise ArgumentError, "Does not support backward jumping to #{label.inspect}" if @labels[label] < @line
164
+
132
165
  @labels[label] - @line - 1
133
166
  end
134
167
 
135
168
  def evaluate(val)
136
169
  return val if val.is_a?(Integer) || val == :x || val == :a
170
+
137
171
  # keywords
138
172
  val = case val
139
173
  when 'sys_number' then [:data, 0]
140
174
  when 'arch' then [:data, 4]
175
+ when 'len' then [:len, 0]
141
176
  else val
142
177
  end
143
178
  return eval_constants(val) if val.is_a?(String)
144
- # remains are [:mem/:data/:args, <num>]
179
+
180
+ # remains are [:mem/:data/:args/:args_h, <num>]
145
181
  # first convert args to data
146
182
  val = [:data, val.last * 8 + 16] if val.first == :args
183
+ val = [:data, val.last * 8 + 20] if val.first == :args_h
147
184
  val
148
185
  end
149
186
 
150
187
  def eval_constants(str)
151
- Const::Syscall.const_get(@arch.upcase.to_sym)[str.to_sym] || Const::Audit::ARCH[str]
188
+ Const::Syscall.const_get(@arch.upcase.to_sym)[str.to_sym] ||
189
+ Const::Audit::ARCH[str] ||
190
+ raise(ArgumentError, "Invalid constant: #{str.inspect}")
152
191
  end
153
192
 
154
193
  attr_reader :token
155
194
 
195
+ # <goto|jmp|jump> <label|Integer>
196
+ def jmp_abs
197
+ token.fetch('goto') ||
198
+ token.fetch('jmp') ||
199
+ token.fetch('jump') ||
200
+ raise(ArgumentError, 'Invalid jump alias: ' + token.cur.inspect)
201
+ target = token.fetch!(:goto)
202
+ [:jmp_abs, target]
203
+ end
204
+
156
205
  # A <comparison> <sys_str|X|Integer> ? <label|Integer> : <label|Integer>
157
206
  def cmp
158
207
  token.fetch!('A')
@@ -192,6 +241,7 @@ module SeccompTools
192
241
  # A = mem[i]
193
242
  # A = args[i]
194
243
  # A = sys_number|arch
244
+ # A = len
195
245
  def assign
196
246
  dst = token.fetch!(:ax)
197
247
  token.fetch!('=')
@@ -200,6 +250,7 @@ module SeccompTools
200
250
  token.fetch(:ary) ||
201
251
  token.fetch('sys_number') ||
202
252
  token.fetch('arch') ||
253
+ token.fetch('len') ||
203
254
  raise(ArgumentError, 'Invalid source: ' + token.cur.inspect)
204
255
  [:assign, dst, src]
205
256
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'seccomp-tools/const'
2
4
  require 'seccomp-tools/instruction/alu'
3
5
 
@@ -5,9 +7,10 @@ module SeccompTools
5
7
  module Asm
6
8
  # Fetch tokens from string.
7
9
  # This class is for internel usage, used by {Compiler}.
10
+ # @private
8
11
  class Tokenizer
9
12
  # a valid label
10
- LABEL_REGEXP = /[a-z_][a-z0-9_]+/
13
+ LABEL_REGEXP = /[A-Za-z_]\w*/.freeze
11
14
  attr_accessor :cur
12
15
 
13
16
  # @param [String] str
@@ -64,6 +67,8 @@ Invalid return type: #{cur.inspect}.
64
67
 
65
68
  def fetch_str(str)
66
69
  return nil unless cur.start_with?(str)
70
+ return nil if str =~ /\A[A-Za-z0-9_]+\Z/ && cur[str.size] =~ /[A-Za-z0-9_]/
71
+
67
72
  @last_match_size = str.size
68
73
  str
69
74
  end
@@ -71,11 +76,13 @@ Invalid return type: #{cur.inspect}.
71
76
  def fetch_ax
72
77
  return :a if fetch_str('A')
73
78
  return :x if fetch_str('X')
79
+
74
80
  nil
75
81
  end
76
82
 
77
83
  def fetch_sys_num_arch_x
78
84
  return :x if fetch_str('X')
85
+
79
86
  fetch_number || fetch_syscall || fetch_arch
80
87
  end
81
88
 
@@ -83,6 +90,7 @@ Invalid return type: #{cur.inspect}.
83
90
  def fetch_number
84
91
  res = fetch_regexp(/^0x[0-9a-f]+/) || fetch_regexp(/^[0-9]+/)
85
92
  return nil if res.nil?
93
+
86
94
  Integer(res)
87
95
  end
88
96
 
@@ -99,6 +107,7 @@ Invalid return type: #{cur.inspect}.
99
107
  def fetch_regexp(regexp)
100
108
  idx = cur =~ regexp
101
109
  return nil if idx.nil? || idx != 0
110
+
102
111
  match = cur.match(regexp)[0]
103
112
  @last_match_size = match.size
104
113
  match
@@ -114,6 +123,7 @@ Invalid return type: #{cur.inspect}.
114
123
  regexp = /(#{Const::BPF::ACTION.keys.join('|')})(\([0-9]{1,5}\))?/
115
124
  action = fetch_regexp(regexp)
116
125
  return fetch_str('A') && :a if action.nil?
126
+
117
127
  # check if action contains '('the next bytes are (<num>)
118
128
  ret_val = 0
119
129
  if action.include?('(')
@@ -124,10 +134,11 @@ Invalid return type: #{cur.inspect}.
124
134
  end
125
135
 
126
136
  def fetch_ary
127
- support_name = %w[data mem args]
137
+ support_name = %w[data mem args args_h]
128
138
  regexp = /(#{support_name.join('|')})\[[0-9]{1,2}\]/
129
139
  match = fetch_regexp(regexp)
130
140
  return nil if match.nil?
141
+
131
142
  res, val = match.split('[')
132
143
  val = val.to_i
133
144
  [res.to_sym, val]
@@ -137,6 +148,7 @@ Invalid return type: #{cur.inspect}.
137
148
  ops = %w[+ - * / | & ^ << >>]
138
149
  op = fetch_strs(ops)
139
150
  return nil if op.nil?
151
+
140
152
  Instruction::ALU::OP_SYM.invert[op.to_sym]
141
153
  end
142
154
 
@@ -148,7 +160,7 @@ Invalid return type: #{cur.inspect}.
148
160
 
149
161
  def raise_expected(msg)
150
162
  raise ArgumentError, <<-EOS
151
- Expected #{msg}, while #{cur.split[0].inspect} occured.
163
+ Expected #{msg} but found #{cur.split[0].inspect}.
152
164
  EOS
153
165
  end
154
166
  end