From ba973ef9b95f3457181b7b1a7739422eedda44f0 Mon Sep 17 00:00:00 2001 From: Ville Vesilehto Date: Wed, 14 Jan 2026 23:39:17 +0200 Subject: [PATCH] fix(vm): validate arg count before OpCall Prevent index out of bounds panic when calling a function with more arguments than it accepts. The VM now validates argument count before attempting to access parameter types. Includes a regression test. This issue was discovered by clusterfuzz with the expression: $env(''matches' '? :now().UTC(g).d)// Signed-off-by: Ville Vesilehto --- test/fuzz/fuzz_test.go | 1 + vm/vm.go | 11 ++++++++++- vm/vm_test.go | 19 +++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/test/fuzz/fuzz_test.go b/test/fuzz/fuzz_test.go index 1be7b11d..684df025 100644 --- a/test/fuzz/fuzz_test.go +++ b/test/fuzz/fuzz_test.go @@ -40,6 +40,7 @@ func FuzzExpr(f *testing.F) { regexp.MustCompile(`reflect.Value.MapIndex: value of type .* is not assignable to type .*`), regexp.MustCompile(`reflect: Call using .* as type .*`), regexp.MustCompile(`reflect: Call with too few input arguments`), + regexp.MustCompile(`invalid number of arguments`), regexp.MustCompile(`reflect: call of reflect.Value.Call on .* Value`), regexp.MustCompile(`reflect: call of reflect.Value.Index on map Value`), regexp.MustCompile(`reflect: call of reflect.Value.Len on .* Value`), diff --git a/vm/vm.go b/vm/vm.go index 3c7a2b3f..69c379b2 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -372,9 +372,18 @@ func (vm *VM) Run(program *Program, env any) (_ any, err error) { } fnType := fn.Type() size := arg - in := make([]reflect.Value, size) isVariadic := fnType.IsVariadic() numIn := fnType.NumIn() + if isVariadic { + if size < numIn-1 { + panic(fmt.Sprintf("invalid number of arguments: expected at least %d, got %d", numIn-1, size)) + } + } else { + if size != numIn { + panic(fmt.Sprintf("invalid number of arguments: expected %d, got %d", numIn, size)) + } + } + in := make([]reflect.Value, size) for i := int(size) - 1; i >= 0; i-- { param := vm.pop() if param == nil { diff --git a/vm/vm_test.go b/vm/vm_test.go index 6038abca..355f764e 100644 --- a/vm/vm_test.go +++ b/vm/vm_test.go @@ -1491,3 +1491,22 @@ func TestVM_StackUnderflow(t *testing.T) { }) } } + +func TestVM_OpCall_InvalidNumberOfArguments(t *testing.T) { + // This test ensures that calling a function with wrong number of arguments + // produces a clear error message instead of a panic. + // Regression test for clusterfuzz issue with expression: + // $env(''matches' '? :now().UTC(g).d)// + + env := map[string]any{ + "ok": true, + } + + code := `$env('' matches ' '? : now().UTC(g))` + program, err := expr.Compile(code, expr.Env(env)) + require.NoError(t, err) + + _, err = expr.Run(program, env) + require.Error(t, err) + require.Contains(t, err.Error(), "invalid number of arguments") +}