seccomp-tools 0.1.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 +7 -0
- data/README.md +151 -0
- data/bin/seccomp-tools +5 -0
- data/ext/ptrace/extconf.rb +5 -0
- data/ext/ptrace/ptrace.c +76 -0
- data/lib/seccomp-tools.rb +8 -0
- data/lib/seccomp-tools/bpf.rb +71 -0
- data/lib/seccomp-tools/cli/base.rb +67 -0
- data/lib/seccomp-tools/cli/cli.rb +72 -0
- data/lib/seccomp-tools/cli/disasm.rb +41 -0
- data/lib/seccomp-tools/cli/dump.rb +66 -0
- data/lib/seccomp-tools/const.rb +112 -0
- data/lib/seccomp-tools/consts/amd64.rb +335 -0
- data/lib/seccomp-tools/consts/i386.rb +382 -0
- data/lib/seccomp-tools/context.rb +31 -0
- data/lib/seccomp-tools/disasm.rb +37 -0
- data/lib/seccomp-tools/dumper.rb +128 -0
- data/lib/seccomp-tools/instruction/alu.rb +42 -0
- data/lib/seccomp-tools/instruction/base.rb +30 -0
- data/lib/seccomp-tools/instruction/instruction.rb +8 -0
- data/lib/seccomp-tools/instruction/jmp.rb +76 -0
- data/lib/seccomp-tools/instruction/ld.rb +69 -0
- data/lib/seccomp-tools/instruction/ldx.rb +14 -0
- data/lib/seccomp-tools/instruction/misc.rb +24 -0
- data/lib/seccomp-tools/instruction/ret.rb +19 -0
- data/lib/seccomp-tools/instruction/st.rb +20 -0
- data/lib/seccomp-tools/instruction/stx.rb +14 -0
- data/lib/seccomp-tools/syscall.rb +67 -0
- data/lib/seccomp-tools/util.rb +54 -0
- data/lib/seccomp-tools/version.rb +4 -0
- metadata +173 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: afb07d55f6cf7b437b6829709c0897af34ae112e
|
4
|
+
data.tar.gz: 72b290bd53662794f8b588d59912733096d7d79d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0d38df515ef8dc6474b3b407be4c3e0959cd2e28227e863c3826d8b437154c65ca7e5b385d1db4ba6ae1010f1058c25b089d2918bbe6b6b805a9bbdbe438ad07
|
7
|
+
data.tar.gz: 54730dafe8e3a77743f0d2eaa8cb947767d00b9aa3b5f2cd4a8d77386eb65decc664f74d84998d7630c7216a985cf8d8e7ca7345a63eae99aa3d9ae449d495db
|
data/README.md
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
[](https://travis-ci.org/david942j/seccomp-tools)
|
2
|
+
[](https://codeclimate.com/github/david942j/seccomp-tools)
|
3
|
+
[](https://codeclimate.com/github/david942j/seccomp-tools)
|
4
|
+
[](https://codeclimate.com/github/david942j/seccomp-tools/coverage)
|
5
|
+
[](https://inch-ci.org/github/david942j/seccomp-tools)
|
6
|
+
[](http://choosealicense.com/licenses/mit/)
|
7
|
+
|
8
|
+
# Seccomp Tools
|
9
|
+
Provides powerful tools for seccomp analysis.
|
10
|
+
|
11
|
+
This project is targeted to (but not limited to) analyze seccomp sandbox in CTF pwn challenges.
|
12
|
+
Some features might be CTF-specific, but still useful for analysis of seccomp in real-case.
|
13
|
+
|
14
|
+
## Features
|
15
|
+
* Dump - Automatically dump seccomp-bpf from binary.
|
16
|
+
* Disasm - Convert bpf to human readable format.
|
17
|
+
- Simple decompile.
|
18
|
+
- Show syscall names.
|
19
|
+
- (TODO) Simplify disassemble result.
|
20
|
+
* (TODO) Solve constraints for executing syscalls (e.g. `execve/open/read/write`).
|
21
|
+
* Support multi-architectures.
|
22
|
+
|
23
|
+
## Installation
|
24
|
+
|
25
|
+
Will be available on RubyGems.org!
|
26
|
+
(TODO)
|
27
|
+
|
28
|
+
## Command Line Interface
|
29
|
+
|
30
|
+
### seccomp-tools
|
31
|
+
|
32
|
+
```bash
|
33
|
+
$ seccomp-tools --help
|
34
|
+
# Usage: seccomp-tools [--version] [--help] <command> [<options>]
|
35
|
+
#
|
36
|
+
# List of commands:
|
37
|
+
#
|
38
|
+
# dump Automatically dump seccomp bpf from execution file.
|
39
|
+
# disasm Disassembly seccomp bpf.
|
40
|
+
#
|
41
|
+
# See 'seccomp-tools --help <command>' to read about a specific subcommand.
|
42
|
+
|
43
|
+
$ seccomp-tools --help dump
|
44
|
+
# dump - Automatically dump seccomp bpf from execution file.
|
45
|
+
#
|
46
|
+
# Usage: seccomp-tools dump [exec] [options]
|
47
|
+
# -c, --sh-exec <command> Executes the given command (via sh).
|
48
|
+
# Use this option if want to pass arguments or do pipe things to the execution file.
|
49
|
+
# -f, --format FORMAT Output format. FORMAT can only be one of <disasm|raw|inspect>.
|
50
|
+
# Default: disasm
|
51
|
+
# -l, --limit LIMIT Limit the number of calling "prctl(PR_SET_SECCOMP)".
|
52
|
+
# The target process will be killed whenever its calling times reaches LIMIT.
|
53
|
+
# Default: 1
|
54
|
+
# -o, --output FILE Output result into FILE instead of stdout.
|
55
|
+
# If multiple seccomp syscalls have been invoked (see --limit),
|
56
|
+
# results will be written to FILE, FILE_1, FILE_2.. etc.
|
57
|
+
# For example, "--output out.bpf" and the output files are out.bpf, out_1.bpf, ...
|
58
|
+
|
59
|
+
```
|
60
|
+
|
61
|
+
### dump
|
62
|
+
|
63
|
+
Dump the seccomp bpf from an execution file.
|
64
|
+
This work is done by the `ptrace` syscall.
|
65
|
+
|
66
|
+
NOTICE: beware of the execution file will be executed.
|
67
|
+
```bash
|
68
|
+
$ file spec/binary/twctf-2016-diary
|
69
|
+
# 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
|
70
|
+
|
71
|
+
$ seccomp-tools dump spec/binary/twctf-2016-diary
|
72
|
+
# line CODE JT JF K
|
73
|
+
# =================================
|
74
|
+
# 0000: 0x20 0x00 0x00 0x00000000 A = sys_number
|
75
|
+
# 0001: 0x15 0x00 0x01 0x00000002 if (A != open) goto 0003
|
76
|
+
# 0002: 0x06 0x00 0x00 0x00000000 return KILL
|
77
|
+
# 0003: 0x15 0x00 0x01 0x00000101 if (A != openat) goto 0005
|
78
|
+
# 0004: 0x06 0x00 0x00 0x00000000 return KILL
|
79
|
+
# 0005: 0x15 0x00 0x01 0x0000003b if (A != execve) goto 0007
|
80
|
+
# 0006: 0x06 0x00 0x00 0x00000000 return KILL
|
81
|
+
# 0007: 0x15 0x00 0x01 0x00000038 if (A != clone) goto 0009
|
82
|
+
# 0008: 0x06 0x00 0x00 0x00000000 return KILL
|
83
|
+
# 0009: 0x15 0x00 0x01 0x00000039 if (A != fork) goto 0011
|
84
|
+
# 0010: 0x06 0x00 0x00 0x00000000 return KILL
|
85
|
+
# 0011: 0x15 0x00 0x01 0x0000003a if (A != vfork) goto 0013
|
86
|
+
# 0012: 0x06 0x00 0x00 0x00000000 return KILL
|
87
|
+
# 0013: 0x15 0x00 0x01 0x00000055 if (A != creat) goto 0015
|
88
|
+
# 0014: 0x06 0x00 0x00 0x00000000 return KILL
|
89
|
+
# 0015: 0x15 0x00 0x01 0x00000142 if (A != execveat) goto 0017
|
90
|
+
# 0016: 0x06 0x00 0x00 0x00000000 return KILL
|
91
|
+
# 0017: 0x06 0x00 0x00 0x7fff0000 return ALLOW
|
92
|
+
|
93
|
+
$ seccomp-tools dump spec/binary/twctf-2016-diary -f inspect
|
94
|
+
# "\x20\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x01\x02\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x01\x01\x01\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x01\x3B\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x01\x38\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x01\x39\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x01\x3A\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x01\x55\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x01\x42\x01\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\xFF\x7F"
|
95
|
+
|
96
|
+
$ seccomp-tools dump spec/binary/twctf-2016-diary -f raw | xxd
|
97
|
+
# 00000000: 2000 0000 0000 0000 1500 0001 0200 0000 ...............
|
98
|
+
# 00000010: 0600 0000 0000 0000 1500 0001 0101 0000 ................
|
99
|
+
# 00000020: 0600 0000 0000 0000 1500 0001 3b00 0000 ............;...
|
100
|
+
# 00000030: 0600 0000 0000 0000 1500 0001 3800 0000 ............8...
|
101
|
+
# 00000040: 0600 0000 0000 0000 1500 0001 3900 0000 ............9...
|
102
|
+
# 00000050: 0600 0000 0000 0000 1500 0001 3a00 0000 ............:...
|
103
|
+
# 00000060: 0600 0000 0000 0000 1500 0001 5500 0000 ............U...
|
104
|
+
# 00000070: 0600 0000 0000 0000 1500 0001 4201 0000 ............B...
|
105
|
+
# 00000080: 0600 0000 0000 0000 0600 0000 0000 ff7f ................
|
106
|
+
|
107
|
+
```
|
108
|
+
|
109
|
+
### disasm
|
110
|
+
|
111
|
+
Disassemble the seccomp bpf.
|
112
|
+
```bash
|
113
|
+
$ xxd spec/data/twctf-2016-diary.bpf | head -n 3
|
114
|
+
# 00000000: 2000 0000 0000 0000 1500 0001 0200 0000 ...............
|
115
|
+
# 00000010: 0600 0000 0000 0000 1500 0001 0101 0000 ................
|
116
|
+
# 00000020: 0600 0000 0000 0000 1500 0001 3b00 0000 ............;...
|
117
|
+
|
118
|
+
$ seccomp-tools disasm spec/data/twctf-2016-diary.bpf
|
119
|
+
# line CODE JT JF K
|
120
|
+
# =================================
|
121
|
+
# 0000: 0x20 0x00 0x00 0x00000000 A = sys_number
|
122
|
+
# 0001: 0x15 0x00 0x01 0x00000002 if (A != open) goto 0003
|
123
|
+
# 0002: 0x06 0x00 0x00 0x00000000 return KILL
|
124
|
+
# 0003: 0x15 0x00 0x01 0x00000101 if (A != openat) goto 0005
|
125
|
+
# 0004: 0x06 0x00 0x00 0x00000000 return KILL
|
126
|
+
# 0005: 0x15 0x00 0x01 0x0000003b if (A != execve) goto 0007
|
127
|
+
# 0006: 0x06 0x00 0x00 0x00000000 return KILL
|
128
|
+
# 0007: 0x15 0x00 0x01 0x00000038 if (A != clone) goto 0009
|
129
|
+
# 0008: 0x06 0x00 0x00 0x00000000 return KILL
|
130
|
+
# 0009: 0x15 0x00 0x01 0x00000039 if (A != fork) goto 0011
|
131
|
+
# 0010: 0x06 0x00 0x00 0x00000000 return KILL
|
132
|
+
# 0011: 0x15 0x00 0x01 0x0000003a if (A != vfork) goto 0013
|
133
|
+
# 0012: 0x06 0x00 0x00 0x00000000 return KILL
|
134
|
+
# 0013: 0x15 0x00 0x01 0x00000055 if (A != creat) goto 0015
|
135
|
+
# 0014: 0x06 0x00 0x00 0x00000000 return KILL
|
136
|
+
# 0015: 0x15 0x00 0x01 0x00000142 if (A != execveat) goto 0017
|
137
|
+
# 0016: 0x06 0x00 0x00 0x00000000 return KILL
|
138
|
+
# 0017: 0x06 0x00 0x00 0x7fff0000 return ALLOW
|
139
|
+
|
140
|
+
```
|
141
|
+
|
142
|
+
## Screenshots
|
143
|
+
|
144
|
+
### Dump
|
145
|
+

|
146
|
+
|
147
|
+
|
148
|
+
## I Need You
|
149
|
+
Any suggestion or feature request is welcome!
|
150
|
+
Feel free to file an issue or send a pull request.
|
151
|
+
And, if you like this work, I'll be happy to be [stared](https://github.com/david942j/seccomp-tools/stargazers) :grimacing:
|
data/bin/seccomp-tools
ADDED
data/ext/ptrace/ptrace.c
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
#include <sys/ptrace.h>
|
2
|
+
#include <sys/signal.h>
|
3
|
+
|
4
|
+
#include "ruby.h"
|
5
|
+
|
6
|
+
static VALUE
|
7
|
+
ptrace_geteventmsg(VALUE _mod, VALUE pid) {
|
8
|
+
unsigned long val;
|
9
|
+
ptrace(PTRACE_GETEVENTMSG, NUM2LONG(pid), NULL, &val);
|
10
|
+
return ULONG2NUM(val);
|
11
|
+
}
|
12
|
+
|
13
|
+
static VALUE
|
14
|
+
ptrace_peekdata(VALUE _mod, VALUE pid, VALUE addr, VALUE _data) {
|
15
|
+
long val = ptrace(PTRACE_PEEKDATA, NUM2LONG(pid), NUM2LONG(addr), NULL);
|
16
|
+
return LONG2NUM(val);
|
17
|
+
}
|
18
|
+
|
19
|
+
static VALUE
|
20
|
+
ptrace_peekuser(VALUE _mod, VALUE pid, VALUE off, VALUE _data) {
|
21
|
+
long val = ptrace(PTRACE_PEEKUSER, NUM2LONG(pid), NUM2LONG(off), NULL);
|
22
|
+
return LONG2NUM(val);
|
23
|
+
}
|
24
|
+
|
25
|
+
static VALUE
|
26
|
+
ptrace_setoptions(VALUE _mod, VALUE pid, VALUE _addr, VALUE option) {
|
27
|
+
if(ptrace(PTRACE_SETOPTIONS, NUM2LONG(pid), NULL, NUM2LONG(option)) != 0)
|
28
|
+
perror("ptrace setoptions");
|
29
|
+
return Qnil;
|
30
|
+
}
|
31
|
+
|
32
|
+
static VALUE
|
33
|
+
ptrace_syscall(VALUE _mod, VALUE pid, VALUE _addr, VALUE sig) {
|
34
|
+
if(ptrace(PTRACE_SYSCALL, NUM2LONG(pid), NULL, NUM2LONG(sig)) != 0)
|
35
|
+
perror("ptrace syscall");
|
36
|
+
return Qnil;
|
37
|
+
}
|
38
|
+
|
39
|
+
static VALUE
|
40
|
+
ptrace_traceme(VALUE _mod) {
|
41
|
+
if(ptrace(PTRACE_TRACEME, 0, 0, 0) != 0)
|
42
|
+
perror("ptrace traceme");
|
43
|
+
return Qnil;
|
44
|
+
}
|
45
|
+
|
46
|
+
static VALUE
|
47
|
+
ptrace_traceme_and_stop(VALUE mod) {
|
48
|
+
ptrace_traceme(mod);
|
49
|
+
kill(getpid(), SIGSTOP);
|
50
|
+
return Qnil;
|
51
|
+
}
|
52
|
+
|
53
|
+
|
54
|
+
void Init_ptrace(void) {
|
55
|
+
VALUE mSeccompTools = rb_define_module("SeccompTools");
|
56
|
+
VALUE mPtrace = rb_define_module_under(mSeccompTools, "Ptrace");
|
57
|
+
|
58
|
+
/* consts */
|
59
|
+
rb_define_const(mPtrace, "EVENT_CLONE", UINT2NUM(PTRACE_EVENT_CLONE));
|
60
|
+
rb_define_const(mPtrace, "EVENT_FORK", UINT2NUM(PTRACE_EVENT_FORK));
|
61
|
+
rb_define_const(mPtrace, "EVENT_VFORK", UINT2NUM(PTRACE_EVENT_VFORK));
|
62
|
+
rb_define_const(mPtrace, "O_TRACECLONE", UINT2NUM(PTRACE_O_TRACECLONE));
|
63
|
+
rb_define_const(mPtrace, "O_TRACEFORK", UINT2NUM(PTRACE_O_TRACEFORK));
|
64
|
+
rb_define_const(mPtrace, "O_TRACESYSGOOD", UINT2NUM(PTRACE_O_TRACESYSGOOD));
|
65
|
+
rb_define_const(mPtrace, "O_TRACEVFORK", UINT2NUM(PTRACE_O_TRACEVFORK));
|
66
|
+
|
67
|
+
/* ptrace wrapper */
|
68
|
+
rb_define_module_function(mPtrace, "geteventmsg", ptrace_geteventmsg, 1);
|
69
|
+
rb_define_module_function(mPtrace, "peekdata", ptrace_peekdata, 3);
|
70
|
+
rb_define_module_function(mPtrace, "peekuser", ptrace_peekuser, 3);
|
71
|
+
rb_define_module_function(mPtrace, "setoptions", ptrace_setoptions, 3);
|
72
|
+
rb_define_module_function(mPtrace, "syscall", ptrace_syscall, 3);
|
73
|
+
rb_define_module_function(mPtrace, "traceme", ptrace_traceme, 0);
|
74
|
+
rb_define_module_function(mPtrace, "traceme_and_stop", ptrace_traceme_and_stop, 0);
|
75
|
+
}
|
76
|
+
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'seccomp-tools/const'
|
2
|
+
require 'seccomp-tools/instruction/instruction'
|
3
|
+
|
4
|
+
module SeccompTools
|
5
|
+
# Define the +struct sock_filter+, while more powerful.
|
6
|
+
class BPF
|
7
|
+
attr_reader :line, :code, :jt, :jf, :k, :arch
|
8
|
+
# @return [Array<SeccompTools::Context>]
|
9
|
+
attr_accessor :contexts
|
10
|
+
|
11
|
+
# @param [String] raw
|
12
|
+
# One +struct sock_filter+ in bytes, should exactly 8 bytes.
|
13
|
+
# @param [Symbol] arch
|
14
|
+
# Architecture, for showing constant names in decompile.
|
15
|
+
# @param [Integer] line
|
16
|
+
# Line number of this filter.
|
17
|
+
def initialize(raw, arch, line)
|
18
|
+
io = StringIO.new(raw)
|
19
|
+
@code = io.read(2).unpack('S').first
|
20
|
+
@jt = io.read(1).ord
|
21
|
+
@jf = io.read(1).ord
|
22
|
+
@k = io.read(4).unpack('L').first
|
23
|
+
@arch = arch
|
24
|
+
@line = line
|
25
|
+
end
|
26
|
+
|
27
|
+
# Pretty display the disassemble result.
|
28
|
+
# @return [String]
|
29
|
+
def disasm
|
30
|
+
format(' %04d: 0x%02x 0x%02x 0x%02x 0x%08x %s',
|
31
|
+
line, code, jt, jf, k, decompile)
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [Symbol]
|
35
|
+
def command
|
36
|
+
Const::BPF::COMMAND.invert[code & 7]
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [String]
|
40
|
+
def decompile
|
41
|
+
inst.decompile
|
42
|
+
end
|
43
|
+
|
44
|
+
# @param [Context] context
|
45
|
+
# Current context.
|
46
|
+
# @yieldparam [Integer] pc
|
47
|
+
# Program conter after this instruction.
|
48
|
+
# @yieldparam [Context] ctx
|
49
|
+
# Context after this instruction.
|
50
|
+
# @return [void]
|
51
|
+
def branch(context, &block)
|
52
|
+
# TODO: consider alu
|
53
|
+
inst.branch(context).each(&block)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def inst
|
59
|
+
@inst ||= case command
|
60
|
+
when :alu then SeccompTools::Instruction::ALU
|
61
|
+
when :jmp then SeccompTools::Instruction::JMP
|
62
|
+
when :ld then SeccompTools::Instruction::LD
|
63
|
+
when :ldx then SeccompTools::Instruction::LDX
|
64
|
+
when :misc then SeccompTools::Instruction::MISC
|
65
|
+
when :ret then SeccompTools::Instruction::RET
|
66
|
+
when :st then SeccompTools::Instruction::ST
|
67
|
+
when :stx then SeccompTools::Instruction::STX
|
68
|
+
end.new(self)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module SeccompTools
|
4
|
+
module CLI
|
5
|
+
# Base class for handlers.
|
6
|
+
class Base
|
7
|
+
attr_reader :option, :argv
|
8
|
+
def initialize(argv)
|
9
|
+
@option = {}
|
10
|
+
@argv = argv
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
# Handle show help message.
|
16
|
+
# @return [Boolean]
|
17
|
+
# For decestors to check if needs to conitnue.
|
18
|
+
def handle
|
19
|
+
return CLI.show(parser.help) if argv.empty? || %w[-h --help].any? { |h| argv.include?(h) }
|
20
|
+
parser.parse!(argv)
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
24
|
+
# Write data to stdout or file(s).
|
25
|
+
# @param [String] data
|
26
|
+
# Data.
|
27
|
+
# @return [void]
|
28
|
+
def output(data)
|
29
|
+
# if file name not present, just output to stdout.
|
30
|
+
return $stdout.write(data) if option[:ofile].nil?
|
31
|
+
# times of calling output
|
32
|
+
@serial ||= 0
|
33
|
+
IO.binwrite(file_of(option[:ofile], @serial), data)
|
34
|
+
@serial += 1
|
35
|
+
end
|
36
|
+
|
37
|
+
# Get filename with serial number.
|
38
|
+
#
|
39
|
+
# @param [String] file
|
40
|
+
# Filename.
|
41
|
+
# @param [Integer] serial
|
42
|
+
# serial number, starts from zero.
|
43
|
+
# @return [String]
|
44
|
+
# Result filename.
|
45
|
+
# @example
|
46
|
+
# file_of('a.png', 0)
|
47
|
+
# #=> 'a.png'
|
48
|
+
# file_of('a.png', 1)
|
49
|
+
# #=> 'a_1.png'
|
50
|
+
# file_of('test/a.png', 3)
|
51
|
+
# #=> 'test/a_3.png'
|
52
|
+
def file_of(file, serial)
|
53
|
+
suffix = serial.zero? ? '' : "_#{serial}"
|
54
|
+
ext = File.extname(file)
|
55
|
+
base = File.basename(file, ext)
|
56
|
+
File.join(File.dirname(file), base + suffix) + ext
|
57
|
+
end
|
58
|
+
|
59
|
+
# For decestors easy to define usage message.
|
60
|
+
# @return [String]
|
61
|
+
# Usage information.
|
62
|
+
def usage
|
63
|
+
self.class.const_get(:USAGE)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'seccomp-tools/cli/disasm'
|
2
|
+
require 'seccomp-tools/cli/dump'
|
3
|
+
require 'seccomp-tools/version'
|
4
|
+
|
5
|
+
module SeccompTools
|
6
|
+
# Handle CLI arguments parse.
|
7
|
+
module CLI
|
8
|
+
# Handled commands
|
9
|
+
COMMANDS = {
|
10
|
+
'dump' => SeccompTools::CLI::Dump,
|
11
|
+
'disasm' => SeccompTools::CLI::Disasm
|
12
|
+
}.freeze
|
13
|
+
|
14
|
+
# Main usage message.
|
15
|
+
USAGE = <<EOS.sub('%COMMANDS', COMMANDS.map { |k, v| "\t#{k}\t#{v::SUMMARY}" }.join("\n")).freeze
|
16
|
+
Usage: seccomp-tools [--version] [--help] <command> [<options>]
|
17
|
+
|
18
|
+
List of commands:
|
19
|
+
|
20
|
+
%COMMANDS
|
21
|
+
|
22
|
+
See 'seccomp-tools --help <command>' to read about a specific subcommand.
|
23
|
+
EOS
|
24
|
+
|
25
|
+
module_function
|
26
|
+
|
27
|
+
# Main work method for CLI.
|
28
|
+
# @param [Array<String>] argv
|
29
|
+
# Command line arguments.
|
30
|
+
# @return [void]
|
31
|
+
# @example
|
32
|
+
# work(argv: %w[--help])
|
33
|
+
# #=> # usage message
|
34
|
+
# work(argv: %w[--version])
|
35
|
+
# #=> # version message
|
36
|
+
def work(argv)
|
37
|
+
# all -h equivalent to --help
|
38
|
+
argv = argv.map { |a| a == '-h' ? '--help' : a }
|
39
|
+
idx = argv.index { |c| !c.start_with?('-') }
|
40
|
+
preoption = idx.nil? ? argv.shift(argv.size) : argv.shift(idx)
|
41
|
+
|
42
|
+
# handle --version or --help or nothing
|
43
|
+
return show("SeccompTools Version #{SeccompTools::VERSION}") if preoption.include?('--version')
|
44
|
+
return show(USAGE) if idx.nil?
|
45
|
+
|
46
|
+
# let's handle commands
|
47
|
+
cmd = argv.shift
|
48
|
+
argv = %w[--help] if preoption.include?('--help')
|
49
|
+
return show(invalid(cmd)) if COMMANDS[cmd].nil?
|
50
|
+
COMMANDS[cmd].new(argv).handle
|
51
|
+
end
|
52
|
+
|
53
|
+
# Just write message to stdout.
|
54
|
+
# @param [String] msg
|
55
|
+
# The message.
|
56
|
+
# @return [false]
|
57
|
+
# Always return +false+.
|
58
|
+
def show(msg)
|
59
|
+
puts msg
|
60
|
+
false
|
61
|
+
end
|
62
|
+
|
63
|
+
class << self
|
64
|
+
private
|
65
|
+
|
66
|
+
# Invalid command message.
|
67
|
+
def invalid(cmd)
|
68
|
+
format("Invalid command '%s'\n\nSee 'seccomp-tools --help' for list of valid commands", cmd)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|