Skip to content

Commit ba973ef

Browse files
committed
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 <ville@vesilehto.fi>
1 parent 4ff281d commit ba973ef

File tree

3 files changed

+30
-1
lines changed

3 files changed

+30
-1
lines changed

test/fuzz/fuzz_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ func FuzzExpr(f *testing.F) {
4040
regexp.MustCompile(`reflect.Value.MapIndex: value of type .* is not assignable to type .*`),
4141
regexp.MustCompile(`reflect: Call using .* as type .*`),
4242
regexp.MustCompile(`reflect: Call with too few input arguments`),
43+
regexp.MustCompile(`invalid number of arguments`),
4344
regexp.MustCompile(`reflect: call of reflect.Value.Call on .* Value`),
4445
regexp.MustCompile(`reflect: call of reflect.Value.Index on map Value`),
4546
regexp.MustCompile(`reflect: call of reflect.Value.Len on .* Value`),

vm/vm.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,9 +372,18 @@ func (vm *VM) Run(program *Program, env any) (_ any, err error) {
372372
}
373373
fnType := fn.Type()
374374
size := arg
375-
in := make([]reflect.Value, size)
376375
isVariadic := fnType.IsVariadic()
377376
numIn := fnType.NumIn()
377+
if isVariadic {
378+
if size < numIn-1 {
379+
panic(fmt.Sprintf("invalid number of arguments: expected at least %d, got %d", numIn-1, size))
380+
}
381+
} else {
382+
if size != numIn {
383+
panic(fmt.Sprintf("invalid number of arguments: expected %d, got %d", numIn, size))
384+
}
385+
}
386+
in := make([]reflect.Value, size)
378387
for i := int(size) - 1; i >= 0; i-- {
379388
param := vm.pop()
380389
if param == nil {

vm/vm_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1491,3 +1491,22 @@ func TestVM_StackUnderflow(t *testing.T) {
14911491
})
14921492
}
14931493
}
1494+
1495+
func TestVM_OpCall_InvalidNumberOfArguments(t *testing.T) {
1496+
// This test ensures that calling a function with wrong number of arguments
1497+
// produces a clear error message instead of a panic.
1498+
// Regression test for clusterfuzz issue with expression:
1499+
// $env(''matches' '? :now().UTC(g).d)//
1500+
1501+
env := map[string]any{
1502+
"ok": true,
1503+
}
1504+
1505+
code := `$env('' matches ' '? : now().UTC(g))`
1506+
program, err := expr.Compile(code, expr.Env(env))
1507+
require.NoError(t, err)
1508+
1509+
_, err = expr.Run(program, env)
1510+
require.Error(t, err)
1511+
require.Contains(t, err.Error(), "invalid number of arguments")
1512+
}

0 commit comments

Comments
 (0)