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.
- checksums.yaml +5 -5
- data/README.md +84 -17
- data/bin/seccomp-tools +1 -0
- data/ext/ptrace/ptrace.c +8 -1
- data/lib/seccomp-tools.rb +2 -0
- data/lib/seccomp-tools/asm/asm.rb +4 -1
- data/lib/seccomp-tools/asm/compiler.rb +61 -10
- data/lib/seccomp-tools/asm/tokenizer.rb +15 -3
- data/lib/seccomp-tools/bpf.rb +2 -0
- data/lib/seccomp-tools/cli/asm.rb +14 -4
- data/lib/seccomp-tools/cli/base.rb +5 -0
- data/lib/seccomp-tools/cli/cli.rb +6 -3
- data/lib/seccomp-tools/cli/disasm.rb +5 -1
- data/lib/seccomp-tools/cli/dump.rb +4 -1
- data/lib/seccomp-tools/cli/emu.rb +15 -2
- data/lib/seccomp-tools/const.rb +25 -19
- data/lib/seccomp-tools/consts/sys_arg.rb +432 -0
- data/lib/seccomp-tools/consts/{amd64.rb → sys_nr/amd64.rb} +4 -2
- data/lib/seccomp-tools/consts/{i386.rb → sys_nr/i386.rb} +5 -2
- data/lib/seccomp-tools/disasm/context.rb +125 -34
- data/lib/seccomp-tools/disasm/disasm.rb +4 -2
- data/lib/seccomp-tools/dumper.rb +4 -0
- data/lib/seccomp-tools/emulator.rb +10 -0
- data/lib/seccomp-tools/instruction/alu.rb +6 -1
- data/lib/seccomp-tools/instruction/base.rb +4 -2
- data/lib/seccomp-tools/instruction/instruction.rb +2 -0
- data/lib/seccomp-tools/instruction/jmp.rb +12 -2
- data/lib/seccomp-tools/instruction/ld.rb +27 -11
- data/lib/seccomp-tools/instruction/ldx.rb +2 -0
- data/lib/seccomp-tools/instruction/misc.rb +2 -0
- data/lib/seccomp-tools/instruction/ret.rb +3 -0
- data/lib/seccomp-tools/instruction/st.rb +3 -1
- data/lib/seccomp-tools/instruction/stx.rb +2 -0
- data/lib/seccomp-tools/syscall.rb +5 -1
- data/lib/seccomp-tools/templates/asm.amd64.asm +26 -0
- data/lib/seccomp-tools/templates/asm.c +17 -0
- data/lib/seccomp-tools/templates/asm.i386.asm +33 -0
- data/lib/seccomp-tools/util.rb +16 -1
- data/lib/seccomp-tools/version.rb +3 -1
- metadata +18 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5d0a3997904616df1a40c2a8131ec70fb83511477e155de8e6d0de9c3a445cf9
|
4
|
+
data.tar.gz: eb7970f0de4a89ac13e41626950dbee92ca141b5bc4342e804a799076a61ac53
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ce8984f8b3ada51158a181de2ab5e12d291ff12cf3515467763c77ab58870416c4927fce3e362c3775d3749e8a5939d54971681ec85da96adfb38210a51ca90
|
7
|
+
data.tar.gz: 2611058a57579fb1806f9bcc6ca05d203f36fa34f5d6aa0434b71b0dbc815f14b513b9907d60a4cbc59a8e648c8880e39e5339a1d85113a98cd147728223e65e
|
data/README.md
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
[](https://travis-ci.org/david942j/seccomp-tools)
|
2
|
+
[](https://dependabot.com)
|
2
3
|
[](https://codeclimate.com/github/david942j/seccomp-tools)
|
3
4
|
[](https://codeclimate.com/github/david942j/seccomp-tools)
|
4
5
|
[](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
|
16
|
-
* Disasm -
|
16
|
+
* Dump - Automatically dumps seccomp-bpf from execution file(s).
|
17
|
+
* Disasm - Converts bpf to human readable format.
|
17
18
|
- Simple decompile.
|
18
|
-
-
|
19
|
+
- Display syscall names and arguments when possible.
|
19
20
|
- Colorful!
|
20
21
|
* Asm - Write seccomp rules is so easy!
|
21
|
-
* Emu -
|
22
|
-
*
|
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
|
-
|
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/
|
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
|
-
|
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
|
-
|
152
|
-
|
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
|
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|
|
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
|
187
|
-
#
|
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
|
-
|
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
|

|
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!
|
data/bin/seccomp-tools
CHANGED
data/ext/ptrace/ptrace.c
CHANGED
@@ -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
|
-
/*
|
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
|
|
data/lib/seccomp-tools.rb
CHANGED
@@ -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(
|
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,
|
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>
|
101
|
+
# mem[i] = <A|X>
|
80
102
|
# <A|X> = 123|sys_const
|
81
|
-
# A =
|
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,
|
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
|
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
|
-
|
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] ||
|
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 = /[
|
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}
|
163
|
+
Expected #{msg} but found #{cur.split[0].inspect}.
|
152
164
|
EOS
|
153
165
|
end
|
154
166
|
end
|