diff --git a/lib/seccomp-tools/asm/compiler.rb b/lib/seccomp-tools/asm/compiler.rb index 139bd43..f187aaf 100644 --- a/lib/seccomp-tools/asm/compiler.rb +++ b/lib/seccomp-tools/asm/compiler.rb @@ -76,6 +76,9 @@ def resolve_symbols(statements) end end + # The farthest distance of a relative jump in BPF. + JUMP_DISTANCE_MAX = 255 + # @param [Integer] index # @param [SeccompTools::Asm::Token, :next] sym def resolve_symbol(index, sym) @@ -86,18 +89,22 @@ def resolve_symbol(index, sym) if @symbols[str].nil? # special case - goto can be considered as $+1+ - return str.to_i if str == str.to_i.to_s + return str.to_i if str == str.to_i.to_s && str.to_i <= JUMP_DISTANCE_MAX raise SeccompTools::UndefinedLabelError, @scanner.format_error(sym, "Cannot find label '#{str}'") end - if @symbols[str][1] <= index - raise SeccompTools::BackwardJumpError, - @scanner.format_error(sym, - "Does not support backward jumping to '#{str}'") - end - @symbols[str][1] - index - 1 + (@symbols[str][1] - index - 1).tap do |dis| + if dis.negative? + raise SeccompTools::BackwardJumpError, + @scanner.format_error(sym, "Does not support backward jumping to '#{str}'") + end + if dis > JUMP_DISTANCE_MAX + raise SeccompTools::LongJumpError, + @scanner.format_error(sym, "Does not support jumping farther than #{JUMP_DISTANCE_MAX}, got: #{dis}") + end + end end # Emits a raw BPF object. diff --git a/lib/seccomp-tools/error.rb b/lib/seccomp-tools/error.rb index 89ab41b..466bdb6 100644 --- a/lib/seccomp-tools/error.rb +++ b/lib/seccomp-tools/error.rb @@ -24,4 +24,8 @@ class BackwardJumpError < Error # Raised when a label is defined more than once on compiling seccomp assembly. class DuplicateLabelError < Error end + + # Raised when a jump is longer than supported distance. + class LongJumpError < Error + end end diff --git a/spec/asm/compiler_spec.rb b/spec/asm/compiler_spec.rb index 2b94bf7..9f4d696 100644 --- a/spec/asm/compiler_spec.rb +++ b/spec/asm/compiler_spec.rb @@ -224,5 +224,20 @@ ^^^^^ EOS end + + it 'raises on long jump' do + compiler = described_class.new(<<-EOS, nil, :amd64) + A = args[0] + A == 0 ? next : end +#{"A = 0\n" * 260} +end: return ALLOW + EOS + + expect { compiler.compile! }.to raise_error(SeccompTools::LongJumpError, <<-EOS) +:2:24 Does not support jumping farther than 255, got: 260 + A == 0 ? next : end + ^^^ + EOS + end end end