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.
- 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
|
[![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
|
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
|
![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!
|
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
|