archive/tar: reader returns bogus headers (original) (raw)

The following program crashes:

package main

import ( "archive/tar" "bytes" "io" )

func main() { t := tar.NewReader(bytes.NewReader([]byte(data))) var headers []*tar.Header for { hdr, err := t.Next() if err == io.EOF { break } if err != nil { return } hdr1 := *hdr // make a copy to be safe headers = append(headers, &hdr1) } buf := new(bytes.Buffer) w := tar.NewWriter(buf) for _, hdr := range headers { err := w.WriteHeader(hdr) if err != nil { panic(err) } } }

var data = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" + "\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x0000000000\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\t" + "\xbf\x97KǸ\xd4\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"

panic: archive/tar: header field too long

The problem is that reader produces the following header:

tar.Header{Name:"", Mode:9151314442816847872, Uid:0, Gid:0, Size:0, ModTime:time.Time{sec:62135596800, nsec:0, loc:(*time.Location)(0x5d6f40)}, Typeflag:0x0, Linkname:"", Uname:"", Gname:"", Devmajor:0, Devminor:0, AccessTime:time.Time{sec:0, nsec:0, loc:(*time.Location)(nil)}, ChangeTime:time.Time{sec:0, nsec:0, loc:(*time.Location)(nil)}, Xattrs:map[string]string(nil)}

Mode is bogus. Then, cString tries to serialize that mode in octal format into 8-byte buffer. It does not fit.
I've inserted panic when this error is generated, and there is output:

b="\x00\x00\x00\x00\x00\x00\x00\x00"
s="774000000000000000000"
panic: archive/tar: header field too long

goroutine 1 [running]:
archive/tar.(*Writer).cString(0xc820090480, 0xc820090517, 0x8, 0x19c, 0xc8200ae0e0, 0x15, 0x505f00, 0x0, 0x0, 0x0)
    src/archive/tar/writer.go:83 +0x333
archive/tar.(*Writer).octal(0xc820090480, 0xc820090517, 0x8, 0x19c, 0x7f00000000000000)
    src/archive/tar/writer.go:102 +0xea
archive/tar.(*Writer).writeHeader(0xc820090480, 0xc8200b8f70, 0x517701, 0x0, 0x0)
    src/archive/tar/writer.go:193 +0x651
archive/tar.(*Writer).WriteHeader(0xc820090480, 0xc8200b8f70, 0x0, 0x0)
    src/archive/tar/writer.go:142 +0x3c
main.main()
    /tmp/tar.go:26 +0x336
exit status 2

go version devel +9c514e1 Tue Sep 1 04:00:12 2015 +0000 linux/amd64