seccomp-tools 1.1.0 → 1.5.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 +112 -30
- data/bin/seccomp-tools +1 -0
- data/ext/ptrace/extconf.rb +2 -0
- data/ext/ptrace/ptrace.c +107 -5
- data/lib/seccomp-tools.rb +5 -0
- data/lib/seccomp-tools/asm/asm.rb +5 -2
- data/lib/seccomp-tools/asm/compiler.rb +96 -18
- data/lib/seccomp-tools/asm/tokenizer.rb +25 -8
- data/lib/seccomp-tools/bpf.rb +7 -4
- data/lib/seccomp-tools/cli/asm.rb +16 -6
- data/lib/seccomp-tools/cli/base.rb +10 -4
- data/lib/seccomp-tools/cli/cli.rb +9 -6
- data/lib/seccomp-tools/cli/disasm.rb +6 -2
- data/lib/seccomp-tools/cli/dump.rb +37 -6
- data/lib/seccomp-tools/cli/emu.rb +41 -22
- data/lib/seccomp-tools/const.rb +47 -16
- data/lib/seccomp-tools/consts/sys_arg.rb +432 -0
- data/lib/seccomp-tools/consts/sys_nr/aarch64.rb +284 -0
- data/lib/seccomp-tools/consts/{amd64.rb → sys_nr/amd64.rb} +6 -1
- data/lib/seccomp-tools/consts/{i386.rb → sys_nr/i386.rb} +18 -15
- data/lib/seccomp-tools/disasm/context.rb +125 -34
- data/lib/seccomp-tools/disasm/disasm.rb +5 -2
- data/lib/seccomp-tools/dumper.rb +75 -8
- data/lib/seccomp-tools/emulator.rb +19 -8
- data/lib/seccomp-tools/instruction/alu.rb +7 -2
- data/lib/seccomp-tools/instruction/base.rb +5 -3
- data/lib/seccomp-tools/instruction/instruction.rb +2 -0
- data/lib/seccomp-tools/instruction/jmp.rb +28 -14
- data/lib/seccomp-tools/instruction/ld.rb +28 -12
- 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 +14 -2
- data/lib/seccomp-tools/instruction/st.rb +4 -2
- data/lib/seccomp-tools/instruction/stx.rb +2 -0
- data/lib/seccomp-tools/logger.rb +40 -0
- data/lib/seccomp-tools/syscall.rb +24 -13
- 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 +24 -3
- data/lib/seccomp-tools/version.rb +3 -1
- metadata +51 -44
@@ -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,13 +33,17 @@ 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
|
30
40
|
when /^#{Tokenizer::LABEL_REGEXP}:/ then define_label
|
31
41
|
when /^return/ then ret
|
42
|
+
when /^A\s*=\s*-A/ then alu_neg
|
32
43
|
when /^(A|X)\s*=[^=]/ then assign
|
33
|
-
when /^
|
44
|
+
when /^mem\[\d+\]\s*=\s*(A|X)/ then store
|
45
|
+
when /^A\s*.{1,2}=/ then alu
|
46
|
+
when /^(goto|jmp|jump)/ then jmp_abs
|
34
47
|
end
|
35
48
|
rescue ArgumentError => e
|
36
49
|
invalid(@input.size - 1, e.message)
|
@@ -40,11 +53,16 @@ module SeccompTools
|
|
40
53
|
@labels[res.last] = @insts.size
|
41
54
|
else
|
42
55
|
@insts << res
|
56
|
+
@insts_linenum[@insts.size - 1] = @input.size - 1
|
43
57
|
end
|
44
|
-
res
|
45
58
|
end
|
46
59
|
|
60
|
+
# Compiles the processed instructions.
|
61
|
+
#
|
47
62
|
# @return [Array<SeccompTools::BPF>]
|
63
|
+
# Returns the compiled {BPF} array.
|
64
|
+
# @raise [ArgumentError]
|
65
|
+
# Raises the error found during compilation.
|
48
66
|
def compile!
|
49
67
|
@insts.map.with_index do |inst, idx|
|
50
68
|
@line = idx
|
@@ -53,17 +71,22 @@ module SeccompTools
|
|
53
71
|
when :alu then compile_alu(inst[1], inst[2])
|
54
72
|
when :ret then compile_ret(inst[1])
|
55
73
|
when :cmp then compile_cmp(inst[1], inst[2], inst[3], inst[4])
|
74
|
+
when :jmp_abs then compile_jmp_abs(inst[1])
|
56
75
|
end
|
57
76
|
end
|
58
77
|
rescue ArgumentError => e
|
59
|
-
invalid(@line, e.message)
|
78
|
+
invalid(@insts_linenum[@line], e.message)
|
60
79
|
end
|
61
80
|
|
62
81
|
private
|
63
82
|
|
83
|
+
# Emits a raw BPF object.
|
84
|
+
#
|
85
|
+
# @return [BPF]
|
86
|
+
# Returns the emitted {BPF} object.
|
64
87
|
def emit(*args, k: 0, jt: 0, jf: 0)
|
65
88
|
code = 0
|
66
|
-
# bad idea,
|
89
|
+
# bad idea, but keys are not duplicated so this is ok.
|
67
90
|
args.each do |a|
|
68
91
|
code |= Const::BPF::COMMAND.fetch(a, 0)
|
69
92
|
code |= Const::BPF::JMP.fetch(a, 0)
|
@@ -76,27 +99,37 @@ module SeccompTools
|
|
76
99
|
end
|
77
100
|
|
78
101
|
# A = X / X = A
|
79
|
-
# <A|X>
|
102
|
+
# mem[i] = <A|X>
|
80
103
|
# <A|X> = 123|sys_const
|
81
|
-
# A =
|
104
|
+
# A = len
|
105
|
+
# <A|X> = mem[i]
|
106
|
+
# A = args_h[i]|args[i]|sys_number|arch
|
82
107
|
# A = data[4 * i]
|
83
108
|
def compile_assign(dst, src)
|
84
109
|
# misc txa / tax
|
85
|
-
return
|
86
|
-
|
110
|
+
return compile_assign_misc(dst, src) if (dst == :a && src == :x) || (dst == :x && src == :a)
|
111
|
+
# case of st / stx
|
112
|
+
return emit(src == :x ? :stx : :st, k: dst.last) if dst.is_a?(Array) && dst.first == :mem
|
113
|
+
|
87
114
|
src = evaluate(src)
|
88
|
-
# TODO: handle store case.
|
89
115
|
ld = dst == :x ? :ldx : :ld
|
90
116
|
# <A|X> = <immi>
|
91
117
|
return emit(ld, :imm, k: src) if src.is_a?(Integer)
|
92
|
-
# now src must be in form [:mem/:data, num]
|
93
|
-
return emit(ld,
|
118
|
+
# now src must be in form [:len/:mem/:data, num]
|
119
|
+
return emit(ld, src.first, k: src.last) if src.first == :mem || src.first == :len
|
94
120
|
# check if num is multiple of 4
|
95
|
-
raise ArgumentError, 'Index of data[] must be
|
121
|
+
raise ArgumentError, 'Index of data[] must be a multiple of 4' if src.last % 4 != 0
|
122
|
+
|
96
123
|
emit(ld, :abs, k: src.last)
|
97
124
|
end
|
98
125
|
|
126
|
+
def compile_assign_misc(dst, _src)
|
127
|
+
emit(:misc, dst == :a ? :txa : :tax)
|
128
|
+
end
|
129
|
+
|
99
130
|
def compile_alu(op, val)
|
131
|
+
return emit(:alu, :neg) if op == :neg
|
132
|
+
|
100
133
|
val = evaluate(val)
|
101
134
|
src = val == :x ? :x : :k
|
102
135
|
val = 0 if val == :x
|
@@ -104,9 +137,19 @@ module SeccompTools
|
|
104
137
|
end
|
105
138
|
|
106
139
|
def compile_ret(val)
|
107
|
-
|
140
|
+
if val == :a
|
141
|
+
src = :a
|
142
|
+
val = 0
|
143
|
+
end
|
144
|
+
emit(:ret, src, k: val)
|
108
145
|
end
|
109
146
|
|
147
|
+
def compile_jmp_abs(target)
|
148
|
+
targ = label_offset(target)
|
149
|
+
emit(:jmp, :ja, k: targ)
|
150
|
+
end
|
151
|
+
|
152
|
+
# Compiles comparison.
|
110
153
|
def compile_cmp(op, val, jt, jf)
|
111
154
|
jt = label_offset(jt)
|
112
155
|
jf = label_offset(jf)
|
@@ -120,26 +163,48 @@ module SeccompTools
|
|
120
163
|
return label if label.is_a?(Integer)
|
121
164
|
return 0 if label == 'next'
|
122
165
|
raise ArgumentError, "Undefined label #{label.inspect}" if @labels[label].nil?
|
166
|
+
raise ArgumentError, "Does not support backward jumping to #{label.inspect}" if @labels[label] < @line
|
167
|
+
|
123
168
|
@labels[label] - @line - 1
|
124
169
|
end
|
125
170
|
|
126
171
|
def evaluate(val)
|
127
|
-
return val if val.is_a?(Integer) || val == :x
|
172
|
+
return val if val.is_a?(Integer) || val == :x || val == :a
|
173
|
+
|
128
174
|
# keywords
|
129
175
|
val = case val
|
130
176
|
when 'sys_number' then [:data, 0]
|
131
177
|
when 'arch' then [:data, 4]
|
178
|
+
when 'len' then [:len, 0]
|
132
179
|
else val
|
133
180
|
end
|
134
|
-
return
|
135
|
-
|
181
|
+
return eval_constants(val) if val.is_a?(String)
|
182
|
+
|
183
|
+
# remains are [:mem/:data/:args/:args_h, <num>]
|
136
184
|
# first convert args to data
|
137
185
|
val = [:data, val.last * 8 + 16] if val.first == :args
|
186
|
+
val = [:data, val.last * 8 + 20] if val.first == :args_h
|
138
187
|
val
|
139
188
|
end
|
140
189
|
|
190
|
+
def eval_constants(str)
|
191
|
+
Const::Syscall.const_get(@arch.upcase.to_sym)[str.to_sym] ||
|
192
|
+
Const::Audit::ARCH[str] ||
|
193
|
+
raise(ArgumentError, "Invalid constant: #{str.inspect}")
|
194
|
+
end
|
195
|
+
|
141
196
|
attr_reader :token
|
142
197
|
|
198
|
+
# <goto|jmp|jump> <label|Integer>
|
199
|
+
def jmp_abs
|
200
|
+
token.fetch('goto') ||
|
201
|
+
token.fetch('jmp') ||
|
202
|
+
token.fetch('jump') ||
|
203
|
+
raise(ArgumentError, "Invalid jump alias: #{token.cur.inspect}")
|
204
|
+
target = token.fetch!(:goto)
|
205
|
+
[:jmp_abs, target]
|
206
|
+
end
|
207
|
+
|
143
208
|
# A <comparison> <sys_str|X|Integer> ? <label|Integer> : <label|Integer>
|
144
209
|
def cmp
|
145
210
|
token.fetch!('A')
|
@@ -179,6 +244,7 @@ module SeccompTools
|
|
179
244
|
# A = mem[i]
|
180
245
|
# A = args[i]
|
181
246
|
# A = sys_number|arch
|
247
|
+
# A = len
|
182
248
|
def assign
|
183
249
|
dst = token.fetch!(:ax)
|
184
250
|
token.fetch!('=')
|
@@ -186,10 +252,17 @@ module SeccompTools
|
|
186
252
|
token.fetch(:sys_num_x) ||
|
187
253
|
token.fetch(:ary) ||
|
188
254
|
token.fetch('sys_number') ||
|
189
|
-
token.fetch('arch')
|
255
|
+
token.fetch('arch') ||
|
256
|
+
token.fetch('len') ||
|
257
|
+
raise(ArgumentError, "Invalid source: #{token.cur.inspect}")
|
190
258
|
[:assign, dst, src]
|
191
259
|
end
|
192
260
|
|
261
|
+
# returns same format as assign
|
262
|
+
def store
|
263
|
+
[:assign, token.fetch!(:ary), token.fetch!('=') && token.fetch!(:ax)]
|
264
|
+
end
|
265
|
+
|
193
266
|
def define_label
|
194
267
|
name = token.fetch!(:goto)
|
195
268
|
token.fetch(':')
|
@@ -205,6 +278,11 @@ module SeccompTools
|
|
205
278
|
[:alu, op, src]
|
206
279
|
end
|
207
280
|
|
281
|
+
# A = -A
|
282
|
+
def alu_neg
|
283
|
+
%i[alu neg]
|
284
|
+
end
|
285
|
+
|
208
286
|
def remove_comment(line)
|
209
287
|
line = line.to_s.dup
|
210
288
|
line.slice!(/#.*\Z/m)
|
@@ -213,7 +291,7 @@ module SeccompTools
|
|
213
291
|
|
214
292
|
def invalid(line, extra_msg = nil)
|
215
293
|
message = "Invalid instruction at line #{line + 1}: #{@input[line].inspect}"
|
216
|
-
message += "\
|
294
|
+
message += "\nError: #{extra_msg}" if extra_msg
|
217
295
|
raise ArgumentError, message
|
218
296
|
end
|
219
297
|
end
|
@@ -1,13 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'seccomp-tools/const'
|
2
4
|
require 'seccomp-tools/instruction/alu'
|
3
5
|
|
4
6
|
module SeccompTools
|
5
7
|
module Asm
|
6
|
-
# Fetch tokens from string.
|
7
|
-
#
|
8
|
+
# Fetch tokens from a string.
|
9
|
+
#
|
10
|
+
# Internal used by {Compiler}.
|
11
|
+
# @private
|
8
12
|
class Tokenizer
|
9
13
|
# a valid label
|
10
|
-
LABEL_REGEXP = /[
|
14
|
+
LABEL_REGEXP = /[A-Za-z_]\w*/.freeze
|
11
15
|
attr_accessor :cur
|
12
16
|
|
13
17
|
# @param [String] str
|
@@ -40,7 +44,7 @@ module SeccompTools
|
|
40
44
|
res = case type
|
41
45
|
when String then fetch_str(type) || raise_expected("token #{type.inspect}")
|
42
46
|
when :comparison then fetch_strs(COMPARISON).to_sym || raise_expected('a comparison operator')
|
43
|
-
when :sys_num_x then
|
47
|
+
when :sys_num_x then fetch_sys_num_arch_x || raise_expected("a syscall number or 'X'")
|
44
48
|
when :goto then fetch_number || fetch_label || raise_expected('a number or label name')
|
45
49
|
when :ret then fetch_return || raise(ArgumentError, <<-EOS)
|
46
50
|
Invalid return type: #{cur.inspect}.
|
@@ -64,6 +68,8 @@ Invalid return type: #{cur.inspect}.
|
|
64
68
|
|
65
69
|
def fetch_str(str)
|
66
70
|
return nil unless cur.start_with?(str)
|
71
|
+
return nil if str =~ /\A[A-Za-z0-9_]+\Z/ && cur[str.size] =~ /[A-Za-z0-9_]/
|
72
|
+
|
67
73
|
@last_match_size = str.size
|
68
74
|
str
|
69
75
|
end
|
@@ -71,18 +77,21 @@ Invalid return type: #{cur.inspect}.
|
|
71
77
|
def fetch_ax
|
72
78
|
return :a if fetch_str('A')
|
73
79
|
return :x if fetch_str('X')
|
80
|
+
|
74
81
|
nil
|
75
82
|
end
|
76
83
|
|
77
|
-
def
|
84
|
+
def fetch_sys_num_arch_x
|
78
85
|
return :x if fetch_str('X')
|
79
|
-
|
86
|
+
|
87
|
+
fetch_number || fetch_syscall || fetch_arch
|
80
88
|
end
|
81
89
|
|
82
90
|
# Currently only supports 10-based decimal numbers.
|
83
91
|
def fetch_number
|
84
92
|
res = fetch_regexp(/^0x[0-9a-f]+/) || fetch_regexp(/^[0-9]+/)
|
85
93
|
return nil if res.nil?
|
94
|
+
|
86
95
|
Integer(res)
|
87
96
|
end
|
88
97
|
|
@@ -92,9 +101,14 @@ Invalid return type: #{cur.inspect}.
|
|
92
101
|
fetch_strs(sys.keys.map(&:to_s).sort_by(&:size).reverse)
|
93
102
|
end
|
94
103
|
|
104
|
+
def fetch_arch
|
105
|
+
fetch_strs(Const::Audit::ARCH.keys)
|
106
|
+
end
|
107
|
+
|
95
108
|
def fetch_regexp(regexp)
|
96
109
|
idx = cur =~ regexp
|
97
110
|
return nil if idx.nil? || idx != 0
|
111
|
+
|
98
112
|
match = cur.match(regexp)[0]
|
99
113
|
@last_match_size = match.size
|
100
114
|
match
|
@@ -110,6 +124,7 @@ Invalid return type: #{cur.inspect}.
|
|
110
124
|
regexp = /(#{Const::BPF::ACTION.keys.join('|')})(\([0-9]{1,5}\))?/
|
111
125
|
action = fetch_regexp(regexp)
|
112
126
|
return fetch_str('A') && :a if action.nil?
|
127
|
+
|
113
128
|
# check if action contains '('the next bytes are (<num>)
|
114
129
|
ret_val = 0
|
115
130
|
if action.include?('(')
|
@@ -120,10 +135,11 @@ Invalid return type: #{cur.inspect}.
|
|
120
135
|
end
|
121
136
|
|
122
137
|
def fetch_ary
|
123
|
-
support_name = %w[data mem args]
|
138
|
+
support_name = %w[data mem args args_h]
|
124
139
|
regexp = /(#{support_name.join('|')})\[[0-9]{1,2}\]/
|
125
140
|
match = fetch_regexp(regexp)
|
126
141
|
return nil if match.nil?
|
142
|
+
|
127
143
|
res, val = match.split('[')
|
128
144
|
val = val.to_i
|
129
145
|
[res.to_sym, val]
|
@@ -133,6 +149,7 @@ Invalid return type: #{cur.inspect}.
|
|
133
149
|
ops = %w[+ - * / | & ^ << >>]
|
134
150
|
op = fetch_strs(ops)
|
135
151
|
return nil if op.nil?
|
152
|
+
|
136
153
|
Instruction::ALU::OP_SYM.invert[op.to_sym]
|
137
154
|
end
|
138
155
|
|
@@ -144,7 +161,7 @@ Invalid return type: #{cur.inspect}.
|
|
144
161
|
|
145
162
|
def raise_expected(msg)
|
146
163
|
raise ArgumentError, <<-EOS
|
147
|
-
Expected #{msg}
|
164
|
+
Expected #{msg} but found #{cur.split[0].inspect}.
|
148
165
|
EOS
|
149
166
|
end
|
150
167
|
end
|
data/lib/seccomp-tools/bpf.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'set'
|
4
|
+
require 'stringio'
|
2
5
|
|
3
6
|
require 'seccomp-tools/const'
|
4
7
|
require 'seccomp-tools/instruction/instruction'
|
@@ -30,11 +33,11 @@ module SeccompTools
|
|
30
33
|
# Line number of this filter.
|
31
34
|
def initialize(raw, arch, line)
|
32
35
|
if raw.is_a?(String)
|
33
|
-
io = StringIO.new(raw)
|
34
|
-
@code = io.read(2).
|
36
|
+
io = ::StringIO.new(raw)
|
37
|
+
@code = io.read(2).unpack1('S')
|
35
38
|
@jt = io.read(1).ord
|
36
39
|
@jf = io.read(1).ord
|
37
|
-
@k = io.read(4).
|
40
|
+
@k = io.read(4).unpack1('L')
|
38
41
|
else
|
39
42
|
@code = raw[:code]
|
40
43
|
@jt = raw[:jt]
|
@@ -77,7 +80,7 @@ module SeccompTools
|
|
77
80
|
# @param [Context] context
|
78
81
|
# Current context.
|
79
82
|
# @yieldparam [Integer] pc
|
80
|
-
# Program
|
83
|
+
# Program counter after this instruction.
|
81
84
|
# @yieldparam [Context] ctx
|
82
85
|
# Context after this instruction.
|
83
86
|
# @return [void]
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'seccomp-tools/cli/base'
|
2
4
|
require 'seccomp-tools/asm/asm'
|
3
5
|
|
@@ -6,9 +8,9 @@ module SeccompTools
|
|
6
8
|
# Handle 'asm' command.
|
7
9
|
class Asm < Base
|
8
10
|
# Summary of this command.
|
9
|
-
SUMMARY = 'Seccomp bpf assembler.'
|
11
|
+
SUMMARY = 'Seccomp bpf assembler.'
|
10
12
|
# Usage of this command.
|
11
|
-
USAGE =
|
13
|
+
USAGE = "asm - #{SUMMARY}\n\nUsage: seccomp-tools asm IN_FILE [options]"
|
12
14
|
|
13
15
|
def initialize(*)
|
14
16
|
super
|
@@ -24,8 +26,8 @@ module SeccompTools
|
|
24
26
|
option[:ofile] = o
|
25
27
|
end
|
26
28
|
|
27
|
-
opt.on('-f', '--format FORMAT', %i[inspect raw carray],
|
28
|
-
'Output format. FORMAT can only be one of <inspect|raw|
|
29
|
+
opt.on('-f', '--format FORMAT', %i[inspect raw c_array carray c_source assembly],
|
30
|
+
'Output format. FORMAT can only be one of <inspect|raw|c_array|c_source|assembly>.',
|
29
31
|
'Default: inspect') do |f|
|
30
32
|
option[:format] = f
|
31
33
|
end
|
@@ -38,14 +40,22 @@ module SeccompTools
|
|
38
40
|
# @return [void]
|
39
41
|
def handle
|
40
42
|
return unless super
|
43
|
+
|
41
44
|
option[:ifile] = argv.shift
|
42
45
|
return CLI.show(parser.help) if option[:ifile].nil?
|
46
|
+
|
43
47
|
res = SeccompTools::Asm.asm(input, arch: option[:arch])
|
44
48
|
output do
|
45
49
|
case option[:format]
|
46
|
-
when :inspect then res.inspect
|
50
|
+
when :inspect then "#{res.inspect}\n"
|
47
51
|
when :raw then res
|
48
|
-
when :carray then "unsigned char bpf[] = {#{res.bytes.join(',')}};\n"
|
52
|
+
when :c_array, :carray then "unsigned char bpf[] = {#{res.bytes.join(',')}};\n"
|
53
|
+
when :c_source then SeccompTools::Util.template('asm.c').sub('<TO_BE_REPLACED>', res.bytes.join(','))
|
54
|
+
when :assembly
|
55
|
+
SeccompTools::Util.template("asm.#{option[:arch]}.asm").sub(
|
56
|
+
'<TO_BE_REPLACED>',
|
57
|
+
res.bytes.map { |b| format('\\\%03o', b) }.join
|
58
|
+
)
|
49
59
|
end
|
50
60
|
end
|
51
61
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'optparse'
|
2
4
|
|
3
5
|
require 'seccomp-tools/util'
|
@@ -23,10 +25,12 @@ module SeccompTools
|
|
23
25
|
|
24
26
|
# Handle show help message.
|
25
27
|
# @return [Boolean]
|
26
|
-
# For decestors to check if
|
28
|
+
# For decestors to check if need to continue.
|
27
29
|
def handle
|
28
30
|
return CLI.show(parser.help) if argv.empty? || %w[-h --help].any? { |h| argv.include?(h) }
|
31
|
+
|
29
32
|
parser.parse!(argv)
|
33
|
+
option[:arch] ||= Util.system_arch
|
30
34
|
true
|
31
35
|
end
|
32
36
|
|
@@ -35,7 +39,7 @@ module SeccompTools
|
|
35
39
|
# @return [String]
|
36
40
|
# String read from file.
|
37
41
|
def input
|
38
|
-
option[:ifile] == '-' ?
|
42
|
+
option[:ifile] == '-' ? $stdin.read.force_encoding('ascii-8bit') : IO.binread(option[:ifile])
|
39
43
|
end
|
40
44
|
|
41
45
|
# Write data to stdout or file(s).
|
@@ -45,6 +49,7 @@ module SeccompTools
|
|
45
49
|
def output
|
46
50
|
# if file name not present, just output to stdout.
|
47
51
|
return $stdout.write(yield) if option[:ofile].nil?
|
52
|
+
|
48
53
|
# times of calling output
|
49
54
|
@serial ||= 0
|
50
55
|
# Write to file, we should disable colorize
|
@@ -77,7 +82,7 @@ module SeccompTools
|
|
77
82
|
File.join(File.dirname(file), base + suffix) + ext
|
78
83
|
end
|
79
84
|
|
80
|
-
# For
|
85
|
+
# For descendants to define usage message easily.
|
81
86
|
# @return [String]
|
82
87
|
# Usage information.
|
83
88
|
def usage
|
@@ -87,7 +92,8 @@ module SeccompTools
|
|
87
92
|
def option_arch(opt)
|
88
93
|
supported = Util.supported_archs
|
89
94
|
opt.on('-a', '--arch ARCH', supported, 'Specify architecture.',
|
90
|
-
"Supported architectures are <#{supported.join('|')}>."
|
95
|
+
"Supported architectures are <#{supported.join('|')}>.",
|
96
|
+
"Default: #{Util.system_arch}") do |a|
|
91
97
|
option[:arch] = a
|
92
98
|
end
|
93
99
|
end
|