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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +153 -0
  3. data/LICENSE +21 -0
  4. data/README.md +267 -46
  5. data/completions/_seccomp-tools +83 -0
  6. data/completions/seccomp-tools.bash +59 -0
  7. data/completions/seccomp-tools.fish +52 -0
  8. data/ext/ptrace/ptrace.c +2 -2
  9. data/lib/seccomp-tools/asm/asm.rb +9 -4
  10. data/lib/seccomp-tools/asm/compiler.rb +39 -9
  11. data/lib/seccomp-tools/asm/sasm.tab.rb +31 -21
  12. data/lib/seccomp-tools/asm/sasm.y +15 -7
  13. data/lib/seccomp-tools/asm/scalar.rb +50 -7
  14. data/lib/seccomp-tools/asm/scanner.rb +40 -8
  15. data/lib/seccomp-tools/asm/statement.rb +14 -5
  16. data/lib/seccomp-tools/asm/token.rb +19 -1
  17. data/lib/seccomp-tools/audit/catalog.rb +66 -0
  18. data/lib/seccomp-tools/audit/checks/arch_unchecked.rb +41 -0
  19. data/lib/seccomp-tools/audit/checks/dangerous_allow.rb +34 -0
  20. data/lib/seccomp-tools/audit/checks/orw_chain.rb +41 -0
  21. data/lib/seccomp-tools/audit/checks/permissive_default.rb +29 -0
  22. data/lib/seccomp-tools/audit/checks/syscall_alt_gap.rb +44 -0
  23. data/lib/seccomp-tools/audit/checks/x32_guard.rb +46 -0
  24. data/lib/seccomp-tools/audit/checks.rb +42 -0
  25. data/lib/seccomp-tools/audit/finding.rb +25 -0
  26. data/lib/seccomp-tools/audit/policy.rb +126 -0
  27. data/lib/seccomp-tools/audit/report.rb +98 -0
  28. data/lib/seccomp-tools/audit.rb +48 -0
  29. data/lib/seccomp-tools/bpf.rb +27 -17
  30. data/lib/seccomp-tools/cli/asm.rb +7 -3
  31. data/lib/seccomp-tools/cli/audit.rb +86 -0
  32. data/lib/seccomp-tools/cli/base.rb +51 -8
  33. data/lib/seccomp-tools/cli/cli.rb +10 -6
  34. data/lib/seccomp-tools/cli/completion.rb +40 -0
  35. data/lib/seccomp-tools/cli/disasm.rb +10 -6
  36. data/lib/seccomp-tools/cli/dump.rb +37 -52
  37. data/lib/seccomp-tools/cli/dumpable.rb +79 -0
  38. data/lib/seccomp-tools/cli/emu.rb +32 -9
  39. data/lib/seccomp-tools/cli/explain.rb +51 -0
  40. data/lib/seccomp-tools/cli/filter_input.rb +130 -0
  41. data/lib/seccomp-tools/const.rb +98 -15
  42. data/lib/seccomp-tools/consts/sys_nr/amd64.rb +1 -1
  43. data/lib/seccomp-tools/consts/sys_nr/riscv64.rb +332 -0
  44. data/lib/seccomp-tools/disasm/disasm.rb +31 -13
  45. data/lib/seccomp-tools/dumper.rb +67 -35
  46. data/lib/seccomp-tools/emulator.rb +41 -16
  47. data/lib/seccomp-tools/error.rb +4 -2
  48. data/lib/seccomp-tools/explain/analysis.rb +67 -0
  49. data/lib/seccomp-tools/explain/path_facts.rb +110 -0
  50. data/lib/seccomp-tools/explain/qword.rb +204 -0
  51. data/lib/seccomp-tools/explain/renderer.rb +128 -0
  52. data/lib/seccomp-tools/explain/summary.rb +218 -0
  53. data/lib/seccomp-tools/explain/verdict.rb +44 -0
  54. data/lib/seccomp-tools/explain.rb +38 -0
  55. data/lib/seccomp-tools/instruction/alu.rb +14 -9
  56. data/lib/seccomp-tools/instruction/base.rb +39 -10
  57. data/lib/seccomp-tools/instruction/jmp.rb +50 -23
  58. data/lib/seccomp-tools/instruction/ld.rb +46 -21
  59. data/lib/seccomp-tools/instruction/ldx.rb +4 -3
  60. data/lib/seccomp-tools/instruction/misc.rb +11 -9
  61. data/lib/seccomp-tools/instruction/ret.rb +12 -6
  62. data/lib/seccomp-tools/instruction/st.rb +15 -6
  63. data/lib/seccomp-tools/instruction/stx.rb +4 -3
  64. data/lib/seccomp-tools/logger.rb +15 -2
  65. data/lib/seccomp-tools/symbolic/constraint.rb +80 -0
  66. data/lib/seccomp-tools/symbolic/executor.rb +210 -0
  67. data/lib/seccomp-tools/symbolic/expr.rb +185 -0
  68. data/lib/seccomp-tools/symbolic/state.rb +82 -0
  69. data/lib/seccomp-tools/syscall.rb +74 -22
  70. data/lib/seccomp-tools/util.rb +70 -11
  71. data/lib/seccomp-tools/version.rb +1 -1
  72. data/lib/seccomp-tools.rb +10 -1
  73. metadata +83 -11
  74. data/lib/seccomp-tools/disasm/context.rb +0 -171
@@ -0,0 +1,83 @@
1
+ #compdef seccomp-tools
2
+
3
+ # zsh completion for seccomp-tools
4
+ #
5
+ # Load it with either:
6
+ # eval "$(seccomp-tools completion zsh)" # in ~/.zshrc, after `compinit`
7
+ # or drop this file (named `_seccomp-tools`) into a directory on your $fpath.
8
+
9
+ _seccomp-tools() {
10
+ local -a arches=(aarch64 amd64 i386 riscv64 s390x)
11
+
12
+ # $words is 1-indexed; words[1]=seccomp-tools, words[2]=subcommand.
13
+ if (( CURRENT == 2 )); then
14
+ local -a commands=(
15
+ 'asm:Seccomp bpf assembler'
16
+ 'audit:Assess a filter for weaknesses and escape routes'
17
+ 'completion:Print a shell completion script'
18
+ 'disasm:Disassemble seccomp bpf'
19
+ 'dump:Automatically dump seccomp bpf from executable(s)'
20
+ 'emu:Emulate seccomp rules'
21
+ 'explain:Summarize a filter as a per-action policy'
22
+ )
23
+ _describe 'command' commands
24
+ return
25
+ fi
26
+
27
+ case ${words[2]} in
28
+ asm)
29
+ _arguments \
30
+ '(-o --output)'{-o,--output}'[write output to FILE]:file:_files' \
31
+ '(-f --format)'{-f,--format}'[output format]:format:(inspect raw c_array c_source assembly)' \
32
+ '(-a --arch)'{-a,--arch}"[architecture]:arch:($arches)" \
33
+ '1:input asm file:_files'
34
+ ;;
35
+ disasm)
36
+ _arguments \
37
+ '(-o --output)'{-o,--output}'[write output to FILE]:file:_files' \
38
+ '(-a --arch)'{-a,--arch}"[architecture]:arch:($arches)" \
39
+ '--asm-able[emit output that is valid input for asm]' \
40
+ '(--bpf --no-bpf)--no-bpf[hide the raw BPF bytes]' \
41
+ '(--arg-infer --no-arg-infer)--no-arg-infer[do not infer argument names]' \
42
+ '1:bpf file:_files'
43
+ ;;
44
+ dump)
45
+ _arguments \
46
+ '(-c --sh-exec)'{-c,--sh-exec}'[run command via sh and dump its seccomp]:command:' \
47
+ '(-p --pid)'{-p,--pid}'[dump filters of a running process]:pid:' \
48
+ '(-l --limit)'{-l,--limit}'[dump only the first N filters]:limit:' \
49
+ '(-t --timeout)'{-t,--timeout}'[timeout in seconds]:seconds:' \
50
+ '(-f --format)'{-f,--format}'[output format]:format:(disasm raw inspect)' \
51
+ '(-o --output)'{-o,--output}'[write output to FILE]:file:_files' \
52
+ '1:executable:_files'
53
+ ;;
54
+ audit|explain)
55
+ _arguments \
56
+ '(-c --sh-exec)'{-c,--sh-exec}'[run command via sh]:command:' \
57
+ '(-p --pid)'{-p,--pid}'[analyze a running process]:pid:' \
58
+ '(-l --limit)'{-l,--limit}'[analyze only the first N filters]:limit:' \
59
+ '(-t --timeout)'{-t,--timeout}'[timeout in seconds]:seconds:' \
60
+ '(-a --arch)'{-a,--arch}"[architecture]:arch:($arches)" \
61
+ '(-f --format)'{-f,--format}'[output format]:format:(human json)' \
62
+ '1:bpf file or executable:_files'
63
+ ;;
64
+ emu)
65
+ _arguments \
66
+ '(-a --arch)'{-a,--arch}"[architecture]:arch:($arches)" \
67
+ '(-q --quiet)'{-q,--quiet}'[only show the emulation result]' \
68
+ '(-i --ip)'{-i,--ip}'[set the instruction pointer]:ip:' \
69
+ '1:bpf file:_files'
70
+ ;;
71
+ completion)
72
+ _arguments '1:shell:(bash zsh fish)'
73
+ ;;
74
+ esac
75
+ }
76
+
77
+ # When autoloaded from $fpath the completion system calls this function directly;
78
+ # when eval'd or sourced, register it instead of running it.
79
+ if [ "${funcstack[1]}" = "_seccomp-tools" ]; then
80
+ _seccomp-tools "$@"
81
+ else
82
+ compdef _seccomp-tools seccomp-tools
83
+ fi
@@ -0,0 +1,59 @@
1
+ # bash completion for seccomp-tools
2
+ #
3
+ # Load it with either:
4
+ # eval "$(seccomp-tools completion bash)" # in ~/.bashrc
5
+ # or drop this file into a bash-completion directory named `seccomp-tools`, e.g.
6
+ # ~/.local/share/bash-completion/completions/seccomp-tools
7
+
8
+ _seccomp_tools() {
9
+ local cur prev cmd
10
+ cur="${COMP_WORDS[COMP_CWORD]}"
11
+ prev="${COMP_WORDS[COMP_CWORD-1]}"
12
+
13
+ local commands="asm audit completion disasm dump emu explain"
14
+ local arches="aarch64 amd64 i386 riscv64 s390x"
15
+
16
+ # Position 1: the subcommand.
17
+ if [[ $COMP_CWORD -eq 1 ]]; then
18
+ COMPREPLY=( $(compgen -W "$commands --help --version" -- "$cur") )
19
+ return
20
+ fi
21
+
22
+ cmd="${COMP_WORDS[1]}"
23
+
24
+ # The previous word expects a value: complete just that value.
25
+ case "$prev" in
26
+ -a|--arch) COMPREPLY=( $(compgen -W "$arches" -- "$cur") ); return ;;
27
+ -o|--output) COMPREPLY=( $(compgen -f -- "$cur") ); return ;;
28
+ -f|--format)
29
+ case "$cmd" in
30
+ asm) COMPREPLY=( $(compgen -W "inspect raw c_array c_source assembly" -- "$cur") ) ;;
31
+ audit) COMPREPLY=( $(compgen -W "human json" -- "$cur") ) ;;
32
+ dump) COMPREPLY=( $(compgen -W "disasm raw inspect" -- "$cur") ) ;;
33
+ esac
34
+ return ;;
35
+ esac
36
+
37
+ if [[ $cmd == completion ]]; then
38
+ COMPREPLY=( $(compgen -W "bash zsh fish" -- "$cur") )
39
+ return
40
+ fi
41
+
42
+ # Otherwise: this subcommand's flags (when typing a -flag) or a file.
43
+ local opts="-h --help"
44
+ case "$cmd" in
45
+ asm) opts+=" -o --output -f --format -a --arch" ;;
46
+ disasm) opts+=" -o --output -a --arch --bpf --no-bpf --arg-infer --no-arg-infer --asm-able" ;;
47
+ dump) opts+=" -c --sh-exec -l --limit -p --pid -t --timeout -f --format -o --output" ;;
48
+ emu) opts+=" -a --arch -q --no-quiet -i --ip" ;;
49
+ explain) opts+=" -c --sh-exec -l --limit -p --pid -t --timeout -a --arch" ;;
50
+ audit) opts+=" -c --sh-exec -l --limit -p --pid -t --timeout -a --arch -f --format" ;;
51
+ esac
52
+
53
+ if [[ $cur == -* ]]; then
54
+ COMPREPLY=( $(compgen -W "$opts" -- "$cur") )
55
+ else
56
+ COMPREPLY=( $(compgen -f -- "$cur") )
57
+ fi
58
+ }
59
+ complete -F _seccomp_tools seccomp-tools
@@ -0,0 +1,52 @@
1
+ # fish completion for seccomp-tools
2
+ #
3
+ # Load it with either:
4
+ # seccomp-tools completion fish | source # in ~/.config/fish/config.fish
5
+ # or drop this file into ~/.config/fish/completions/seccomp-tools.fish
6
+
7
+ # Disable file completion by default; re-enabled per option/positional below.
8
+ complete -c seccomp-tools -f
9
+
10
+ # Subcommands (offered only when none has been given yet).
11
+ complete -c seccomp-tools -n __fish_use_subcommand -a asm -d 'Seccomp bpf assembler'
12
+ complete -c seccomp-tools -n __fish_use_subcommand -a audit -d 'Assess a filter for weaknesses and escape routes'
13
+ complete -c seccomp-tools -n __fish_use_subcommand -a completion -d 'Print a shell completion script'
14
+ complete -c seccomp-tools -n __fish_use_subcommand -a disasm -d 'Disassemble seccomp bpf'
15
+ complete -c seccomp-tools -n __fish_use_subcommand -a dump -d 'Automatically dump seccomp bpf from executable(s)'
16
+ complete -c seccomp-tools -n __fish_use_subcommand -a emu -d 'Emulate seccomp rules'
17
+ complete -c seccomp-tools -n __fish_use_subcommand -a explain -d 'Summarize a filter as a per-action policy'
18
+ complete -c seccomp-tools -n __fish_use_subcommand -l version -d 'Show version'
19
+ complete -c seccomp-tools -s h -l help -d 'Show help'
20
+
21
+ # --arch, shared by the analysis commands.
22
+ complete -c seccomp-tools -n '__fish_seen_subcommand_from asm disasm emu explain audit' \
23
+ -s a -l arch -x -a 'aarch64 amd64 i386 riscv64 s390x' -d Architecture
24
+
25
+ # --format, whose valid values differ per command.
26
+ complete -c seccomp-tools -n '__fish_seen_subcommand_from asm' -s f -l format -x -a 'inspect raw c_array c_source assembly' -d 'Output format'
27
+ complete -c seccomp-tools -n '__fish_seen_subcommand_from dump' -s f -l format -x -a 'disasm raw inspect' -d 'Output format'
28
+ complete -c seccomp-tools -n '__fish_seen_subcommand_from audit' -s f -l format -x -a 'human json' -d 'Output format'
29
+
30
+ # --output takes a file.
31
+ complete -c seccomp-tools -n '__fish_seen_subcommand_from asm disasm dump' -s o -l output -r -d 'Write output to FILE'
32
+
33
+ # Options shared by the commands that read from a process.
34
+ complete -c seccomp-tools -n '__fish_seen_subcommand_from dump explain audit' -s c -l sh-exec -x -d 'Run command via sh and analyze its seccomp'
35
+ complete -c seccomp-tools -n '__fish_seen_subcommand_from dump explain audit' -s p -l pid -x -d 'Analyze a running process'
36
+ complete -c seccomp-tools -n '__fish_seen_subcommand_from dump explain audit' -s l -l limit -x -d 'Analyze only the first N filters'
37
+ complete -c seccomp-tools -n '__fish_seen_subcommand_from dump explain audit' -s t -l timeout -x -d 'Timeout in seconds'
38
+
39
+ # disasm-only flags.
40
+ complete -c seccomp-tools -n '__fish_seen_subcommand_from disasm' -l asm-able -d 'Emit output that is valid input for asm'
41
+ complete -c seccomp-tools -n '__fish_seen_subcommand_from disasm' -l no-bpf -d 'Hide the raw BPF bytes'
42
+ complete -c seccomp-tools -n '__fish_seen_subcommand_from disasm' -l no-arg-infer -d 'Do not infer argument names'
43
+
44
+ # emu-only flags.
45
+ complete -c seccomp-tools -n '__fish_seen_subcommand_from emu' -s i -l ip -x -d 'Set the instruction pointer'
46
+ complete -c seccomp-tools -n '__fish_seen_subcommand_from emu' -s q -l quiet -d 'Only show the emulation result'
47
+
48
+ # completion takes a shell name.
49
+ complete -c seccomp-tools -n '__fish_seen_subcommand_from completion' -a 'bash zsh fish' -d Shell
50
+
51
+ # The commands whose positional argument is a file/executable get file completion.
52
+ complete -c seccomp-tools -n '__fish_seen_subcommand_from asm disasm dump emu explain audit' -F
data/ext/ptrace/ptrace.c CHANGED
@@ -48,9 +48,9 @@ ptrace_peekuser(VALUE _mod, VALUE pid, VALUE off, VALUE _data, VALUE bits) {
48
48
  uint32_t val32;
49
49
  uint64_t val64;
50
50
  } val;
51
- // Dynamically allocate a buffer to store registers-well, at least enough
51
+ // Dynamically allocate a buffer to store registers - well, at least enough
52
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
53
+ // user_pt_regs or similar, but it's difficult to find it available in
54
54
  // the same header across different versions of Linux or libcs, or even with
55
55
  // the same *name*, so this is the compromise.
56
56
  size_t size = offset + width;
@@ -8,19 +8,24 @@ module SeccompTools
8
8
  module Asm
9
9
  module_function
10
10
 
11
- # Assembler of seccomp bpf.
11
+ # Compiles seccomp assembly into raw BPF bytes.
12
12
  # @param [String] str
13
+ # The assembly source to be compiled.
13
14
  # @param [String] filename
14
15
  # Only used for error messages.
15
16
  # @param [Symbol?] arch
17
+ # Target architecture, must be one of {SeccompTools::Util.supported_archs}.
18
+ # Defaults to {SeccompTools::Util.system_arch} when +nil+.
16
19
  # @return [String]
17
20
  # Raw BPF bytes.
21
+ # @raise [SeccompTools::Error]
22
+ # If +str+ is not valid seccomp assembly.
18
23
  # @example
19
24
  # SeccompTools::Asm.asm(<<-EOS)
20
- # # lines start with '#' are comments
25
+ # # lines starting with '#' are comments
21
26
  # A = sys_number # here's a comment, too
22
- # A >= 0x40000000 ? dead : next # 'next' is a keyword, denote the next instruction
23
- # A == read ? ok : next # custom defined label 'dead' and 'ok'
27
+ # A >= 0x40000000 ? dead : next # 'next' is a keyword, denoting the next instruction
28
+ # A == read ? ok : next # custom-defined labels 'dead' and 'ok'
24
29
  # A == 1 ? ok : next # SYS_write = 1 on amd64
25
30
  # return ERRNO(1)
26
31
  # dead:
@@ -12,6 +12,9 @@ module SeccompTools
12
12
  #
13
13
  # Compile seccomp rules.
14
14
  class Compiler
15
+ # The farthest distance of a relative jump in BPF.
16
+ JUMP_DISTANCE_MAX = 255
17
+
15
18
  # Instantiate a {Compiler} object.
16
19
  #
17
20
  # @param [String] source
@@ -21,17 +24,28 @@ module SeccompTools
21
24
  # @param [Symbol] arch
22
25
  # Architecture.
23
26
  def initialize(source, filename, arch)
24
- @scanner = Scanner.new(source, arch, filename: filename)
27
+ @scanner = Scanner.new(source, arch, filename:)
25
28
  @arch = arch
26
29
  @symbols = {}
27
30
  end
28
31
 
29
32
  # Compiles the processed instructions.
30
33
  #
34
+ # Scans and parses the source, resolves the labels into relative jump distances, then emits
35
+ # one {BPF} per statement.
36
+ #
31
37
  # @return [Array<SeccompTools::BPF>]
32
38
  # Returns the compiled {BPF} array.
33
- # @raise [SeccompTools::Error]
34
- # Raises the error found during compilation.
39
+ # @raise [SeccompTools::UnrecognizedTokenError]
40
+ # If the source contains text that is not valid assembly.
41
+ # @raise [SeccompTools::ParseError]
42
+ # If the tokens do not form valid statements.
43
+ # @raise [SeccompTools::DuplicateLabelError]
44
+ # If a label is defined more than once.
45
+ # @raise [SeccompTools::UndefinedLabelError]
46
+ # If a jump refers to a label that is never defined.
47
+ # @raise [SeccompTools::BackwardJumpError]
48
+ # If a jump goes backward, which BPF cannot express.
35
49
  def compile!
36
50
  @scanner.validate!
37
51
  statements = SeccompAsmParser.new(@scanner).parse
@@ -76,8 +90,18 @@ module SeccompTools
76
90
  end
77
91
  end
78
92
 
93
+ # Resolves a jump target into a relative distance from +index+.
94
+ #
79
95
  # @param [Integer] index
96
+ # Index of the statement the jump is written in.
80
97
  # @param [SeccompTools::Asm::Token, :next] sym
98
+ # The jump target, either a label token or +:next+ for the following instruction.
99
+ # @return [Integer]
100
+ # Number of instructions to skip, +0+ meaning the next instruction.
101
+ # @raise [SeccompTools::UndefinedLabelError]
102
+ # If +sym+ names a label that is never defined.
103
+ # @raise [SeccompTools::BackwardJumpError]
104
+ # If the target lies before +index+.
81
105
  def resolve_symbol(index, sym)
82
106
  return 0 if sym.is_a?(Symbol) && sym == :next
83
107
 
@@ -102,6 +126,15 @@ module SeccompTools
102
126
 
103
127
  # Emits a raw BPF object.
104
128
  #
129
+ # @param [Array<Symbol>] args
130
+ # Names of the flags to be OR-ed together into the instruction's +code+ field, looked up in
131
+ # the {Const::BPF} tables. Unknown names contribute nothing.
132
+ # @param [Integer] k
133
+ # The +k+ field, an immediate operand or a jump target.
134
+ # @param [Integer] jt
135
+ # The +jt+ field, instructions to skip when a comparison is true.
136
+ # @param [Integer] jf
137
+ # The +jf+ field, instructions to skip when a comparison is false.
105
138
  # @return [BPF]
106
139
  # Returns the emitted {BPF} object.
107
140
  def emit(*args, k: 0, jt: 0, jf: 0)
@@ -115,7 +148,7 @@ module SeccompTools
115
148
  code |= Const::BPF::OP.fetch(a, 0)
116
149
  code |= Const::BPF::MISCOP.fetch(a, 0)
117
150
  end
118
- BPF.new({ code: code, k: k, jt: jt, jf: jf }, @arch, @line)
151
+ BPF.new({ code:, k:, jt:, jf: }, @arch, @line)
119
152
  end
120
153
 
121
154
  # A = -A
@@ -144,7 +177,7 @@ module SeccompTools
144
177
 
145
178
  def emit_alu(op, val)
146
179
  src, k = val.x? ? [:x, 0] : [:k, val.to_i]
147
- emit(:alu, convert_alu_op(op), src, k: k)
180
+ emit(:alu, convert_alu_op(op), src, k:)
148
181
  end
149
182
 
150
183
  def convert_alu_op(op)
@@ -169,9 +202,6 @@ module SeccompTools
169
202
  emit(:ret, src, k: val.to_i)
170
203
  end
171
204
 
172
- # The farthest distance of a relative jump in BPF.
173
- JUMP_DISTANCE_MAX = 255
174
-
175
205
  def emit_cmp(cmp, jt_sym, jf_sym)
176
206
  jt = jt_sym[0]
177
207
  jf = jf_sym[0]
@@ -187,7 +217,7 @@ module SeccompTools
187
217
  val = cmp[1]
188
218
  src = val.x? ? :x : :k
189
219
  k = val.x? ? 0 : val.to_i
190
- emit(:jmp, jop, src, jt: jt, jf: jf, k: k)
220
+ emit(:jmp, jop, src, jt:, jf:, k:)
191
221
  end
192
222
 
193
223
  # == != >= <= > < &
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # DO NOT MODIFY!!!!
3
- # This file is automatically generated by Racc 1.4.16
4
- # from Racc grammar file "".
3
+ # This file is automatically generated by Racc 1.8.1
4
+ # from Racc grammar file "sasm.y".
5
5
  #
6
6
 
7
7
  require 'racc/parser.rb'
@@ -9,17 +9,24 @@ require 'racc/parser.rb'
9
9
  require 'seccomp-tools/asm/scalar'
10
10
  require 'seccomp-tools/asm/scanner'
11
11
  require 'seccomp-tools/asm/statement'
12
+ require 'seccomp-tools/const'
12
13
 
13
14
  module SeccompTools
14
15
  module Asm
15
16
  class SeccompAsmParser < Racc::Parser
16
17
 
17
- module_eval(<<'...end sasm.y/module_eval...', 'sasm.y', 136)
18
+ module_eval(<<'...end sasm.y/module_eval...', 'sasm.y', 138)
18
19
  def initialize(scanner)
19
20
  @scanner = scanner
20
21
  super()
21
22
  end
22
23
 
24
+ # The byte offset of the low (+hi: false+) or high 32-bit word of the 8-byte seccomp_data field
25
+ # at +base+; on a big-endian target the high word comes first.
26
+ def word_offset(base, hi:)
27
+ base + (hi == SeccompTools::Const::Endian.big?(@scanner.arch) ? 0 : 4)
28
+ end
29
+
23
30
  # @return [Array<Statement>]
24
31
  def parse
25
32
  @tokens = @scanner.scan.dup
@@ -311,6 +318,7 @@ Racc_arg = [
311
318
  racc_shift_n,
312
319
  racc_reduce_n,
313
320
  racc_use_result_var ]
321
+ Ractor.make_shareable(Racc_arg) if defined?(Ractor)
314
322
 
315
323
  Racc_token_to_s_table = [
316
324
  "$end",
@@ -387,6 +395,7 @@ Racc_token_to_s_table = [
387
395
  "alu_op",
388
396
  "args",
389
397
  "number" ]
398
+ Ractor.make_shareable(Racc_token_to_s_table) if defined?(Ractor)
390
399
 
391
400
  Racc_debug_parser = false
392
401
 
@@ -630,47 +639,48 @@ module_eval(<<'.,.,', 'sasm.y', 70)
630
639
  off = val[1] == '>>' ? 0 : -1
631
640
  raise_error("operator after an argument can only be '>> 32'", off)
632
641
  end
633
- val[0] + 4
642
+ val[0] ^ 4 # the other 32-bit word of the same 64-bit field
634
643
 
635
644
  end
636
645
  .,.,
637
646
 
638
647
  module_eval(<<'.,.,', 'sasm.y', 76)
639
648
  def _reduce_46(val, _values)
640
- 0
649
+ SeccompTools::Const::BPF::SeccompData::SYS_NUMBER
641
650
  end
642
651
  .,.,
643
652
 
644
653
  module_eval(<<'.,.,', 'sasm.y', 77)
645
654
  def _reduce_47(val, _values)
646
- 4
655
+ SeccompTools::Const::BPF::SeccompData::ARCH
647
656
  end
648
657
  .,.,
649
658
 
650
659
  module_eval(<<'.,.,', 'sasm.y', 79)
651
660
  def _reduce_48(val, _values)
652
661
  idx = val[2].to_i
653
- if idx % 4 != 0 || idx >= 64
654
- raise_error(format('index of data[] must be a multiple of 4 and less than 64, got %d', idx), -1)
662
+ size = SeccompTools::Const::BPF::SeccompData::SIZE
663
+ if idx % 4 != 0 || idx >= size
664
+ raise_error(format('index of data[] must be a multiple of 4 and less than %d, got %d', size, idx), -1)
655
665
  end
656
666
  idx
657
667
 
658
668
  end
659
669
  .,.,
660
670
 
661
- module_eval(<<'.,.,', 'sasm.y', 87)
671
+ module_eval(<<'.,.,', 'sasm.y', 88)
662
672
  def _reduce_49(val, _values)
663
673
  idx = val[2].to_i
664
674
  s = val[0]
665
675
  raise_error(format('index of %s[] must between 0 and 5, got %d', s, idx), -1) unless idx.between?(0, 5)
666
- 16 + idx * 8 + (s.downcase.end_with?('h') ? 4 : 0)
676
+ word_offset(SeccompTools::Const::BPF::SeccompData::ARGS + idx * 8, hi: s.downcase.end_with?('h'))
667
677
 
668
678
  end
669
679
  .,.,
670
680
 
671
- module_eval(<<'.,.,', 'sasm.y', 92)
681
+ module_eval(<<'.,.,', 'sasm.y', 93)
672
682
  def _reduce_50(val, _values)
673
- 8
683
+ word_offset(SeccompTools::Const::BPF::SeccompData::INSTRUCTION_POINTER, hi: false)
674
684
  end
675
685
  .,.,
676
686
 
@@ -678,7 +688,7 @@ module_eval(<<'.,.,', 'sasm.y', 92)
678
688
 
679
689
  # reduce 52 omitted
680
690
 
681
- module_eval(<<'.,.,', 'sasm.y', 95)
691
+ module_eval(<<'.,.,', 'sasm.y', 96)
682
692
  def _reduce_53(val, _values)
683
693
  val[0] + val[1]
684
694
  end
@@ -688,13 +698,13 @@ module_eval(<<'.,.,', 'sasm.y', 95)
688
698
 
689
699
  # reduce 55 omitted
690
700
 
691
- module_eval(<<'.,.,', 'sasm.y', 98)
701
+ module_eval(<<'.,.,', 'sasm.y', 99)
692
702
  def _reduce_56(val, _values)
693
703
  Scalar::ConstVal.new(val[0] & 0xffffffff)
694
704
  end
695
705
  .,.,
696
706
 
697
- module_eval(<<'.,.,', 'sasm.y', 99)
707
+ module_eval(<<'.,.,', 'sasm.y', 100)
698
708
  def _reduce_57(val, _values)
699
709
  val[1]
700
710
  end
@@ -704,37 +714,37 @@ module_eval(<<'.,.,', 'sasm.y', 99)
704
714
 
705
715
  # reduce 59 omitted
706
716
 
707
- module_eval(<<'.,.,', 'sasm.y', 102)
717
+ module_eval(<<'.,.,', 'sasm.y', 103)
708
718
  def _reduce_60(val, _values)
709
719
  Scalar::A.instance
710
720
  end
711
721
  .,.,
712
722
 
713
- module_eval(<<'.,.,', 'sasm.y', 103)
723
+ module_eval(<<'.,.,', 'sasm.y', 104)
714
724
  def _reduce_61(val, _values)
715
725
  Scalar::X.instance
716
726
  end
717
727
  .,.,
718
728
 
719
- module_eval(<<'.,.,', 'sasm.y', 104)
729
+ module_eval(<<'.,.,', 'sasm.y', 105)
720
730
  def _reduce_62(val, _values)
721
731
  val[0].to_i
722
732
  end
723
733
  .,.,
724
734
 
725
- module_eval(<<'.,.,', 'sasm.y', 105)
735
+ module_eval(<<'.,.,', 'sasm.y', 106)
726
736
  def _reduce_63(val, _values)
727
737
  val[0].to_i(16)
728
738
  end
729
739
  .,.,
730
740
 
731
- module_eval(<<'.,.,', 'sasm.y', 106)
741
+ module_eval(<<'.,.,', 'sasm.y', 107)
732
742
  def _reduce_64(val, _values)
733
743
  Const::Audit::ARCH[val[0]]
734
744
  end
735
745
  .,.,
736
746
 
737
- module_eval(<<'.,.,', 'sasm.y', 108)
747
+ module_eval(<<'.,.,', 'sasm.y', 109)
738
748
  def _reduce_65(val, _values)
739
749
  s = val[0]
740
750
  return @scanner.syscalls[s.to_sym] unless s.include?('.')
@@ -72,14 +72,15 @@ rule
72
72
  off = val[1] == '>>' ? 0 : -1
73
73
  raise_error("operator after an argument can only be '>> 32'", off)
74
74
  end
75
- val[0] + 4
75
+ val[0] ^ 4 # the other 32-bit word of the same 64-bit field
76
76
  }
77
- | SYS_NUMBER { 0 }
78
- | ARCH { 4 }
77
+ | SYS_NUMBER { SeccompTools::Const::BPF::SeccompData::SYS_NUMBER }
78
+ | ARCH { SeccompTools::Const::BPF::SeccompData::ARCH }
79
79
  | DATA LBRACK constexpr RBRACK {
80
80
  idx = val[2].to_i
81
- if idx % 4 != 0 || idx >= 64
82
- raise_error(format('index of data[] must be a multiple of 4 and less than 64, got %d', idx), -1)
81
+ size = SeccompTools::Const::BPF::SeccompData::SIZE
82
+ if idx % 4 != 0 || idx >= size
83
+ raise_error(format('index of data[] must be a multiple of 4 and less than %d, got %d', size, idx), -1)
83
84
  end
84
85
  idx
85
86
  }
@@ -88,9 +89,9 @@ rule
88
89
  idx = val[2].to_i
89
90
  s = val[0]
90
91
  raise_error(format('index of %s[] must between 0 and 5, got %d', s, idx), -1) unless idx.between?(0, 5)
91
- 16 + idx * 8 + (s.downcase.end_with?('h') ? 4 : 0)
92
+ word_offset(SeccompTools::Const::BPF::SeccompData::ARGS + idx * 8, hi: s.downcase.end_with?('h'))
92
93
  }
93
- | INSTRUCTION_POINTER { 8 }
94
+ | INSTRUCTION_POINTER { word_offset(SeccompTools::Const::BPF::SeccompData::INSTRUCTION_POINTER, hi: false) }
94
95
  args: ARGS
95
96
  | ARGS_H
96
97
  alu_op_eq: alu_op ASSIGN { val[0] + val[1] }
@@ -131,6 +132,7 @@ end
131
132
  require 'seccomp-tools/asm/scalar'
132
133
  require 'seccomp-tools/asm/scanner'
133
134
  require 'seccomp-tools/asm/statement'
135
+ require 'seccomp-tools/const'
134
136
 
135
137
  ---- inner
136
138
  def initialize(scanner)
@@ -138,6 +140,12 @@ require 'seccomp-tools/asm/statement'
138
140
  super()
139
141
  end
140
142
 
143
+ # The byte offset of the low (+hi: false+) or high 32-bit word of the 8-byte seccomp_data field
144
+ # at +base+; on a big-endian target the high word comes first.
145
+ def word_offset(base, hi:)
146
+ base + (hi == SeccompTools::Const::Endian.big?(@scanner.arch) ? 0 : 4)
147
+ end
148
+
141
149
  # @return [Array<Statement>]
142
150
  def parse
143
151
  @tokens = @scanner.scan.dup