Skip to content

Commit

Permalink
mod/modfile: parse module.cue in data-only mode
Browse files Browse the repository at this point in the history
This reduces the surface for denial of service attacks involving
arbitrary computations via the module.cue file.

Fixes #3138.

Signed-off-by: Roger Peppe <rogpeppe@gmail.com>
Change-Id: If58c8d3a7b05a657543909bf9d1ebaaf4296d039
  • Loading branch information
rogpeppe committed May 13, 2024
1 parent 185426f commit 9849be9
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 5 deletions.
29 changes: 24 additions & 5 deletions mod/modfile/modfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,14 @@ import (

"cuelang.org/go/cue"
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/build"
"cuelang.org/go/cue/cuecontext"
"cuelang.org/go/cue/errors"
"cuelang.org/go/cue/format"
"cuelang.org/go/cue/parser"
"cuelang.org/go/cue/token"
"cuelang.org/go/internal/cueversion"
"cuelang.org/go/internal/encoding"
"cuelang.org/go/internal/filetypes"
"cuelang.org/go/mod/module"
)

Expand Down Expand Up @@ -255,14 +257,14 @@ func ParseNonStrict(modfile []byte, filename string) (*File, error) {
}

func parse(modfile []byte, filename string, strict bool) (*File, error) {
file, err := parser.ParseFile(filename, modfile)
// Unfortunately we need a new context. See the note inside [moduleSchemaDo].
ctx := cuecontext.New()
file, err := parseDataOnlyCUE(ctx, modfile, filename)
if err != nil {
return nil, errors.Wrapf(err, token.NoPos, "invalid module.cue file syntax")
}
// TODO disallow non-data-mode CUE.

// Unfortunate to need a new context, but see the note inside [moduleSchemaDo].
v := cuecontext.New().BuildFile(file)
v := ctx.BuildFile(file)
if err := v.Validate(cue.Concrete(true)); err != nil {
return nil, errors.Wrapf(err, token.NoPos, "invalid module.cue file value")
}
Expand Down Expand Up @@ -389,6 +391,23 @@ func parse(modfile []byte, filename string, strict bool) (*File, error) {
return mf, nil
}

func parseDataOnlyCUE(ctx *cue.Context, cueData []byte, filename string) (*ast.File, error) {
dec := encoding.NewDecoder(ctx, &build.File{
Filename: filename,
Encoding: build.CUE,
Interpretation: build.Auto,
Form: build.Data,
Source: cueData,
}, &encoding.Config{
Mode: filetypes.Export,
AllErrors: true,
})
if err := dec.Err(); err != nil {
return nil, err
}
return dec.File(), nil
}

func newCUEError(err error, filename string) error {
ps := errors.Positions(err)
for _, p := range ps {
Expand Down
32 changes: 32 additions & 0 deletions mod/modfile/modfile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,38 @@ cue: lang: "xxx"
want: &File{
Module: "foo.com/bar",
},
}, {
testName: "ReferencesNotAllowed#1",
parse: Parse,
data: `
module: "foo.com/bar"
_foo: "v0.9.0"
cue: lang: _foo
`,
wantError: `invalid module.cue file syntax: references not allowed in data mode:
module.cue:4:12`,
}, {
testName: "ReferencesNotAllowed#2",
parse: Parse,
data: `
module: "foo.com/bar"
let foo = "v0.9.0"
cue: lang: foo
`,
wantError: `invalid module.cue file syntax: references not allowed in data mode:
module.cue:3:1
invalid module.cue file syntax: references not allowed in data mode:
module.cue:4:12`,
}, {
testName: "DefinitionsNotAllowed",
parse: Parse,
data: `
module: "foo.com/bar"
#x: "v0.9.0"
cue: lang: "v0.9.0"
`,
wantError: `invalid module.cue file syntax: definitions not allowed in data mode:
module.cue:3:1`,
}}

func TestParse(t *testing.T) {
Expand Down

0 comments on commit 9849be9

Please sign in to comment.