seccomp-tools 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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