seccomp-tools 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Build Status](https://travis-ci.org/david942j/seccomp-tools.svg?branch=master)](https://travis-ci.org/david942j/seccomp-tools)
|
2
|
+
[![Code Climate](https://codeclimate.com/github/david942j/seccomp-tools/badges/gpa.svg)](https://codeclimate.com/github/david942j/seccomp-tools)
|
3
|
+
[![Issue Count](https://codeclimate.com/github/david942j/seccomp-tools/badges/issue_count.svg)](https://codeclimate.com/github/david942j/seccomp-tools)
|
4
|
+
[![Test Coverage](https://codeclimate.com/github/david942j/seccomp-tools/badges/coverage.svg)](https://codeclimate.com/github/david942j/seccomp-tools/coverage)
|
5
|
+
[![Inline docs](https://inch-ci.org/github/david942j/seccomp-tools.svg?branch=master)](https://inch-ci.org/github/david942j/seccomp-tools)
|
6
|
+
[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](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
|
+
![dump](https://github.com/david942j/seccomp-tools/blob/master/examples/dump-diary.png?raw=true)
|
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
|