Skip to content

Commit

Permalink
hclsyntax: Impose an upper limit on a refined prefix in TemplateExpr
Browse files Browse the repository at this point in the history
There is no limit to the length of string prefixes produced by template
expressions, so in rare cases they may return a refined unknown string
has too long a prefix.

The cty's msgpack decoder limits the size of an acceptable refinements
to 1 kiB, so such a value cannot be handled and an error occurs.

This change limits the length of prefixes to 128 B, so overly long
prefixes are no longer an issue in most cases.
  • Loading branch information
wata727 authored and apparentlymart committed Jul 7, 2023
1 parent 7208bce commit 527ec31
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 1 deletion.
11 changes: 10 additions & 1 deletion hclsyntax/expression_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,16 @@ func (e *TemplateExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics)
ret = cty.UnknownVal(cty.String)
if !diags.HasErrors() { // Invalid input means our partial result buffer is suspect
if knownPrefix := buf.String(); knownPrefix != "" {
ret = ret.Refine().StringPrefix(knownPrefix).NewValue()
byteLen := len(knownPrefix)
// Impose a reasonable upper limit to avoid producing too long a prefix.
// The 128 B is about 10% of the safety limits in cty's msgpack decoder.
// @see https://github.com/zclconf/go-cty/blob/v1.13.2/cty/msgpack/unknown.go#L170-L175
//
// This operation is safe because StringPrefix removes incomplete trailing grapheme clusters.
if byteLen > 128 { // arbitrarily-decided threshold
byteLen = 128
}
ret = ret.Refine().StringPrefix(knownPrefix[:byteLen]).NewValue()
}
}
} else {
Expand Down
11 changes: 11 additions & 0 deletions hclsyntax/expression_template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package hclsyntax

import (
"strings"
"testing"

"github.com/hashicorp/hcl/v2"
Expand Down Expand Up @@ -307,6 +308,16 @@ trim`,
cty.UnknownVal(cty.String).Refine().NotNull().StringPrefixFull("test_known_").NewValue(),
0,
},
{ // can preserve a static prefix as a refinement, but the length is limited to 128 B
strings.Repeat("_", 130) + `${unknown}`,
&hcl.EvalContext{
Variables: map[string]cty.Value{
"unknown": cty.UnknownVal(cty.String),
},
},
cty.UnknownVal(cty.String).Refine().NotNull().StringPrefixFull(strings.Repeat("_", 128)).NewValue(),
0,
},
{ // marks from uninterpolated values are ignored
`hello%{ if false } ${target}%{ endif }`,
&hcl.EvalContext{
Expand Down

0 comments on commit 527ec31

Please sign in to comment.