diff --git a/pkg/yqlib/operator_multiply.go b/pkg/yqlib/operator_multiply.go index b32ee3454c..9db2c4f5ab 100644 --- a/pkg/yqlib/operator_multiply.go +++ b/pkg/yqlib/operator_multiply.go @@ -155,8 +155,10 @@ func repeatString(lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error return nil, err } else if count < 0 { return nil, fmt.Errorf("cannot repeat string by a negative number (%v)", count) - } else if count > 10000000 { - return nil, fmt.Errorf("cannot repeat string by more than 100 million (%v)", count) + } + maxResultLen := 10 * 1024 * 1024 // 10 MiB + if count > 0 && len(stringNode.Value) > maxResultLen/count { + return nil, fmt.Errorf("result of repeating string (%v bytes) by %v would exceed %v bytes", len(stringNode.Value), count, maxResultLen) } target.Value = strings.Repeat(stringNode.Value, count) diff --git a/pkg/yqlib/operator_multiply_test.go b/pkg/yqlib/operator_multiply_test.go index 7efeb52498..2f233eaf31 100644 --- a/pkg/yqlib/operator_multiply_test.go +++ b/pkg/yqlib/operator_multiply_test.go @@ -237,12 +237,11 @@ var multiplyOperatorScenarios = []expressionScenario{ expectedError: "cannot repeat string by a negative number (-4)", }, { - description: "Multiply string X by more than 100 million", - // very large string.repeats causes a panic + description: "Multiply string by count that exceeds result size limit", skipDoc: true, document: `n: 100000001`, expression: `"banana" * .n`, - expectedError: "cannot repeat string by more than 100 million (100000001)", + expectedError: "result of repeating string (6 bytes) by 100000001 would exceed 10485760 bytes", }, { description: "Multiply int node X string", @@ -693,6 +692,27 @@ var multiplyOperatorScenarios = []expressionScenario{ "D0, P[], (!!null)::null\n", }, }, + { + // Regression test for https://issues.oss-fuzz.com/issues/418818862 + // Large repeat count with a long string must not panic. + skipDoc: true, + expression: `"abc" * 99999999`, + expectedError: "result of repeating string (3 bytes) by 99999999 would exceed 10485760 bytes", + }, + { + // Regression test for https://issues.oss-fuzz.com/issues/383195001 + // Product of string length * repeat count must be bounded. + skipDoc: true, + expression: `"x" * 99999999`, + expectedError: "result of repeating string (1 bytes) by 99999999 would exceed 10485760 bytes", + }, + { + // The size guard must not overflow: len * count can wrap to + // a negative or small value on 64-bit, bypassing the check. + skipDoc: true, + expression: `"ab" * 4611686018427387904`, + expectedError: "result of repeating string (2 bytes) by 4611686018427387904 would exceed 10485760 bytes", + }, } func TestMultiplyOperatorScenarios(t *testing.T) {