seccomp-tools 1.6.1 → 1.7.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 +4 -4
- data/CHANGELOG.md +153 -0
- data/LICENSE +21 -0
- data/README.md +267 -46
- data/completions/_seccomp-tools +83 -0
- data/completions/seccomp-tools.bash +59 -0
- data/completions/seccomp-tools.fish +52 -0
- data/ext/ptrace/ptrace.c +2 -2
- data/lib/seccomp-tools/asm/asm.rb +9 -4
- data/lib/seccomp-tools/asm/compiler.rb +39 -9
- data/lib/seccomp-tools/asm/sasm.tab.rb +31 -21
- data/lib/seccomp-tools/asm/sasm.y +15 -7
- data/lib/seccomp-tools/asm/scalar.rb +50 -7
- data/lib/seccomp-tools/asm/scanner.rb +40 -8
- data/lib/seccomp-tools/asm/statement.rb +14 -5
- data/lib/seccomp-tools/asm/token.rb +19 -1
- data/lib/seccomp-tools/audit/catalog.rb +66 -0
- data/lib/seccomp-tools/audit/checks/arch_unchecked.rb +41 -0
- data/lib/seccomp-tools/audit/checks/dangerous_allow.rb +34 -0
- data/lib/seccomp-tools/audit/checks/orw_chain.rb +41 -0
- data/lib/seccomp-tools/audit/checks/permissive_default.rb +29 -0
- data/lib/seccomp-tools/audit/checks/syscall_alt_gap.rb +44 -0
- data/lib/seccomp-tools/audit/checks/x32_guard.rb +46 -0
- data/lib/seccomp-tools/audit/checks.rb +42 -0
- data/lib/seccomp-tools/audit/finding.rb +25 -0
- data/lib/seccomp-tools/audit/policy.rb +126 -0
- data/lib/seccomp-tools/audit/report.rb +98 -0
- data/lib/seccomp-tools/audit.rb +48 -0
- data/lib/seccomp-tools/bpf.rb +27 -17
- data/lib/seccomp-tools/cli/asm.rb +7 -3
- data/lib/seccomp-tools/cli/audit.rb +86 -0
- data/lib/seccomp-tools/cli/base.rb +51 -8
- data/lib/seccomp-tools/cli/cli.rb +10 -6
- data/lib/seccomp-tools/cli/completion.rb +40 -0
- data/lib/seccomp-tools/cli/disasm.rb +10 -6
- data/lib/seccomp-tools/cli/dump.rb +37 -52
- data/lib/seccomp-tools/cli/dumpable.rb +79 -0
- data/lib/seccomp-tools/cli/emu.rb +32 -9
- data/lib/seccomp-tools/cli/explain.rb +51 -0
- data/lib/seccomp-tools/cli/filter_input.rb +130 -0
- data/lib/seccomp-tools/const.rb +98 -15
- data/lib/seccomp-tools/consts/sys_nr/amd64.rb +1 -1
- data/lib/seccomp-tools/consts/sys_nr/riscv64.rb +332 -0
- data/lib/seccomp-tools/disasm/disasm.rb +31 -13
- data/lib/seccomp-tools/dumper.rb +67 -35
- data/lib/seccomp-tools/emulator.rb +41 -16
- data/lib/seccomp-tools/error.rb +4 -2
- data/lib/seccomp-tools/explain/analysis.rb +67 -0
- data/lib/seccomp-tools/explain/path_facts.rb +110 -0
- data/lib/seccomp-tools/explain/qword.rb +204 -0
- data/lib/seccomp-tools/explain/renderer.rb +128 -0
- data/lib/seccomp-tools/explain/summary.rb +218 -0
- data/lib/seccomp-tools/explain/verdict.rb +44 -0
- data/lib/seccomp-tools/explain.rb +38 -0
- data/lib/seccomp-tools/instruction/alu.rb +14 -9
- data/lib/seccomp-tools/instruction/base.rb +39 -10
- data/lib/seccomp-tools/instruction/jmp.rb +50 -23
- data/lib/seccomp-tools/instruction/ld.rb +46 -21
- data/lib/seccomp-tools/instruction/ldx.rb +4 -3
- data/lib/seccomp-tools/instruction/misc.rb +11 -9
- data/lib/seccomp-tools/instruction/ret.rb +12 -6
- data/lib/seccomp-tools/instruction/st.rb +15 -6
- data/lib/seccomp-tools/instruction/stx.rb +4 -3
- data/lib/seccomp-tools/logger.rb +15 -2
- data/lib/seccomp-tools/symbolic/constraint.rb +80 -0
- data/lib/seccomp-tools/symbolic/executor.rb +210 -0
- data/lib/seccomp-tools/symbolic/expr.rb +185 -0
- data/lib/seccomp-tools/symbolic/state.rb +82 -0
- data/lib/seccomp-tools/syscall.rb +74 -22
- data/lib/seccomp-tools/util.rb +70 -11
- data/lib/seccomp-tools/version.rb +1 -1
- data/lib/seccomp-tools.rb +10 -1
- metadata +83 -11
- data/lib/seccomp-tools/disasm/context.rb +0 -171
data/lib/seccomp-tools/const.rb
CHANGED
|
@@ -5,15 +5,48 @@ module SeccompTools
|
|
|
5
5
|
module Const
|
|
6
6
|
# For BPF / seccomp.
|
|
7
7
|
module BPF
|
|
8
|
+
# Byte offsets of the fields of the filter's input buffer:
|
|
9
|
+
# struct seccomp_data {
|
|
10
|
+
# int nr; // SYS_NUMBER
|
|
11
|
+
# __u32 arch; // ARCH
|
|
12
|
+
# __u64 instruction_pointer; // INSTRUCTION_POINTER
|
|
13
|
+
# __u64 args[6]; // ARGS
|
|
14
|
+
# };
|
|
15
|
+
# The 64-bit fields are each two 32-bit words a filter loads separately (see {QWORD_BASES}).
|
|
16
|
+
module SeccompData
|
|
17
|
+
# Byte offset of the syscall number.
|
|
18
|
+
SYS_NUMBER = 0
|
|
19
|
+
# Byte offset of the architecture.
|
|
20
|
+
ARCH = 4
|
|
21
|
+
# Byte offset of the instruction pointer.
|
|
22
|
+
INSTRUCTION_POINTER = 8
|
|
23
|
+
# Byte offset of the first 64-bit argument.
|
|
24
|
+
ARGS = 16
|
|
25
|
+
# Total size in bytes; the +len+ load returns this.
|
|
26
|
+
SIZE = 64
|
|
27
|
+
# Byte offsets of the 64-bit fields (+instruction_pointer+ and the six arguments), each a
|
|
28
|
+
# pair of 32-bit words.
|
|
29
|
+
QWORD_BASES = [INSTRUCTION_POINTER, *(ARGS...SIZE).step(8)].freeze
|
|
30
|
+
# Display names of the fixed (non-argument) fields, keyed by byte offset. For the 64-bit
|
|
31
|
+
# +instruction_pointer+ this is the field's base name; a high-word load appends +>> 32+.
|
|
32
|
+
NAMES = { SYS_NUMBER => 'sys_number', ARCH => 'arch', INSTRUCTION_POINTER => 'instruction_pointer' }.freeze
|
|
33
|
+
end
|
|
34
|
+
|
|
8
35
|
# sizeof(struct seccomp_data)
|
|
9
|
-
SIZEOF_SECCOMP_DATA =
|
|
36
|
+
SIZEOF_SECCOMP_DATA = SeccompData::SIZE
|
|
10
37
|
|
|
11
38
|
# option set seccomp
|
|
12
39
|
PR_SET_SECCOMP = 22
|
|
13
40
|
|
|
41
|
+
# strict mode
|
|
42
|
+
SECCOMP_MODE_STRICT = 1
|
|
43
|
+
|
|
14
44
|
# filter mode
|
|
15
45
|
SECCOMP_MODE_FILTER = 2
|
|
16
46
|
|
|
47
|
+
# For syscall +seccomp+
|
|
48
|
+
SECCOMP_SET_MODE_STRICT = 0
|
|
49
|
+
|
|
17
50
|
# For syscall +seccomp+
|
|
18
51
|
SECCOMP_SET_MODE_FILTER = 1
|
|
19
52
|
|
|
@@ -86,7 +119,8 @@ module SeccompTools
|
|
|
86
119
|
lsh: 0x60,
|
|
87
120
|
rsh: 0x70,
|
|
88
121
|
neg: 0x80,
|
|
89
|
-
# mod
|
|
122
|
+
# mod (0x90) is intentionally omitted: the kernel's seccomp_check_filter() allowlist rejects
|
|
123
|
+
# BPF_MOD (EINVAL), so it can never appear in a loadable seccomp filter.
|
|
90
124
|
xor: 0xa0
|
|
91
125
|
}.freeze
|
|
92
126
|
|
|
@@ -95,6 +129,24 @@ module SeccompTools
|
|
|
95
129
|
tax: 0x00,
|
|
96
130
|
txa: 0x80
|
|
97
131
|
}.freeze
|
|
132
|
+
|
|
133
|
+
# The action a seccomp return +value+ names, e.g. +"ALLOW"+ or +"ERRNO(5)"+, or +nil+ when
|
|
134
|
+
# the action bits are not a value the kernel defines. The data part is shown for the actions
|
|
135
|
+
# that consume it: +ERRNO+ always, and +TRACE+/+TRAP+ when non-zero (0 is their idle default).
|
|
136
|
+
# The result is both human-readable and re-assemblable.
|
|
137
|
+
# @param [Integer] value
|
|
138
|
+
# @return [String?]
|
|
139
|
+
def self.action_label(value)
|
|
140
|
+
action = ACTION.invert[value & SECCOMP_RET_ACTION_FULL]
|
|
141
|
+
return if action.nil?
|
|
142
|
+
|
|
143
|
+
data = value & SECCOMP_RET_DATA
|
|
144
|
+
case action
|
|
145
|
+
when :ERRNO then "ERRNO(#{data})"
|
|
146
|
+
when :TRACE, :TRAP then data.zero? ? action.to_s : "#{action}(#{data})"
|
|
147
|
+
else action.to_s
|
|
148
|
+
end
|
|
149
|
+
end
|
|
98
150
|
end
|
|
99
151
|
|
|
100
152
|
# Define syscall numbers for all architectures.
|
|
@@ -104,17 +156,21 @@ module SeccompTools
|
|
|
104
156
|
|
|
105
157
|
# To dynamically fetch constants from files.
|
|
106
158
|
# @param [Symbol] cons
|
|
107
|
-
# Name of const
|
|
108
|
-
# @return [
|
|
109
|
-
#
|
|
159
|
+
# Name of const, an upcased architecture name such as +:AMD64+.
|
|
160
|
+
# @return [{Symbol => Integer}]
|
|
161
|
+
# The syscall table of that architecture, mapping name to number.
|
|
162
|
+
# @raise [NameError]
|
|
163
|
+
# If no syscall table exists for +cons+.
|
|
110
164
|
def const_missing(cons)
|
|
111
165
|
load_const(cons) || super
|
|
112
166
|
end
|
|
113
167
|
|
|
114
168
|
# Load from file and define const value.
|
|
115
169
|
# @param [Symbol] cons
|
|
116
|
-
# Name of const
|
|
117
|
-
# @return [
|
|
170
|
+
# Name of const, an upcased architecture name such as +:AMD64+.
|
|
171
|
+
# @return [{Symbol => Integer}?]
|
|
172
|
+
# The syscall table of that architecture, or +nil+ if it has no file under
|
|
173
|
+
# +consts/sys_nr/+.
|
|
118
174
|
def load_const(cons)
|
|
119
175
|
arch = cons.to_s.downcase
|
|
120
176
|
filename = File.join(__dir__, 'consts', 'sys_nr', "#{arch}.rb")
|
|
@@ -124,6 +180,10 @@ module SeccompTools
|
|
|
124
180
|
end
|
|
125
181
|
|
|
126
182
|
# Helper for loading syscall prototypes from generated sys_arg.rb.
|
|
183
|
+
#
|
|
184
|
+
# @return [{Symbol => Array<String>}]
|
|
185
|
+
# Syscall name to its argument names. Lookups of an +x32_+-prefixed name fall back to the
|
|
186
|
+
# unprefixed one, and unknown names give +nil+.
|
|
127
187
|
def load_args
|
|
128
188
|
hash = instance_eval(File.read(File.join(__dir__, 'consts', 'sys_arg.rb')))
|
|
129
189
|
Hash.new do |_h, k|
|
|
@@ -145,6 +205,7 @@ module SeccompTools
|
|
|
145
205
|
amd64: 'ARCH_X86_64',
|
|
146
206
|
i386: 'ARCH_I386',
|
|
147
207
|
aarch64: 'ARCH_AARCH64',
|
|
208
|
+
riscv64: 'ARCH_RISCV64',
|
|
148
209
|
s390x: 'ARCH_S390X'
|
|
149
210
|
}.freeze
|
|
150
211
|
|
|
@@ -153,19 +214,41 @@ module SeccompTools
|
|
|
153
214
|
'ARCH_X86_64' => 0xc000003e,
|
|
154
215
|
'ARCH_I386' => 0x40000003,
|
|
155
216
|
'ARCH_AARCH64' => 0xc00000b7,
|
|
217
|
+
'ARCH_RISCV64' => 0xc00000f3,
|
|
156
218
|
'ARCH_S390X' => 0x80000016
|
|
157
219
|
}.freeze
|
|
220
|
+
|
|
221
|
+
# The architecture symbol (e.g. +:amd64+) for an +AUDIT_ARCH_*+ value, or +nil+ when it is
|
|
222
|
+
# not one seccomp-tools knows.
|
|
223
|
+
# @param [Integer] audit_val
|
|
224
|
+
# @return [Symbol?]
|
|
225
|
+
def self.arch_symbol(audit_val)
|
|
226
|
+
name = ARCH.invert[audit_val]
|
|
227
|
+
name && ARCH_NAME.invert[name]
|
|
228
|
+
end
|
|
158
229
|
end
|
|
159
230
|
|
|
160
|
-
#
|
|
231
|
+
# Endianness constants.
|
|
161
232
|
module Endian
|
|
162
|
-
#
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}.
|
|
233
|
+
# +__AUDIT_ARCH_LE+ from +uapi/linux/audit.h+: the bit an +AUDIT_ARCH_*+ value carries iff
|
|
234
|
+
# the architecture is little-endian. The kernel encodes endianness in the arch token itself,
|
|
235
|
+
# so it never needs to be guessed from an architecture's name.
|
|
236
|
+
AUDIT_ARCH_LE = 0x40000000
|
|
237
|
+
|
|
238
|
+
# Endianness of each architecture as a pack/unpack format modifier, derived from the
|
|
239
|
+
# {Audit::ARCH} values instead of being maintained by hand.
|
|
240
|
+
ENDIAN = Audit::ARCH_NAME.transform_values do |name|
|
|
241
|
+
Audit::ARCH[name].anybits?(AUDIT_ARCH_LE) ? '<' : '>'
|
|
242
|
+
end.freeze
|
|
243
|
+
|
|
244
|
+
# Whether +arch+ is big-endian, i.e. stores the high 32-bit word of a 64-bit +seccomp_data+
|
|
245
|
+
# field (+instruction_pointer+ or an argument) first. See +arch_arg_offset_lo/hi+ in
|
|
246
|
+
# libseccomp and the +syscall_arg+ macro of the kernel's seccomp selftests.
|
|
247
|
+
# @param [Symbol] arch
|
|
248
|
+
# @return [Boolean]
|
|
249
|
+
def self.big?(arch)
|
|
250
|
+
ENDIAN[arch] == '>'
|
|
251
|
+
end
|
|
169
252
|
end
|
|
170
253
|
end
|
|
171
254
|
end
|
|
@@ -338,4 +338,4 @@ X32_MODE_BIT = 0x40000000
|
|
|
338
338
|
pkey_alloc: 330,
|
|
339
339
|
pkey_free: 331,
|
|
340
340
|
statx: 332
|
|
341
|
-
}.tap { |h| h.keys.each { |k| h["x32_#{k}"
|
|
341
|
+
}.tap { |h| h.keys.each { |k| h[:"x32_#{k}"] = h[k] | X32_MODE_BIT } }
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
{
|
|
4
|
+
io_setup: 0,
|
|
5
|
+
io_destroy: 1,
|
|
6
|
+
io_submit: 2,
|
|
7
|
+
io_cancel: 3,
|
|
8
|
+
io_getevents: 4,
|
|
9
|
+
setxattr: 5,
|
|
10
|
+
lsetxattr: 6,
|
|
11
|
+
fsetxattr: 7,
|
|
12
|
+
getxattr: 8,
|
|
13
|
+
lgetxattr: 9,
|
|
14
|
+
fgetxattr: 10,
|
|
15
|
+
listxattr: 11,
|
|
16
|
+
llistxattr: 12,
|
|
17
|
+
flistxattr: 13,
|
|
18
|
+
removexattr: 14,
|
|
19
|
+
lremovexattr: 15,
|
|
20
|
+
fremovexattr: 16,
|
|
21
|
+
getcwd: 17,
|
|
22
|
+
lookup_dcookie: 18,
|
|
23
|
+
eventfd2: 19,
|
|
24
|
+
epoll_create1: 20,
|
|
25
|
+
epoll_ctl: 21,
|
|
26
|
+
epoll_pwait: 22,
|
|
27
|
+
dup: 23,
|
|
28
|
+
dup3: 24,
|
|
29
|
+
fcntl: 25,
|
|
30
|
+
inotify_init1: 26,
|
|
31
|
+
inotify_add_watch: 27,
|
|
32
|
+
inotify_rm_watch: 28,
|
|
33
|
+
ioctl: 29,
|
|
34
|
+
ioprio_set: 30,
|
|
35
|
+
ioprio_get: 31,
|
|
36
|
+
flock: 32,
|
|
37
|
+
mknodat: 33,
|
|
38
|
+
mkdirat: 34,
|
|
39
|
+
unlinkat: 35,
|
|
40
|
+
symlinkat: 36,
|
|
41
|
+
linkat: 37,
|
|
42
|
+
umount2: 39,
|
|
43
|
+
mount: 40,
|
|
44
|
+
pivot_root: 41,
|
|
45
|
+
nfsservctl: 42,
|
|
46
|
+
statfs: 43,
|
|
47
|
+
fstatfs: 44,
|
|
48
|
+
truncate: 45,
|
|
49
|
+
ftruncate: 46,
|
|
50
|
+
fallocate: 47,
|
|
51
|
+
faccessat: 48,
|
|
52
|
+
chdir: 49,
|
|
53
|
+
fchdir: 50,
|
|
54
|
+
chroot: 51,
|
|
55
|
+
fchmod: 52,
|
|
56
|
+
fchmodat: 53,
|
|
57
|
+
fchownat: 54,
|
|
58
|
+
fchown: 55,
|
|
59
|
+
openat: 56,
|
|
60
|
+
close: 57,
|
|
61
|
+
vhangup: 58,
|
|
62
|
+
pipe2: 59,
|
|
63
|
+
quotactl: 60,
|
|
64
|
+
getdents64: 61,
|
|
65
|
+
lseek: 62,
|
|
66
|
+
read: 63,
|
|
67
|
+
write: 64,
|
|
68
|
+
readv: 65,
|
|
69
|
+
writev: 66,
|
|
70
|
+
pread64: 67,
|
|
71
|
+
pwrite64: 68,
|
|
72
|
+
preadv: 69,
|
|
73
|
+
pwritev: 70,
|
|
74
|
+
sendfile: 71,
|
|
75
|
+
pselect6: 72,
|
|
76
|
+
ppoll: 73,
|
|
77
|
+
signalfd4: 74,
|
|
78
|
+
vmsplice: 75,
|
|
79
|
+
splice: 76,
|
|
80
|
+
tee: 77,
|
|
81
|
+
readlinkat: 78,
|
|
82
|
+
newfstatat: 79,
|
|
83
|
+
fstat: 80,
|
|
84
|
+
sync: 81,
|
|
85
|
+
fsync: 82,
|
|
86
|
+
fdatasync: 83,
|
|
87
|
+
sync_file_range: 84,
|
|
88
|
+
timerfd_create: 85,
|
|
89
|
+
timerfd_settime: 86,
|
|
90
|
+
timerfd_gettime: 87,
|
|
91
|
+
utimensat: 88,
|
|
92
|
+
acct: 89,
|
|
93
|
+
capget: 90,
|
|
94
|
+
capset: 91,
|
|
95
|
+
personality: 92,
|
|
96
|
+
exit: 93,
|
|
97
|
+
exit_group: 94,
|
|
98
|
+
waitid: 95,
|
|
99
|
+
set_tid_address: 96,
|
|
100
|
+
unshare: 97,
|
|
101
|
+
futex: 98,
|
|
102
|
+
set_robust_list: 99,
|
|
103
|
+
get_robust_list: 100,
|
|
104
|
+
nanosleep: 101,
|
|
105
|
+
getitimer: 102,
|
|
106
|
+
setitimer: 103,
|
|
107
|
+
kexec_load: 104,
|
|
108
|
+
init_module: 105,
|
|
109
|
+
delete_module: 106,
|
|
110
|
+
timer_create: 107,
|
|
111
|
+
timer_gettime: 108,
|
|
112
|
+
timer_getoverrun: 109,
|
|
113
|
+
timer_settime: 110,
|
|
114
|
+
timer_delete: 111,
|
|
115
|
+
clock_settime: 112,
|
|
116
|
+
clock_gettime: 113,
|
|
117
|
+
clock_getres: 114,
|
|
118
|
+
clock_nanosleep: 115,
|
|
119
|
+
syslog: 116,
|
|
120
|
+
ptrace: 117,
|
|
121
|
+
sched_setparam: 118,
|
|
122
|
+
sched_setscheduler: 119,
|
|
123
|
+
sched_getscheduler: 120,
|
|
124
|
+
sched_getparam: 121,
|
|
125
|
+
sched_setaffinity: 122,
|
|
126
|
+
sched_getaffinity: 123,
|
|
127
|
+
sched_yield: 124,
|
|
128
|
+
sched_get_priority_max: 125,
|
|
129
|
+
sched_get_priority_min: 126,
|
|
130
|
+
sched_rr_get_interval: 127,
|
|
131
|
+
restart_syscall: 128,
|
|
132
|
+
kill: 129,
|
|
133
|
+
tkill: 130,
|
|
134
|
+
tgkill: 131,
|
|
135
|
+
sigaltstack: 132,
|
|
136
|
+
rt_sigsuspend: 133,
|
|
137
|
+
rt_sigaction: 134,
|
|
138
|
+
rt_sigprocmask: 135,
|
|
139
|
+
rt_sigpending: 136,
|
|
140
|
+
rt_sigtimedwait: 137,
|
|
141
|
+
rt_sigqueueinfo: 138,
|
|
142
|
+
rt_sigreturn: 139,
|
|
143
|
+
setpriority: 140,
|
|
144
|
+
getpriority: 141,
|
|
145
|
+
reboot: 142,
|
|
146
|
+
setregid: 143,
|
|
147
|
+
setgid: 144,
|
|
148
|
+
setreuid: 145,
|
|
149
|
+
setuid: 146,
|
|
150
|
+
setresuid: 147,
|
|
151
|
+
getresuid: 148,
|
|
152
|
+
setresgid: 149,
|
|
153
|
+
getresgid: 150,
|
|
154
|
+
setfsuid: 151,
|
|
155
|
+
setfsgid: 152,
|
|
156
|
+
times: 153,
|
|
157
|
+
setpgid: 154,
|
|
158
|
+
getpgid: 155,
|
|
159
|
+
getsid: 156,
|
|
160
|
+
setsid: 157,
|
|
161
|
+
getgroups: 158,
|
|
162
|
+
setgroups: 159,
|
|
163
|
+
uname: 160,
|
|
164
|
+
sethostname: 161,
|
|
165
|
+
setdomainname: 162,
|
|
166
|
+
getrlimit: 163,
|
|
167
|
+
setrlimit: 164,
|
|
168
|
+
getrusage: 165,
|
|
169
|
+
umask: 166,
|
|
170
|
+
prctl: 167,
|
|
171
|
+
getcpu: 168,
|
|
172
|
+
gettimeofday: 169,
|
|
173
|
+
settimeofday: 170,
|
|
174
|
+
adjtimex: 171,
|
|
175
|
+
getpid: 172,
|
|
176
|
+
getppid: 173,
|
|
177
|
+
getuid: 174,
|
|
178
|
+
geteuid: 175,
|
|
179
|
+
getgid: 176,
|
|
180
|
+
getegid: 177,
|
|
181
|
+
gettid: 178,
|
|
182
|
+
sysinfo: 179,
|
|
183
|
+
mq_open: 180,
|
|
184
|
+
mq_unlink: 181,
|
|
185
|
+
mq_timedsend: 182,
|
|
186
|
+
mq_timedreceive: 183,
|
|
187
|
+
mq_notify: 184,
|
|
188
|
+
mq_getsetattr: 185,
|
|
189
|
+
msgget: 186,
|
|
190
|
+
msgctl: 187,
|
|
191
|
+
msgrcv: 188,
|
|
192
|
+
msgsnd: 189,
|
|
193
|
+
semget: 190,
|
|
194
|
+
semctl: 191,
|
|
195
|
+
semtimedop: 192,
|
|
196
|
+
semop: 193,
|
|
197
|
+
shmget: 194,
|
|
198
|
+
shmctl: 195,
|
|
199
|
+
shmat: 196,
|
|
200
|
+
shmdt: 197,
|
|
201
|
+
socket: 198,
|
|
202
|
+
socketpair: 199,
|
|
203
|
+
bind: 200,
|
|
204
|
+
listen: 201,
|
|
205
|
+
accept: 202,
|
|
206
|
+
connect: 203,
|
|
207
|
+
getsockname: 204,
|
|
208
|
+
getpeername: 205,
|
|
209
|
+
sendto: 206,
|
|
210
|
+
recvfrom: 207,
|
|
211
|
+
setsockopt: 208,
|
|
212
|
+
getsockopt: 209,
|
|
213
|
+
shutdown: 210,
|
|
214
|
+
sendmsg: 211,
|
|
215
|
+
recvmsg: 212,
|
|
216
|
+
readahead: 213,
|
|
217
|
+
brk: 214,
|
|
218
|
+
munmap: 215,
|
|
219
|
+
mremap: 216,
|
|
220
|
+
add_key: 217,
|
|
221
|
+
request_key: 218,
|
|
222
|
+
keyctl: 219,
|
|
223
|
+
clone: 220,
|
|
224
|
+
execve: 221,
|
|
225
|
+
mmap: 222,
|
|
226
|
+
fadvise64: 223,
|
|
227
|
+
swapon: 224,
|
|
228
|
+
swapoff: 225,
|
|
229
|
+
mprotect: 226,
|
|
230
|
+
msync: 227,
|
|
231
|
+
mlock: 228,
|
|
232
|
+
munlock: 229,
|
|
233
|
+
mlockall: 230,
|
|
234
|
+
munlockall: 231,
|
|
235
|
+
mincore: 232,
|
|
236
|
+
madvise: 233,
|
|
237
|
+
remap_file_pages: 234,
|
|
238
|
+
mbind: 235,
|
|
239
|
+
get_mempolicy: 236,
|
|
240
|
+
set_mempolicy: 237,
|
|
241
|
+
migrate_pages: 238,
|
|
242
|
+
move_pages: 239,
|
|
243
|
+
rt_tgsigqueueinfo: 240,
|
|
244
|
+
perf_event_open: 241,
|
|
245
|
+
accept4: 242,
|
|
246
|
+
recvmmsg: 243,
|
|
247
|
+
riscv_hwprobe: 258,
|
|
248
|
+
riscv_flush_icache: 259,
|
|
249
|
+
wait4: 260,
|
|
250
|
+
prlimit64: 261,
|
|
251
|
+
fanotify_init: 262,
|
|
252
|
+
fanotify_mark: 263,
|
|
253
|
+
name_to_handle_at: 264,
|
|
254
|
+
open_by_handle_at: 265,
|
|
255
|
+
clock_adjtime: 266,
|
|
256
|
+
syncfs: 267,
|
|
257
|
+
setns: 268,
|
|
258
|
+
sendmmsg: 269,
|
|
259
|
+
process_vm_readv: 270,
|
|
260
|
+
process_vm_writev: 271,
|
|
261
|
+
kcmp: 272,
|
|
262
|
+
finit_module: 273,
|
|
263
|
+
sched_setattr: 274,
|
|
264
|
+
sched_getattr: 275,
|
|
265
|
+
renameat2: 276,
|
|
266
|
+
seccomp: 277,
|
|
267
|
+
getrandom: 278,
|
|
268
|
+
memfd_create: 279,
|
|
269
|
+
bpf: 280,
|
|
270
|
+
execveat: 281,
|
|
271
|
+
userfaultfd: 282,
|
|
272
|
+
membarrier: 283,
|
|
273
|
+
mlock2: 284,
|
|
274
|
+
copy_file_range: 285,
|
|
275
|
+
preadv2: 286,
|
|
276
|
+
pwritev2: 287,
|
|
277
|
+
pkey_mprotect: 288,
|
|
278
|
+
pkey_alloc: 289,
|
|
279
|
+
pkey_free: 290,
|
|
280
|
+
statx: 291,
|
|
281
|
+
io_pgetevents: 292,
|
|
282
|
+
rseq: 293,
|
|
283
|
+
kexec_file_load: 294,
|
|
284
|
+
pidfd_send_signal: 424,
|
|
285
|
+
io_uring_setup: 425,
|
|
286
|
+
io_uring_enter: 426,
|
|
287
|
+
io_uring_register: 427,
|
|
288
|
+
open_tree: 428,
|
|
289
|
+
move_mount: 429,
|
|
290
|
+
fsopen: 430,
|
|
291
|
+
fsconfig: 431,
|
|
292
|
+
fsmount: 432,
|
|
293
|
+
fspick: 433,
|
|
294
|
+
pidfd_open: 434,
|
|
295
|
+
clone3: 435,
|
|
296
|
+
close_range: 436,
|
|
297
|
+
openat2: 437,
|
|
298
|
+
pidfd_getfd: 438,
|
|
299
|
+
faccessat2: 439,
|
|
300
|
+
process_madvise: 440,
|
|
301
|
+
epoll_pwait2: 441,
|
|
302
|
+
mount_setattr: 442,
|
|
303
|
+
quotactl_fd: 443,
|
|
304
|
+
landlock_create_ruleset: 444,
|
|
305
|
+
landlock_add_rule: 445,
|
|
306
|
+
landlock_restrict_self: 446,
|
|
307
|
+
memfd_secret: 447,
|
|
308
|
+
process_mrelease: 448,
|
|
309
|
+
futex_waitv: 449,
|
|
310
|
+
set_mempolicy_home_node: 450,
|
|
311
|
+
cachestat: 451,
|
|
312
|
+
fchmodat2: 452,
|
|
313
|
+
map_shadow_stack: 453,
|
|
314
|
+
futex_wake: 454,
|
|
315
|
+
futex_wait: 455,
|
|
316
|
+
futex_requeue: 456,
|
|
317
|
+
statmount: 457,
|
|
318
|
+
listmount: 458,
|
|
319
|
+
lsm_get_self_attr: 459,
|
|
320
|
+
lsm_set_self_attr: 460,
|
|
321
|
+
lsm_list_modules: 461,
|
|
322
|
+
mseal: 462,
|
|
323
|
+
setxattrat: 463,
|
|
324
|
+
getxattrat: 464,
|
|
325
|
+
listxattrat: 465,
|
|
326
|
+
removexattrat: 466,
|
|
327
|
+
open_tree_attr: 467,
|
|
328
|
+
file_getattr: 468,
|
|
329
|
+
file_setattr: 469,
|
|
330
|
+
listns: 470,
|
|
331
|
+
rseq_slice_yield: 471
|
|
332
|
+
}
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
require 'set'
|
|
4
4
|
|
|
5
5
|
require 'seccomp-tools/bpf'
|
|
6
|
-
require 'seccomp-tools/
|
|
6
|
+
require 'seccomp-tools/symbolic/constraint'
|
|
7
|
+
require 'seccomp-tools/symbolic/state'
|
|
7
8
|
require 'seccomp-tools/util'
|
|
8
9
|
|
|
9
10
|
module SeccompTools
|
|
@@ -12,25 +13,39 @@ module SeccompTools
|
|
|
12
13
|
module_function
|
|
13
14
|
|
|
14
15
|
# Disassemble BPF codes.
|
|
16
|
+
#
|
|
17
|
+
# Emulates the filter to track what each register holds, so syscall names and argument
|
|
18
|
+
# positions can be inferred and shown as comments.
|
|
15
19
|
# @param [String] raw
|
|
16
20
|
# The raw BPF bytes.
|
|
17
|
-
# @param [Symbol] arch
|
|
18
|
-
#
|
|
21
|
+
# @param [Symbol?] arch
|
|
22
|
+
# Target architecture, must be one of {SeccompTools::Util.supported_archs}.
|
|
23
|
+
# Defaults to {SeccompTools::Util.system_arch} when +nil+.
|
|
19
24
|
# @param [Boolean] display_bpf
|
|
25
|
+
# Whether to prepend each line with its raw +code+, +jt+, +jf+ and +k+ fields.
|
|
20
26
|
# @param [Boolean] arg_infer
|
|
27
|
+
# Whether to annotate lines with the inferred syscall name and argument.
|
|
28
|
+
# @return [String]
|
|
29
|
+
# The disassembly result, ready to be printed.
|
|
30
|
+
# @example
|
|
31
|
+
# SeccompTools::Disasm.disasm(raw, arch: :amd64, display_bpf: false)
|
|
32
|
+
# #=> "0000: A = sys_number\n0001: if (A == read) goto 0003\n0002: return KILL\n0003: return ALLOW\n"
|
|
21
33
|
def disasm(raw, arch: nil, display_bpf: true, arg_infer: true)
|
|
22
34
|
codes = to_bpf(raw, arch)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
#
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
35
|
+
states = Array.new(codes.size) { Set.new }
|
|
36
|
+
states[0].add(Symbolic::State.initial)
|
|
37
|
+
# A forward pass (jumps only go forward) tracking, per line, the states that can reach it, so
|
|
38
|
+
# syscall names and argument positions can be inferred from what each register holds. Unlike
|
|
39
|
+
# the Executor, this over-approximates - it forks every conditional instead of folding - so
|
|
40
|
+
# dead lines are still rendered.
|
|
41
|
+
dis = codes.zip(states).map do |code, sts|
|
|
42
|
+
sts.each do |st|
|
|
43
|
+
code.branch(st) do |pc, s|
|
|
44
|
+
states[pc].add(s) unless pc >= states.size
|
|
30
45
|
end
|
|
31
46
|
end
|
|
32
|
-
code.
|
|
33
|
-
code.disasm(code: display_bpf, arg_infer:
|
|
47
|
+
code.states = sts
|
|
48
|
+
code.disasm(code: display_bpf, arg_infer:)
|
|
34
49
|
end.join("\n")
|
|
35
50
|
if display_bpf
|
|
36
51
|
<<-EOS
|
|
@@ -45,8 +60,11 @@ module SeccompTools
|
|
|
45
60
|
|
|
46
61
|
# Convert raw BPF string to array of {BPF}.
|
|
47
62
|
# @param [String] raw
|
|
48
|
-
#
|
|
63
|
+
# The raw BPF bytes, each instruction being 8 bytes long.
|
|
64
|
+
# @param [Symbol?] arch
|
|
65
|
+
# Target architecture, defaults to {SeccompTools::Util.system_arch} when +nil+.
|
|
49
66
|
# @return [Array<BPF>]
|
|
67
|
+
# One {BPF} per instruction, in order.
|
|
50
68
|
def to_bpf(raw, arch)
|
|
51
69
|
arch ||= Util.system_arch
|
|
52
70
|
raw.scan(/.{8}/m).map.with_index { |b, i| BPF.new(b, arch, i) }
|