Skip to content

Commit 29289d4

Browse files
committed
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 <[email protected]>
1 parent e05670d commit 29289d4

File tree

2 files changed

+54
-6
lines changed

2 files changed

+54
-6
lines changed

modules/markup/html.go

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -317,8 +317,8 @@ func RenderEmoji(
317317
return ctx.postProcess(rawHTML)
318318
}
319319

320-
var byteBodyTag = []byte("<body>")
321-
var byteBodyTagClosing = []byte("</body>")
320+
const byteBodyTag = "<body>"
321+
const byteBodyTagClosing = "</body>"
322322

323323
func (ctx *postProcessCtx) postProcess(rawHTML []byte) ([]byte, error) {
324324
if ctx.procs == nil {
@@ -327,9 +327,9 @@ func (ctx *postProcessCtx) postProcess(rawHTML []byte) ([]byte, error) {
327327

328328
// give a generous extra 50 bytes
329329
res := make([]byte, 0, len(rawHTML)+50)
330-
res = append(res, byteBodyTag...)
330+
res = append(res, "<html><body>"...)
331331
res = append(res, rawHTML...)
332-
res = append(res, byteBodyTagClosing...)
332+
res = append(res, "</body></html>"...)
333333

334334
// parse the HTML
335335
nodes, err := html.ParseFragment(bytes.NewReader(res), nil)
@@ -341,6 +341,31 @@ func (ctx *postProcessCtx) postProcess(rawHTML []byte) ([]byte, error) {
341341
ctx.visitNode(node, true)
342342
}
343343

344+
newNodes := make([]*html.Node, 0, len(nodes))
345+
346+
for _, node := range nodes {
347+
if node.Data == "html" {
348+
node = node.FirstChild
349+
for node != nil && node.Data != "body" {
350+
node = node.NextSibling
351+
}
352+
}
353+
if node == nil {
354+
continue
355+
}
356+
if node.Data == "body" {
357+
child := node.FirstChild
358+
for child != nil {
359+
newNodes = append(newNodes, child)
360+
child = child.NextSibling
361+
}
362+
} else {
363+
newNodes = append(newNodes, node)
364+
}
365+
}
366+
367+
nodes = newNodes
368+
344369
// Create buffer in which the data will be placed again. We know that the
345370
// length will be at least that of res; to spare a few alloc+copy, we
346371
// reuse res, resetting its length to 0.
@@ -353,9 +378,7 @@ func (ctx *postProcessCtx) postProcess(rawHTML []byte) ([]byte, error) {
353378
}
354379
}
355380

356-
// remove initial parts - because Render creates a whole HTML page.
357381
res = buf.Bytes()
358-
res = res[bytes.Index(res, byteBodyTag)+len(byteBodyTag) : bytes.LastIndex(res, byteBodyTagClosing)]
359382

360383
// Everything done successfully, return parsed data.
361384
return res, nil

modules/markup/html_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,3 +383,28 @@ func TestRender_ShortLinks(t *testing.T) {
383383
`<p><a href="https://example.org" rel="nofollow">[[foobar]]</a></p>`,
384384
`<p><a href="https://example.org" rel="nofollow">[[foobar]]</a></p>`)
385385
}
386+
387+
func Test_ParseClusterFuzz(t *testing.T) {
388+
setting.AppURL = AppURL
389+
setting.AppSubURL = AppSubURL
390+
391+
var localMetas = map[string]string{
392+
"user": "go-gitea",
393+
"repo": "gitea",
394+
}
395+
396+
data := "<A><maTH><tr><MN><bodY ÿ><temPlate></template><tH><tr></A><tH><d<bodY "
397+
398+
val, err := PostProcess([]byte(data), "https://example.com", localMetas, false)
399+
400+
assert.NoError(t, err)
401+
assert.NotContains(t, string(val), "<html")
402+
403+
data = "<!DOCTYPE html>\n<A><maTH><tr><MN><bodY ÿ><temPlate></template><tH><tr></A><tH><d<bodY "
404+
405+
val, err = PostProcess([]byte(data), "https://example.com", localMetas, false)
406+
407+
assert.NoError(t, err)
408+
409+
assert.NotContains(t, string(val), "<html")
410+
}

0 commit comments

Comments
 (0)