seccomp-tools 1.4.0 → 1.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2726a64dc089ec7c492cedad9a98d500c656dce84ca593a505d95a42cd07906c
4
- data.tar.gz: c8d3eec04aa38ead5bac1727bb4a1a29199283e648b902edb38df2a7fc4e539f
3
+ metadata.gz: fa755fd2e7ed97279b094dfa28bd668aef4ee638005f0b38405066502fc8a30d
4
+ data.tar.gz: 56b0d51796d97a89f67262c36716833d078ce19ea6b58fbb83c2f8bee88b8685
5
5
  SHA512:
6
- metadata.gz: 2639ed20158afda2cc96dfeb16899f417d50180da548b4a45a0024c12119d0b9908649979fb9ab00287d41478f507eb6740ffda855aa238cd82755d774ca82de
7
- data.tar.gz: 6e6df86398ee4bde9ff9c54647dc5af95eb03e40001cf6117077afeecf20ecaed12f6e3f53b47bda1e2908094632c12e9d7faee3ee72c2422d7665016e583eff
6
+ metadata.gz: 027f57a717cb63fadeefd4a60213115a27ed51bb1eb3e6b58251690ed7c1d42335086ff4448b480296b77d395ba2e8718fa662e227394abfddaf80b19b769b74
7
+ data.tar.gz: f6aca254b4a43d6c60d5df7e6694b976de1e56fbb6d6585bd46fd17c0849820d76c81f25bbc872dc785576e05eeaaab5d0276a3f065b730988973c5073ace761
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- [![Build Status](https://travis-ci.org/david942j/seccomp-tools.svg?branch=master)](https://travis-ci.org/david942j/seccomp-tools)
1
+ [![Build Status](https://github.com/david942j/seccomp-tools/workflows/build/badge.svg)](https://github.com/david942j/seccomp-tools/actions)
2
2
  [![Dependabot Status](https://api.dependabot.com/badges/status?host=github&repo=david942j/seccomp-tools)](https://dependabot.com)
3
3
  [![Code Climate](https://codeclimate.com/github/david942j/seccomp-tools/badges/gpa.svg)](https://codeclimate.com/github/david942j/seccomp-tools)
4
4
  [![Issue Count](https://codeclimate.com/github/david942j/seccomp-tools/badges/issue_count.svg)](https://codeclimate.com/github/david942j/seccomp-tools)
@@ -54,6 +54,7 @@ $ seccomp-tools --help
54
54
 
55
55
  $ seccomp-tools dump --help
56
56
  # dump - Automatically dump seccomp bpf from execution file(s).
57
+ # NOTE : This function is only available on Linux.
57
58
  #
58
59
  # Usage: seccomp-tools dump [exec] [options]
59
60
  # -c, --sh-exec <command> Executes the given command (via sh).
@@ -169,7 +170,7 @@ $ seccomp-tools asm
169
170
  # -f, --format FORMAT Output format. FORMAT can only be one of <inspect|raw|c_array|c_source|assembly>.
170
171
  # Default: inspect
171
172
  # -a, --arch ARCH Specify architecture.
172
- # Supported architectures are <amd64|i386>.
173
+ # Supported architectures are <aarch64|amd64|i386>.
173
174
  # Default: amd64
174
175
 
175
176
  # Input file for asm
@@ -267,7 +268,7 @@ $ seccomp-tools emu --help
267
268
  #
268
269
  # Usage: seccomp-tools emu [options] BPF_FILE [sys_nr [arg0 [arg1 ... arg5]]]
269
270
  # -a, --arch ARCH Specify architecture.
270
- # Supported architectures are <amd64|i386>.
271
+ # Supported architectures are <aarch64|amd64|i386>.
271
272
  # Default: amd64
272
273
  # -q, --[no-]quiet Run quietly, only show emulation result.
273
274
 
@@ -300,6 +301,13 @@ $ seccomp-tools emu spec/data/libseccomp.bpf write 0x3
300
301
 
301
302
  ![emu](https://github.com/david942j/seccomp-tools/blob/master/examples/emu-amigo.png?raw=true)
302
303
 
304
+ ## Architecture Supported
305
+
306
+ - [x] x86_64
307
+ - [x] x32
308
+ - [x] x86
309
+ - [x] arm64 (Thanks to @saagarjha!)
310
+
303
311
  ## Development
304
312
 
305
313
  I recommend to use [rbenv](https://github.com/rbenv/rbenv) for your Ruby environment.
data/ext/ptrace/ptrace.c CHANGED
@@ -1,7 +1,15 @@
1
+ // ptrace is only available on Linux, therefore let this file be an empty
2
+ // object when installing on other platforms.
3
+ #if __linux__
4
+
5
+ #include <assert.h>
1
6
  #include <errno.h>
7
+ #include <linux/elf.h>
2
8
  #include <linux/filter.h>
9
+ #include <stdint.h>
3
10
  #include <sys/ptrace.h>
4
11
  #include <sys/signal.h>
12
+ #include <sys/uio.h>
5
13
  #include <sys/wait.h>
6
14
 
7
15
  #include "ruby.h"
@@ -19,10 +27,53 @@ ptrace_peekdata(VALUE _mod, VALUE pid, VALUE addr, VALUE _data) {
19
27
  return LONG2NUM(val);
20
28
  }
21
29
 
30
+ // aarch64 doesn't support PTRACE_PEEKUSER, but it does support
31
+ // PTRACE_GETREGSET which is fairly similar. Since i386 and x86_64 support it
32
+ // too, just use that unconditionally to present the same API for the registers
33
+ // we care about.
22
34
  static VALUE
23
- ptrace_peekuser(VALUE _mod, VALUE pid, VALUE off, VALUE _data) {
24
- long val = ptrace(PTRACE_PEEKUSER, NUM2LONG(pid), NUM2LONG(off), NULL);
25
- return LONG2NUM(val);
35
+ ptrace_peekuser(VALUE _mod, VALUE pid, VALUE off, VALUE _data, VALUE bits) {
36
+ size_t offset = NUM2LONG(off);
37
+ // Unless your registers fill an entire page, an offset greater than this is
38
+ // probably wrong.
39
+ if (offset >= 4096) {
40
+ return LONG2NUM(-1);
41
+ }
42
+ size_t width = NUM2LONG(bits);
43
+ if (width != 32 && width != 64) {
44
+ return LONG2NUM(-1);
45
+ }
46
+ width /= 8;
47
+ union {
48
+ uint32_t val32;
49
+ uint64_t val64;
50
+ } val;
51
+ // Dynamically allocate a buffer to store registers-well, at least enough
52
+ // registers to reach the offset we want. Normally we'd want to use
53
+ // user_pt_regs or similar, but it's difficult to find it available in the
54
+ // the same header across different versions of Linux or libcs, or even with
55
+ // the same *name*, so this is the compromise.
56
+ size_t size = offset + width;
57
+ char *regs = malloc(size);
58
+ if (!regs) {
59
+ return LONG2NUM(-1);
60
+ }
61
+ struct iovec vec = { regs, size };
62
+ if (ptrace(PTRACE_GETREGSET, NUM2LONG(pid), NT_PRSTATUS, &vec) != -1 && vec.iov_len >= size) {
63
+ memcpy(&val, regs + offset, width);
64
+ } else {
65
+ free(regs);
66
+ return LONG2NUM(-1);
67
+ }
68
+ free(regs);
69
+ if (width == sizeof(val.val32)) {
70
+ return LONG2NUM(val.val32);
71
+ } else if (width == sizeof(val.val64)) {
72
+ return LONG2NUM(val.val64);
73
+ } else {
74
+ assert(!"Unreachable");
75
+ return LONG2NUM(-1);
76
+ }
26
77
  }
27
78
 
28
79
  static VALUE
@@ -107,7 +158,7 @@ void Init_ptrace(void) {
107
158
  /* get data */
108
159
  rb_define_module_function(mPtrace, "peekdata", ptrace_peekdata, 3);
109
160
  /* get registers */
110
- rb_define_module_function(mPtrace, "peekuser", ptrace_peekuser, 3);
161
+ rb_define_module_function(mPtrace, "peekuser", ptrace_peekuser, 4);
111
162
  /* set ptrace options */
112
163
  rb_define_module_function(mPtrace, "setoptions", ptrace_setoptions, 3);
113
164
  /* wait for syscall */
@@ -124,3 +175,4 @@ void Init_ptrace(void) {
124
175
  rb_define_module_function(mPtrace, "detach", ptrace_detach, 1);
125
176
  }
126
177
 
178
+ #endif /* __linux__ */
@@ -200,7 +200,7 @@ module SeccompTools
200
200
  token.fetch('goto') ||
201
201
  token.fetch('jmp') ||
202
202
  token.fetch('jump') ||
203
- raise(ArgumentError, 'Invalid jump alias: ' + token.cur.inspect)
203
+ raise(ArgumentError, "Invalid jump alias: #{token.cur.inspect}")
204
204
  target = token.fetch!(:goto)
205
205
  [:jmp_abs, target]
206
206
  end
@@ -254,7 +254,7 @@ module SeccompTools
254
254
  token.fetch('sys_number') ||
255
255
  token.fetch('arch') ||
256
256
  token.fetch('len') ||
257
- raise(ArgumentError, 'Invalid source: ' + token.cur.inspect)
257
+ raise(ArgumentError, "Invalid source: #{token.cur.inspect}")
258
258
  [:assign, dst, src]
259
259
  end
260
260
 
@@ -291,7 +291,7 @@ module SeccompTools
291
291
 
292
292
  def invalid(line, extra_msg = nil)
293
293
  message = "Invalid instruction at line #{line + 1}: #{@input[line].inspect}"
294
- message += "\n" + 'Error: ' + extra_msg if extra_msg
294
+ message += "\nError: #{extra_msg}" if extra_msg
295
295
  raise ArgumentError, message
296
296
  end
297
297
  end
@@ -34,10 +34,10 @@ module SeccompTools
34
34
  def initialize(raw, arch, line)
35
35
  if raw.is_a?(String)
36
36
  io = ::StringIO.new(raw)
37
- @code = io.read(2).unpack('S').first
37
+ @code = io.read(2).unpack1('S')
38
38
  @jt = io.read(1).ord
39
39
  @jf = io.read(1).ord
40
- @k = io.read(4).unpack('L').first
40
+ @k = io.read(4).unpack1('L')
41
41
  else
42
42
  @code = raw[:code]
43
43
  @jt = raw[:jt]
@@ -10,7 +10,7 @@ module SeccompTools
10
10
  # Summary of this command.
11
11
  SUMMARY = 'Seccomp bpf assembler.'
12
12
  # Usage of this command.
13
- USAGE = ('asm - ' + SUMMARY + "\n\n" + 'Usage: seccomp-tools asm IN_FILE [options]').freeze
13
+ USAGE = "asm - #{SUMMARY}\n\nUsage: seccomp-tools asm IN_FILE [options]"
14
14
 
15
15
  def initialize(*)
16
16
  super
@@ -47,7 +47,7 @@ module SeccompTools
47
47
  res = SeccompTools::Asm.asm(input, arch: option[:arch])
48
48
  output do
49
49
  case option[:format]
50
- when :inspect then res.inspect + "\n"
50
+ when :inspect then "#{res.inspect}\n"
51
51
  when :raw then res
52
52
  when :c_array, :carray then "unsigned char bpf[] = {#{res.bytes.join(',')}};\n"
53
53
  when :c_source then SeccompTools::Util.template('asm.c').sub('<TO_BE_REPLACED>', res.bytes.join(','))
@@ -39,7 +39,7 @@ module SeccompTools
39
39
  # @return [String]
40
40
  # String read from file.
41
41
  def input
42
- option[:ifile] == '-' ? STDIN.read.force_encoding('ascii-8bit') : IO.binread(option[:ifile])
42
+ option[:ifile] == '-' ? $stdin.read.force_encoding('ascii-8bit') : IO.binread(option[:ifile])
43
43
  end
44
44
 
45
45
  # Write data to stdout or file(s).
@@ -10,7 +10,7 @@ module SeccompTools
10
10
  # Summary of this command.
11
11
  SUMMARY = 'Disassemble seccomp bpf.'
12
12
  # Usage of this command.
13
- USAGE = ('disasm - ' + SUMMARY + "\n\n" + 'Usage: seccomp-tools disasm BPF_FILE [options]').freeze
13
+ USAGE = "disasm - #{SUMMARY}\n\nUsage: seccomp-tools disasm BPF_FILE [options]"
14
14
 
15
15
  # Define option parser.
16
16
  # @return [OptionParser]
@@ -14,7 +14,8 @@ module SeccompTools
14
14
  # Summary of this command.
15
15
  SUMMARY = 'Automatically dump seccomp bpf from execution file(s).'
16
16
  # Usage of this command.
17
- USAGE = ('dump - ' + SUMMARY + "\n\n" + 'Usage: seccomp-tools dump [exec] [options]').freeze
17
+ USAGE = "dump - #{SUMMARY}\nNOTE : This function is only available on Linux." \
18
+ "\n\nUsage: seccomp-tools dump [exec] [options]"
18
19
 
19
20
  def initialize(*)
20
21
  super
@@ -64,11 +65,12 @@ module SeccompTools
64
65
  # Handle options.
65
66
  # @return [void]
66
67
  def handle
68
+ return Logger.error('Dump is only available on Linux.') unless Dumper::SUPPORTED
67
69
  return unless super
68
70
 
69
71
  block = lambda do |bpf, arch|
70
72
  case option[:format]
71
- when :inspect then output { '"' + bpf.bytes.map { |b| format('\\x%02X', b) }.join + "\"\n" }
73
+ when :inspect then output { "\"#{bpf.bytes.map { |b| format('\\x%02X', b) }.join}\"\n" }
72
74
  when :raw then output { bpf }
73
75
  when :disasm then output { SeccompTools::Disasm.disasm(bpf, arch: arch) }
74
76
  end
@@ -15,10 +15,7 @@ module SeccompTools
15
15
  # Summary of this command.
16
16
  SUMMARY = 'Emulate seccomp rules.'
17
17
  # Usage of this command.
18
- USAGE = ('emu - ' +
19
- SUMMARY +
20
- "\n\n" \
21
- 'Usage: seccomp-tools emu [options] BPF_FILE [sys_nr [arg0 [arg1 ... arg5]]]').freeze
18
+ USAGE = "emu - #{SUMMARY}\n\nUsage: seccomp-tools emu [options] BPF_FILE [sys_nr [arg0 [arg1 ... arg5]]]"
22
19
 
23
20
  def initialize(*)
24
21
  super
@@ -59,6 +59,8 @@ module SeccompTools
59
59
  KILL: 0x00000000, # alias of KILL_THREAD
60
60
  TRAP: 0x00030000,
61
61
  ERRNO: 0x00050000,
62
+ USER_NOTIF: 0x7fc00000,
63
+ LOG: 0x7ffc0000,
62
64
  TRACE: 0x7ff00000,
63
65
  ALLOW: 0x7fff0000
64
66
  }.freeze
@@ -120,17 +122,28 @@ module SeccompTools
120
122
 
121
123
  const_set(cons, instance_eval(IO.read(filename)))
122
124
  end
125
+
126
+ def load_args
127
+ hash = instance_eval(IO.read(File.join(__dir__, 'consts', 'sys_arg.rb')))
128
+ Hash.new do |_h, k|
129
+ next hash[k] if hash[k]
130
+ next hash[k.to_s[4..-1].to_sym] if k.to_s.start_with?('x32_')
131
+
132
+ nil
133
+ end
134
+ end
123
135
  end
124
136
 
125
137
  # The argument names of all syscalls.
126
- SYS_ARG = instance_eval(IO.read(File.join(__dir__, 'consts', 'sys_arg.rb'))).freeze
138
+ SYS_ARG = Syscall.load_args.freeze
127
139
 
128
140
  # Constants from https://github.com/torvalds/linux/blob/master/include/uapi/linux/audit.h.
129
141
  module Audit
130
142
  # AUDIT_ARCH_*
131
143
  ARCH = {
132
144
  'ARCH_X86_64' => 0xc000003e,
133
- 'ARCH_I386' => 0x40000003
145
+ 'ARCH_I386' => 0x40000003,
146
+ 'ARCH_AARCH64' => 0xc00000b7
134
147
  }.freeze
135
148
  end
136
149
  end
@@ -0,0 +1,284 @@
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
+ renameat: 38,
43
+ umount2: 39,
44
+ mount: 40,
45
+ pivot_root: 41,
46
+ nfsservctl: 42,
47
+ statfs: 43,
48
+ fstatfs: 44,
49
+ truncate: 45,
50
+ ftruncate: 46,
51
+ fallocate: 47,
52
+ faccessat: 48,
53
+ chdir: 49,
54
+ fchdir: 50,
55
+ chroot: 51,
56
+ fchmod: 52,
57
+ fchmodat: 53,
58
+ fchownat: 54,
59
+ fchown: 55,
60
+ openat: 56,
61
+ close: 57,
62
+ vhangup: 58,
63
+ pipe2: 59,
64
+ quotactl: 60,
65
+ getdents: 61,
66
+ getdents64: 61,
67
+ lseek: 62,
68
+ read: 63,
69
+ write: 64,
70
+ readv: 65,
71
+ writev: 66,
72
+ pread: 67,
73
+ pread64: 67,
74
+ pwrite: 68,
75
+ pwrite64: 68,
76
+ preadv: 69,
77
+ pwritev: 70,
78
+ sendfile: 71,
79
+ pselect6: 72,
80
+ ppoll: 73,
81
+ signalfd4: 74,
82
+ vmsplice: 75,
83
+ splice: 76,
84
+ tee: 77,
85
+ readlinkat: 78,
86
+ newfstatat: 79,
87
+ fstat: 80,
88
+ newfstat: 80,
89
+ sync: 81,
90
+ fsync: 82,
91
+ fdatasync: 83,
92
+ sync_file_range: 84,
93
+ timerfd_create: 85,
94
+ timerfd_settime: 86,
95
+ timerfd_gettime: 87,
96
+ utimensat: 88,
97
+ acct: 89,
98
+ capget: 90,
99
+ capset: 91,
100
+ personality: 92,
101
+ exit: 93,
102
+ exit_group: 94,
103
+ waitid: 95,
104
+ set_tid_address: 96,
105
+ unshare: 97,
106
+ futex: 98,
107
+ set_robust_list: 99,
108
+ get_robust_list: 100,
109
+ nanosleep: 101,
110
+ getitimer: 102,
111
+ setitimer: 103,
112
+ kexec_load: 104,
113
+ init_module: 105,
114
+ delete_module: 106,
115
+ timer_create: 107,
116
+ timer_gettime: 108,
117
+ timer_getoverrun: 109,
118
+ timer_settime: 110,
119
+ timer_delete: 111,
120
+ clock_settime: 112,
121
+ clock_gettime: 113,
122
+ clock_getres: 114,
123
+ clock_nanosleep: 115,
124
+ syslog: 116,
125
+ ptrace: 117,
126
+ sched_setparam: 118,
127
+ sched_setscheduler: 119,
128
+ sched_getscheduler: 120,
129
+ sched_getparam: 121,
130
+ sched_setaffinity: 122,
131
+ sched_getaffinity: 123,
132
+ sched_yield: 124,
133
+ sched_get_priority_max: 125,
134
+ sched_get_priority_min: 126,
135
+ sched_rr_get_interval: 127,
136
+ restart_syscall: 128,
137
+ kill: 129,
138
+ tkill: 130,
139
+ tgkill: 131,
140
+ sigaltstack: 132,
141
+ rt_sigsuspend: 133,
142
+ rt_sigaction: 134,
143
+ rt_sigprocmask: 135,
144
+ rt_sigpending: 136,
145
+ rt_sigtimedwait: 137,
146
+ rt_sigqueueinfo: 138,
147
+ rt_sigreturn: 139,
148
+ setpriority: 140,
149
+ getpriority: 141,
150
+ reboot: 142,
151
+ setregid: 143,
152
+ setgid: 144,
153
+ setreuid: 145,
154
+ setuid: 146,
155
+ setresuid: 147,
156
+ getresuid: 148,
157
+ setresgid: 149,
158
+ getresgid: 150,
159
+ setfsuid: 151,
160
+ setfsgid: 152,
161
+ times: 153,
162
+ setpgid: 154,
163
+ getpgid: 155,
164
+ getsid: 156,
165
+ setsid: 157,
166
+ getgroups: 158,
167
+ setgroups: 159,
168
+ uname: 160,
169
+ sethostname: 161,
170
+ setdomainname: 162,
171
+ getrlimit: 163,
172
+ setrlimit: 164,
173
+ getrusage: 165,
174
+ umask: 166,
175
+ prctl: 167,
176
+ getcpu: 168,
177
+ gettimeofday: 169,
178
+ settimeofday: 170,
179
+ adjtimex: 171,
180
+ getpid: 172,
181
+ getppid: 173,
182
+ getuid: 174,
183
+ geteuid: 175,
184
+ getgid: 176,
185
+ getegid: 177,
186
+ gettid: 178,
187
+ sysinfo: 179,
188
+ mq_open: 180,
189
+ mq_unlink: 181,
190
+ mq_timedsend: 182,
191
+ mq_timedreceive: 183,
192
+ mq_notify: 184,
193
+ mq_getsetattr: 185,
194
+ msgget: 186,
195
+ msgctl: 187,
196
+ msgrcv: 188,
197
+ msgsnd: 189,
198
+ semget: 190,
199
+ semctl: 191,
200
+ semtimedop: 192,
201
+ semop: 193,
202
+ shmget: 194,
203
+ shmctl: 195,
204
+ shmat: 196,
205
+ shmdt: 197,
206
+ socket: 198,
207
+ socketpair: 199,
208
+ bind: 200,
209
+ listen: 201,
210
+ accept: 202,
211
+ connect: 203,
212
+ getsockname: 204,
213
+ getpeername: 205,
214
+ sendto: 206,
215
+ recvfrom: 207,
216
+ setsockopt: 208,
217
+ getsockopt: 209,
218
+ shutdown: 210,
219
+ sendmsg: 211,
220
+ recvmsg: 212,
221
+ readahead: 213,
222
+ brk: 214,
223
+ munmap: 215,
224
+ mremap: 216,
225
+ add_key: 217,
226
+ request_key: 218,
227
+ keyctl: 219,
228
+ clone: 220,
229
+ execve: 221,
230
+ mmap: 222,
231
+ fadvise64: 223,
232
+ swapon: 224,
233
+ swapoff: 225,
234
+ mprotect: 226,
235
+ msync: 227,
236
+ mlock: 228,
237
+ munlock: 229,
238
+ mlockall: 230,
239
+ munlockall: 231,
240
+ mincore: 232,
241
+ madvise: 233,
242
+ remap_file_pages: 234,
243
+ mbind: 235,
244
+ get_mempolicy: 236,
245
+ set_mempolicy: 237,
246
+ migrate_pages: 238,
247
+ move_pages: 239,
248
+ rt_tgsigqueueinfo: 240,
249
+ perf_event_open: 241,
250
+ accept4: 242,
251
+ recvmmsg: 243,
252
+ wait4: 260,
253
+ prlimit64: 261,
254
+ fanotify_init: 262,
255
+ fanotify_mark: 263,
256
+ name_to_handle_at: 264,
257
+ open_by_handle_at: 265,
258
+ clock_adjtime: 266,
259
+ syncfs: 267,
260
+ setns: 268,
261
+ sendmmsg: 269,
262
+ process_vm_readv: 270,
263
+ process_vm_writev: 271,
264
+ kcmp: 272,
265
+ finit_module: 273,
266
+ sched_setattr: 274,
267
+ sched_getattr: 275,
268
+ renameat2: 276,
269
+ seccomp: 277,
270
+ getrandom: 278,
271
+ memfd_create: 279,
272
+ bpf: 280,
273
+ execveat: 281,
274
+ userfaultfd: 282,
275
+ membarrier: 283,
276
+ mlock2: 284,
277
+ copy_file_range: 285,
278
+ preadv2: 286,
279
+ pwritev2: 287,
280
+ pkey_mprotect: 288,
281
+ pkey_alloc: 289,
282
+ pkey_free: 290,
283
+ statx: 291
284
+ }
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ X32_MODE_BIT = 0x40000000
3
4
  {
4
5
  read: 0,
5
6
  write: 1,
@@ -18,7 +19,9 @@
18
19
  rt_sigprocmask: 14,
19
20
  rt_sigreturn: 15,
20
21
  ioctl: 16,
22
+ pread: 17,
21
23
  pread64: 17,
24
+ pwrite: 18,
22
25
  pwrite64: 18,
23
26
  readv: 19,
24
27
  writev: 20,
@@ -334,4 +337,4 @@
334
337
  pkey_alloc: 330,
335
338
  pkey_free: 331,
336
339
  statx: 332
337
- }
340
+ }.tap { |h| h.keys.each { |k| h["x32_#{k}".to_sym] = h[k] | X32_MODE_BIT } } # rubocop:disable Style/HashEachMethods
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  {
4
- setup: 0,
4
+ restart_syscall: 0,
5
5
  exit: 1,
6
6
  fork: 2,
7
7
  read: 3,
@@ -259,14 +259,14 @@
259
259
  remap_file_pages: 257,
260
260
  set_tid_address: 258,
261
261
  timer_create: 259,
262
- timer_settime: (259 + 1),
263
- timer_gettime: (259 + 2),
264
- timer_getoverrun: (259 + 3),
265
- timer_delete: (259 + 4),
266
- clock_settime: (259 + 5),
267
- clock_gettime: (259 + 6),
268
- clock_getres: (259 + 7),
269
- clock_nanosleep: (259 + 8),
262
+ timer_settime: 260,
263
+ timer_gettime: 261,
264
+ timer_getoverrun: 262,
265
+ timer_delete: 263,
266
+ clock_settime: 264,
267
+ clock_gettime: 265,
268
+ clock_getres: 266,
269
+ clock_nanosleep: 267,
270
270
  statfs64: 268,
271
271
  fstatfs64: 269,
272
272
  tgkill: 270,
@@ -277,11 +277,11 @@
277
277
  get_mempolicy: 275,
278
278
  set_mempolicy: 276,
279
279
  mq_open: 277,
280
- mq_unlink: (277 + 1),
281
- mq_timedsend: (277 + 2),
282
- mq_timedreceive: (277 + 3),
283
- mq_notify: (277 + 4),
284
- mq_getsetattr: (277 + 5),
280
+ mq_unlink: 278,
281
+ mq_timedsend: 279,
282
+ mq_timedreceive: 280,
283
+ mq_notify: 281,
284
+ mq_getsetattr: 282,
285
285
  sys_kexec_load: 283,
286
286
  waitid: 284,
287
287
  add_key: 286,
@@ -30,9 +30,10 @@ module SeccompTools
30
30
  code.contexts = ctxs
31
31
  code.disasm
32
32
  end.join("\n")
33
- <<-EOS + dis + "\n"
33
+ <<-EOS
34
34
  line CODE JT JF K
35
35
  =================================
36
+ #{dis}
36
37
  EOS
37
38
  end
38
39
 
@@ -1,13 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'os'
4
+
3
5
  require 'seccomp-tools/logger'
4
- require 'seccomp-tools/ptrace'
6
+ require 'seccomp-tools/ptrace' if OS.linux?
5
7
  require 'seccomp-tools/syscall'
6
8
 
7
9
  module SeccompTools
8
10
  # Dump seccomp-bpf using ptrace of binary.
9
- # Currently only support x86_64.
11
+ # Currently only support x86_64 and aarch64.
10
12
  module Dumper
13
+ # Whether the dumper is supported.
14
+ # Dumper works based on ptrace, so we need the platform be Linux.
15
+ SUPPORTED = OS.linux?
16
+
11
17
  module_function
12
18
 
13
19
  # Main bpf dump function.
@@ -35,6 +41,8 @@ module SeccompTools
35
41
  # @todo
36
42
  # +timeout+ option.
37
43
  def dump(*args, limit: 1, &block)
44
+ return [] unless SUPPORTED
45
+
38
46
  pid = fork { handle_child(*args) }
39
47
  Handler.new(pid).handle(limit, &block)
40
48
  end
@@ -164,6 +172,8 @@ module SeccompTools
164
172
  # dump_by_pid(pid2, 1) { |c| c[0, 10] }
165
173
  # #=> [" \x00\x00\x00\x00\x00\x00\x00\x15\x00"]
166
174
  def dump_by_pid(pid, limit, &block)
175
+ return [] unless SUPPORTED
176
+
167
177
  collect = []
168
178
  Ptrace.attach_and_wait(pid)
169
179
  begin
@@ -58,10 +58,11 @@ module SeccompTools
58
58
  end
59
59
 
60
60
  def audit(arch)
61
- type = case arch
62
- when :amd64 then 'ARCH_X86_64'
63
- when :i386 then 'ARCH_I386'
64
- end
61
+ type = {
62
+ amd64: 'ARCH_X86_64',
63
+ i386: 'ARCH_I386',
64
+ aarch64: 'ARCH_AARCH64'
65
+ }[arch]
65
66
  Const::Audit::ARCH[type]
66
67
  end
67
68
 
@@ -62,7 +62,7 @@ module SeccompTools
62
62
 
63
63
  case op
64
64
  when :lsh, :rsh then src.to_s
65
- else '0x' + src.to_s(16)
65
+ else "0x#{src.to_s(16)}"
66
66
  end
67
67
  end
68
68
 
@@ -16,9 +16,9 @@ module SeccompTools
16
16
  # otherwise => if () goto jt; else goto jf;
17
17
  return '/* no-op */' if jt.zero? && jf.zero?
18
18
  return goto(jt) if jt == jf
19
- return if_str(true) + goto(jf) if jt.zero?
19
+ return if_str(neg: true) + goto(jf) if jt.zero?
20
20
 
21
- if_str + goto(jt) + (jf.zero? ? '' : ' else ' + goto(jf))
21
+ if_str + goto(jt) + (jf.zero? ? '' : " else #{goto(jf)}")
22
22
  end
23
23
 
24
24
  # See {Instruction::Base#symbolize}.
@@ -64,14 +64,19 @@ module SeccompTools
64
64
  a = a[0]
65
65
  return k.to_s unless a.data?
66
66
 
67
- hex = '0x' + k.to_s(16)
67
+ hex = "0x#{k.to_s(16)}"
68
68
  case a.val
69
- when 0 then Util.colorize(Const::Syscall.const_get(arch.upcase.to_sym).invert[k] || hex, t: :syscall)
69
+ # interpret as syscalls only if it's an equality test
70
+ when 0 then Util.colorize(jop == :== ? sysname_by_k || hex : hex, t: :syscall)
70
71
  when 4 then Util.colorize(Const::Audit::ARCH.invert[k] || hex, t: :arch)
71
72
  else hex
72
73
  end
73
74
  end
74
75
 
76
+ def sysname_by_k
77
+ Const::Syscall.const_get(arch.upcase.to_sym).invert[k]
78
+ end
79
+
75
80
  def src
76
81
  SRC.invert[code & 8] == :x ? :x : k
77
82
  end
@@ -84,15 +89,15 @@ module SeccompTools
84
89
  line + off + 1
85
90
  end
86
91
 
87
- def if_str(neg = false)
92
+ def if_str(neg: false)
88
93
  return "if (A #{jop} #{src_str}) " unless neg
89
94
  return "if (!(A & #{src_str})) " if jop == :&
90
95
 
91
- op = case jop
92
- when :>= then :<
93
- when :> then :<=
94
- when :== then :!=
95
- end
96
+ op = {
97
+ :>= => :<,
98
+ :> => :<=,
99
+ :== => :!=
100
+ }[jop]
96
101
  "if (A #{op} #{src_str}) "
97
102
  end
98
103
  end
@@ -10,7 +10,7 @@ module SeccompTools
10
10
  class LD < Base
11
11
  # Decompile instruction.
12
12
  def decompile
13
- ret = reg + ' = '
13
+ ret = "#{reg} = "
14
14
  _, _reg, type = symbolize
15
15
  return ret + type[:val].to_s if type[:rel] == :immi
16
16
  return ret + "mem[#{type[:val]}]" if type[:rel] == :mem
@@ -88,7 +88,7 @@ module SeccompTools
88
88
 
89
89
  comment = "# #{sys}(#{args.join(', ')})"
90
90
  arg_name = Util.colorize(args[idx / 2], t: :args)
91
- (idx.even? ? arg_name : "#{arg_name} >> 32") + ' ' + Util.colorize(comment, t: :gray)
91
+ "#{idx.even? ? arg_name : "#{arg_name} >> 32"} #{Util.colorize(comment, t: :gray)}"
92
92
  end
93
93
  end
94
94
  end
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'os'
4
+
3
5
  require 'seccomp-tools/const'
4
- require 'seccomp-tools/ptrace'
6
+ require 'seccomp-tools/ptrace' if OS.linux?
5
7
 
6
8
  module SeccompTools
7
9
  # Record syscall number, arguments, return value.
@@ -9,7 +11,8 @@ module SeccompTools
9
11
  # Syscall arguments offset of +struct user+ in different arch.
10
12
  ABI = {
11
13
  amd64: { number: 120, args: [112, 104, 96, 56, 72, 44], ret: 80, SYS_prctl: 157, SYS_seccomp: 317 },
12
- i386: { number: 120, args: [40, 88, 96, 104, 112, 32], ret: 80, SYS_prctl: 172, SYS_seccomp: 354 }
14
+ i386: { number: 44, args: [0, 4, 8, 12, 16, 20], ret: 24, SYS_prctl: 172, SYS_seccomp: 354 },
15
+ aarch64: { number: 64, args: [0, 8, 16, 24, 32, 40, 48], ret: 0, SYS_prctl: 167, SYS_seccomp: 277 }
13
16
  }.freeze
14
17
 
15
18
  # @return [Integer] Process id.
@@ -60,10 +63,11 @@ module SeccompTools
60
63
  # Architecture of this syscall.
61
64
  def arch
62
65
  @arch ||= File.open("/proc/#{pid}/exe", 'rb') do |f|
63
- f.pos = 4
66
+ f.pos = 18
64
67
  case f.read(1).ord
65
- when 1 then :i386
66
- when 2 then :amd64
68
+ when 3 then :i386
69
+ when 62 then :amd64
70
+ when 183 then :aarch64
67
71
  end
68
72
  end
69
73
  end
@@ -71,14 +75,15 @@ module SeccompTools
71
75
  private
72
76
 
73
77
  def bits
74
- case arch
75
- when :i386 then 32
76
- when :amd64 then 64
77
- end
78
+ {
79
+ i386: 32,
80
+ amd64: 64,
81
+ aarch64: 64
82
+ }[arch]
78
83
  end
79
84
 
80
85
  def peek(offset)
81
- Ptrace.peekuser(pid, offset, 0)
86
+ Ptrace.peekuser(pid, offset, 0, bits)
82
87
  end
83
88
  end
84
89
  end
@@ -20,6 +20,7 @@ module SeccompTools
20
20
  case RbConfig::CONFIG['host_cpu']
21
21
  when /x86_64/ then :amd64
22
22
  when /i386/ then :i386
23
+ when /aarch64/ then :aarch64
23
24
  else :unknown
24
25
  end
25
26
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module SeccompTools
4
4
  # Gem version.
5
- VERSION = '1.4.0'
5
+ VERSION = '1.5.0'
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: seccomp-tools
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - david942j
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-16 00:00:00.000000000 Z
11
+ date: 2021-03-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -58,28 +58,34 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0.79'
61
+ version: '1.1'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0.79'
68
+ version: '1.1'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: simplecov
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 0.17.0
75
+ version: '0.17'
76
+ - - "<"
77
+ - !ruby/object:Gem::Version
78
+ version: '0.18'
76
79
  type: :development
77
80
  prerelease: false
78
81
  version_requirements: !ruby/object:Gem::Requirement
79
82
  requirements:
80
83
  - - "~>"
81
84
  - !ruby/object:Gem::Version
82
- version: 0.17.0
85
+ version: '0.17'
86
+ - - "<"
87
+ - !ruby/object:Gem::Version
88
+ version: '0.18'
83
89
  - !ruby/object:Gem::Dependency
84
90
  name: yard
85
91
  requirement: !ruby/object:Gem::Requirement
@@ -94,6 +100,26 @@ dependencies:
94
100
  - - "~>"
95
101
  - !ruby/object:Gem::Version
96
102
  version: '0.9'
103
+ - !ruby/object:Gem::Dependency
104
+ name: os
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '1.1'
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: 1.1.1
113
+ type: :runtime
114
+ prerelease: false
115
+ version_requirements: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - "~>"
118
+ - !ruby/object:Gem::Version
119
+ version: '1.1'
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: 1.1.1
97
123
  description: |
98
124
  Provide useful tools to analyze seccomp rules.
99
125
  Visit https://github.com/david942j/seccomp-tools for more details.
@@ -122,6 +148,7 @@ files:
122
148
  - lib/seccomp-tools/cli/emu.rb
123
149
  - lib/seccomp-tools/const.rb
124
150
  - lib/seccomp-tools/consts/sys_arg.rb
151
+ - lib/seccomp-tools/consts/sys_nr/aarch64.rb
125
152
  - lib/seccomp-tools/consts/sys_nr/amd64.rb
126
153
  - lib/seccomp-tools/consts/sys_nr/i386.rb
127
154
  - lib/seccomp-tools/disasm/context.rb
@@ -168,7 +195,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
168
195
  - !ruby/object:Gem::Version
169
196
  version: '0'
170
197
  requirements: []
171
- rubygems_version: 3.0.3
198
+ rubygems_version: 3.1.4
172
199
  signing_key:
173
200
  specification_version: 4
174
201
  summary: seccomp-tools