diff options
author | 6543 <6543@obermui.de> | 2021-01-20 19:47:30 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-20 20:47:30 +0200 |
commit | fb274ec54b56d0126bdde024d5316309c83fcc0b (patch) | |
tree | 4203adad32eb0a8acb1b0efc889e316475d7b0d6 | |
parent | 0c3f95034a91a448ae0d96d88a0d8b0f53a9b4a7 (diff) | |
download | gitea-fb274ec54b56d0126bdde024d5316309c83fcc0b.tar.gz gitea-fb274ec54b56d0126bdde024d5316309c83fcc0b.zip |
Prevent panic on fuzzer provided string (#14405) (#14409)
* Prevent panic on fuzzer provided string
The fuzzer has found that providing a <body> tag with an attribute to
PostProcess causes a panic. This PR removes any rendered html or body
tags from the output.
Signed-off-by: Andrew Thornton <art27@cantab.net>
* Placate lint
* placate lint again
Signed-off-by: Andrew Thornton <art27@cantab.net>
* minor cleanup
Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: zeripath <art27@cantab.net>
-rw-r--r-- | modules/markup/html.go | 38 | ||||
-rw-r--r-- | modules/markup/html_test.go | 25 |
2 files changed, 53 insertions, 10 deletions
diff --git a/modules/markup/html.go b/modules/markup/html.go index 0c2fff3e01..1d4a9be58c 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -298,9 +298,6 @@ func RenderEmoji( return ctx.postProcess(rawHTML) } -var byteBodyTag = []byte("<body>") -var byteBodyTagClosing = []byte("</body>") - func (ctx *postProcessCtx) postProcess(rawHTML []byte) ([]byte, error) { if ctx.procs == nil { ctx.procs = defaultProcessors @@ -308,9 +305,9 @@ func (ctx *postProcessCtx) postProcess(rawHTML []byte) ([]byte, error) { // give a generous extra 50 bytes res := make([]byte, 0, len(rawHTML)+50) - res = append(res, byteBodyTag...) + res = append(res, "<html><body>"...) res = append(res, rawHTML...) - res = append(res, byteBodyTagClosing...) + res = append(res, "</body></html>"...) // parse the HTML nodes, err := html.ParseFragment(bytes.NewReader(res), nil) @@ -322,6 +319,31 @@ func (ctx *postProcessCtx) postProcess(rawHTML []byte) ([]byte, error) { ctx.visitNode(node, true) } + newNodes := make([]*html.Node, 0, len(nodes)) + + for _, node := range nodes { + if node.Data == "html" { + node = node.FirstChild + for node != nil && node.Data != "body" { + node = node.NextSibling + } + } + if node == nil { + continue + } + if node.Data == "body" { + child := node.FirstChild + for child != nil { + newNodes = append(newNodes, child) + child = child.NextSibling + } + } else { + newNodes = append(newNodes, node) + } + } + + nodes = newNodes + // Create buffer in which the data will be placed again. We know that the // length will be at least that of res; to spare a few alloc+copy, we // reuse res, resetting its length to 0. @@ -334,12 +356,8 @@ func (ctx *postProcessCtx) postProcess(rawHTML []byte) ([]byte, error) { } } - // remove initial parts - because Render creates a whole HTML page. - res = buf.Bytes() - res = res[bytes.Index(res, byteBodyTag)+len(byteBodyTag) : bytes.LastIndex(res, byteBodyTagClosing)] - // Everything done successfully, return parsed data. - return res, nil + return buf.Bytes(), nil } func (ctx *postProcessCtx) visitNode(node *html.Node, visitText bool) { diff --git a/modules/markup/html_test.go b/modules/markup/html_test.go index b04781489a..a78b936f87 100644 --- a/modules/markup/html_test.go +++ b/modules/markup/html_test.go @@ -383,3 +383,28 @@ func TestRender_ShortLinks(t *testing.T) { `<p><a href="https://example.org" rel="nofollow">[[foobar]]</a></p>`, `<p><a href="https://example.org" rel="nofollow">[[foobar]]</a></p>`) } + +func Test_ParseClusterFuzz(t *testing.T) { + setting.AppURL = AppURL + setting.AppSubURL = AppSubURL + + var localMetas = map[string]string{ + "user": "go-gitea", + "repo": "gitea", + } + + data := "<A><maTH><tr><MN><bodY ÿ><temPlate></template><tH><tr></A><tH><d<bodY " + + val, err := PostProcess([]byte(data), "https://example.com", localMetas, false) + + assert.NoError(t, err) + assert.NotContains(t, string(val), "<html") + + data = "<!DOCTYPE html>\n<A><maTH><tr><MN><bodY ÿ><temPlate></template><tH><tr></A><tH><d<bodY " + + val, err = PostProcess([]byte(data), "https://example.com", localMetas, false) + + assert.NoError(t, err) + + assert.NotContains(t, string(val), "<html") +} |