aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
author6543 <6543@obermui.de>2021-01-20 19:47:30 +0100
committerGitHub <noreply@github.com>2021-01-20 20:47:30 +0200
commitfb274ec54b56d0126bdde024d5316309c83fcc0b (patch)
tree4203adad32eb0a8acb1b0efc889e316475d7b0d6
parent0c3f95034a91a448ae0d96d88a0d8b0f53a9b4a7 (diff)
downloadgitea-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.go38
-rw-r--r--modules/markup/html_test.go25
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")
+}