From 01dd7c16af6204d18d530f9d3018689215482170 Mon Sep 17 00:00:00 2001 From: gzagatti Date: Mon, 11 Jan 2021 16:46:31 +0800 Subject: [PATCH] Fixes #7698. markup: Allow installed arbitrary Asciidoc extension via path validation. --- docs/content/en/content-management/formats.md | 2 + .../asciidocext/asciidocext_config/config.go | 12 ----- markup/asciidocext/convert.go | 6 +-- markup/asciidocext/convert_test.go | 46 ++++++++++++++++--- 4 files changed, 44 insertions(+), 22 deletions(-) diff --git a/docs/content/en/content-management/formats.md b/docs/content/en/content-management/formats.md index 576ce2fa3..5654be7f0 100644 --- a/docs/content/en/content-management/formats.md +++ b/docs/content/en/content-management/formats.md @@ -100,6 +100,8 @@ Below are all the AsciiDoc related settings in Hugo with their default values: {{< code-toggle config="markup.asciidocExt" />}} +Notice that for security concerns only extensions that do not have path separators (either `\`, `/` or `.`) are allowed. That means that extensions can only be invoked if they are in one's ruby's `$LOAD_PATH` (ie. most likely, the extension has been installed by the user). Any extension declared relative to the website's path will not be accepted. + Example of how to set extensions and attributes: ``` diff --git a/markup/asciidocext/asciidocext_config/config.go b/markup/asciidocext/asciidocext_config/config.go index ac6e0cda4..1409b2783 100644 --- a/markup/asciidocext/asciidocext_config/config.go +++ b/markup/asciidocext/asciidocext_config/config.go @@ -37,18 +37,6 @@ var ( FailureLevel: "fatal", } - AllowedExtensions = map[string]bool{ - "asciidoctor-html5s": true, - "asciidoctor-bibtex": true, - "asciidoctor-diagram": true, - "asciidoctor-interdoc-reftext": true, - "asciidoctor-katex": true, - "asciidoctor-latex": true, - "asciidoctor-mathematical": true, - "asciidoctor-question": true, - "asciidoctor-rouge": true, - } - AllowedSafeMode = map[string]bool{ "unsafe": true, "safe": true, diff --git a/markup/asciidocext/convert.go b/markup/asciidocext/convert.go index 51f114be2..10e16810e 100644 --- a/markup/asciidocext/convert.go +++ b/markup/asciidocext/convert.go @@ -19,6 +19,7 @@ package asciidocext import ( "bytes" "path/filepath" + "strings" "github.com/gohugoio/hugo/htesting" @@ -105,11 +106,10 @@ func (a *asciidocConverter) parseArgs(ctx converter.DocumentContext) []string { args = a.appendArg(args, "-b", cfg.Backend, asciidocext_config.CliDefault.Backend, asciidocext_config.AllowedBackend) for _, extension := range cfg.Extensions { - if !asciidocext_config.AllowedExtensions[extension] { - a.cfg.Logger.Errorln("Unsupported asciidoctor extension was passed in. Extension `" + extension + "` ignored.") + if strings.LastIndexAny(extension, `\/.`) > -1 { + a.cfg.Logger.Errorln("Unsupported asciidoctor extension was passed in. Extension `" + extension + "` ignored. Only installed asciidoctor extensions are allowed.") continue } - args = append(args, "-r", extension) } diff --git a/markup/asciidocext/convert_test.go b/markup/asciidocext/convert_test.go index fa3aef404..4c183f7bb 100644 --- a/markup/asciidocext/convert_test.go +++ b/markup/asciidocext/convert_test.go @@ -91,7 +91,7 @@ func TestAsciidoctorDisallowedArgs(t *testing.T) { cfg := viper.New() mconf := markup_config.Default mconf.AsciidocExt.Backend = "disallowed-backend" - mconf.AsciidocExt.Extensions = []string{"disallowed-extension"} + mconf.AsciidocExt.Extensions = []string{"./disallowed-extension"} mconf.AsciidocExt.Attributes = map[string]string{"outdir": "disallowed-attribute"} mconf.AsciidocExt.SafeMode = "disallowed-safemode" mconf.AsciidocExt.FailureLevel = "disallowed-failurelevel" @@ -115,14 +115,11 @@ func TestAsciidoctorDisallowedArgs(t *testing.T) { c.Assert(args, qt.DeepEquals, expected) } -func TestAsciidoctorDiagramArgs(t *testing.T) { +func TestAsciidoctorArbitraryExtension(t *testing.T) { c := qt.New(t) cfg := viper.New() mconf := markup_config.Default - mconf.AsciidocExt.NoHeaderOrFooter = true - mconf.AsciidocExt.Extensions = []string{"asciidoctor-html5s", "asciidoctor-diagram"} - mconf.AsciidocExt.Backend = "html5s" - mconf.AsciidocExt.Trace = false + mconf.AsciidocExt.Extensions = []string{"arbitrary-extension"} p, err := Provider.New( converter.ProviderConfig{ Cfg: cfg, @@ -139,10 +136,45 @@ func TestAsciidoctorDiagramArgs(t *testing.T) { c.Assert(ac, qt.Not(qt.IsNil)) args := ac.parseArgs(converter.DocumentContext{}) - expected := []string{"-b", "html5s", "-r", "asciidoctor-html5s", "-r", "asciidoctor-diagram", "--no-header-footer"} + expected := []string{"-r", "arbitrary-extension", "--no-header-footer"} c.Assert(args, qt.DeepEquals, expected) } +func TestAsciidoctorDisallowedExtension(t *testing.T) { + c := qt.New(t) + cfg := viper.New() + for _, disallowedExtension := range []string{ + `foo-bar//`, + `foo-bar\\ `, + `../../foo-bar`, + `/foo-bar`, + `C:\foo-bar`, + `foo-bar.rb`, + `foo.bar`, + } { + mconf := markup_config.Default + mconf.AsciidocExt.Extensions = []string{disallowedExtension} + p, err := Provider.New( + converter.ProviderConfig{ + Cfg: cfg, + MarkupConfig: mconf, + Logger: loggers.NewErrorLogger(), + }, + ) + c.Assert(err, qt.IsNil) + + conv, err := p.New(converter.DocumentContext{}) + c.Assert(err, qt.IsNil) + + ac := conv.(*asciidocConverter) + c.Assert(ac, qt.Not(qt.IsNil)) + + args := ac.parseArgs(converter.DocumentContext{}) + expected := []string{"--no-header-footer"} + c.Assert(args, qt.DeepEquals, expected) + } +} + func TestAsciidoctorWorkingFolderCurrent(t *testing.T) { c := qt.New(t) cfg := viper.New()