image/jpeg: excessive memory usage
dvyukov opened this issue · 5 comments
The following program consumes 1.3GB of memory to produce:
decode failed: invalid JPEG format: bad Huffman code
Not sure whether it is OK or not, since the format is compressed probably the image bounds are large. But still it is suspicious for the tiny input file.
package main
import (
"bytes"
"encoding/hex"
"fmt"
"image/jpeg"
)
func main() {
data, _ := hex.DecodeString(input)
img, err := jpeg.Decode(bytes.NewReader(data))
if err != nil {
fmt.Printf("decode failed: %v\n", err)
return
}
fmt.Printf("bounds: %+v\n", img.Bounds())
var w bytes.Buffer
err = jpeg.Encode(&w, img, nil)
if err != nil {
panic(err)
}
}
var input = "ffd8ffe000104a46494600010100000100010000ffdb004300100b0c0e0c0a10" +
"0e0d0e121110131828de1816161834363125000000fe3c3c3933383440485c4e" +
"17116df646ddaa1cd09c404457453738506d51575f626768673e4d7179706478" +
"5c656763ffc2000b08ff80fe9501011100ffc4001a0000020301010000000000" +
"00000000000003040102050006ffda00080101000000011badd2b348270c4c0c" +
"3c2232968cf52a22aa801c6415211cb2ef440c4100000064a18f7f424ea33141" +
"2f2aa1a26caaaf11bda026af5028b19365cec317116df646ddaa1cd09cc952bd" +
"5882346354852873acc677067ae20e80236cddcb32a9427124aeac67eca68ec9" +
"42551460c5e81674c53759f8eb03"
go version devel +87054c4 Wed Apr 22 02:50:48 2015 +0000 linux/amd64
The image bounds are large. The fragment "ffc2000b08ff80fe95" means a Start-Of-Frame marker "ffc2" whose height and width are 0xff80 and 0xfe95. In other words, the image claims to be 65173 x 65408, or over 4 billion pixels.
See also issue #5050.
Closing as WAI.
I am very sad that this issue is not taken seriously and closed as WAI. It is a real security threat and can easily be used for DoS attacks. For example, https://hackerone.com/reports/390
I understand that the API cannot distinguish between a legitimate or malicious image in this case. There should be an option to pass the max image dimensions or max memory size to prevent DoS attacks.
As it stands now, we have no way of protecting our servers against malicious images.
As it stands now, we have no way of protecting our servers against malicious images.
@roustem, yes you do: https://golang.org/pkg/image/jpeg/#DecodeConfig
Read the header to calculate its dimensions first. Use a https://golang.org/pkg/io/#TeeReader to save the bytes read into a https://golang.org/pkg/bytes/#Buffer and then if you're happy with the dimensions, use https://golang.org/pkg/io/#MultiReader to stitch together the saved header buffer with the remaining jpeg io.Reader. It all takes a few lines and is the natural Go composable way. See Camlistore's codebase for an example.
(Of course, that's only necessary if you can't rewind the stream. If it's just a file or something, you can seek back to the beginning)