diff -Nru golang-uboot-go-0~2.git361f6eb/debian/changelog golang-uboot-go-0~3.git69978a3/debian/changelog --- golang-uboot-go-0~2.git361f6eb/debian/changelog 2015-07-23 07:08:01.000000000 +0000 +++ golang-uboot-go-0~3.git69978a3/debian/changelog 2015-07-23 08:18:06.000000000 +0000 @@ -1,9 +1,8 @@ -golang-uboot-go (0~2.git361f6eb-0ubuntu2) vivid; urgency=medium +golang-uboot-go (0~3.git69978a3-0ubuntu1) wily; urgency=medium - * debian/patches/series: - - fix uboot env reading when there are double \0 + * fix incorrect handling of \0\0 (eof) - -- Michael Vogt Thu, 23 Jul 2015 09:06:44 +0200 + -- Michael Vogt Thu, 23 Jul 2015 10:17:38 +0200 golang-uboot-go (0~2.git361f6eb-0ubuntu1) wily; urgency=medium diff -Nru golang-uboot-go-0~2.git361f6eb/debian/patches/01-fix-stuff.patch golang-uboot-go-0~3.git69978a3/debian/patches/01-fix-stuff.patch --- golang-uboot-go-0~2.git361f6eb/debian/patches/01-fix-stuff.patch 2015-07-23 07:06:29.000000000 +0000 +++ golang-uboot-go-0~3.git69978a3/debian/patches/01-fix-stuff.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,71 +0,0 @@ -diff --git a/uenv/env.go b/uenv/env.go -index c521756..60353c3 100644 ---- a/uenv/env.go -+++ b/uenv/env.go -@@ -73,11 +73,12 @@ func Open(fname string) (*Env, error) { - if crc != actualCRC { - return nil, fmt.Errorf("bad CRC: %v != %v", crc, actualCRC) - } -+ eof := bytes.Index(content[headerSize:], []byte{0, 0}) - - env := &Env{ - fname: fname, - size: len(content), -- data: parseData(content[headerSize:]), -+ data: parseData(content[headerSize:eof+headerSize]), - } - - return env, nil -@@ -91,6 +92,9 @@ func parseData(data []byte) map[string]string { - continue - } - l := strings.SplitN(string(envStr), "=", 2) -+ if len(l) == 1 { -+ panic(fmt.Sprintf("invalid line '%s'", string(envStr))) -+ } - key := l[0] - value := l[1] - out[key] = value -@@ -117,6 +121,9 @@ func (env *Env) Get(name string) string { - // Set an environment name to the given value, if the value is empty - // the variable will be removed from the environment - func (env *Env) Set(name, value string) { -+ if name == "" { -+ panic("name empty") -+ } - if value == "" { - delete(env.data, name) - return -@@ -134,6 +141,10 @@ func (env *Env) iterEnv(f func(key, value string)) { - sort.Strings(keys) - - for _, k := range keys { -+ if k == "" { -+ panic("k empty") -+ } -+ - f(k, env.data[k]) - } - } -@@ -150,8 +161,19 @@ func (env *Env) Save() error { - w.Write([]byte{0}) - }) - -- // ensure buffer is exactly the size we need it to be -- w.Write(make([]byte, env.size-headerSize-w.Len())) -+ // write double \0 to mark the end of the env -+ w.Write([]byte{0}) -+ // write ff into the remaining parts -+ writtenSoFar := w.Len() -+ for i := 0; i < env.size-headerSize-writtenSoFar; i++ { -+ w.Write([]byte{0xff}) -+ } -+ // not really needed -+ if w.Len() != env.size - headerSize { -+ panic(fmt.Sprintf("buffer size incorrect %v != %v", w.Len(), env.size - headerSize)) -+ } -+ -+ // checksum - crc := crc32.ChecksumIEEE(w.Bytes()) - - // Note that we overwrite the existing file and do not do diff -Nru golang-uboot-go-0~2.git361f6eb/debian/patches/series golang-uboot-go-0~3.git69978a3/debian/patches/series --- golang-uboot-go-0~2.git361f6eb/debian/patches/series 2015-07-23 07:06:37.000000000 +0000 +++ golang-uboot-go-0~3.git69978a3/debian/patches/series 2015-07-23 08:17:23.000000000 +0000 @@ -1 +1 @@ -01-fix-stuff.patch + diff -Nru golang-uboot-go-0~2.git361f6eb/uenv/env.go golang-uboot-go-0~3.git69978a3/uenv/env.go --- golang-uboot-go-0~2.git361f6eb/uenv/env.go 2015-07-22 06:53:46.000000000 +0000 +++ golang-uboot-go-0~3.git69978a3/uenv/env.go 2015-07-23 08:17:10.000000000 +0000 @@ -63,21 +63,23 @@ } defer f.Close() - content, err := ioutil.ReadAll(f) + contentWithHeader, err := ioutil.ReadAll(f) if err != nil { return nil, err } + crc := readUint32(contentWithHeader) - crc := readUint32(content) - actualCRC := crc32.ChecksumIEEE(content[headerSize:]) + payload := contentWithHeader[headerSize:] + actualCRC := crc32.ChecksumIEEE(payload) if crc != actualCRC { return nil, fmt.Errorf("bad CRC: %v != %v", crc, actualCRC) } + eof := bytes.Index(payload, []byte{0, 0}) env := &Env{ fname: fname, - size: len(content), - data: parseData(content[headerSize:]), + size: len(contentWithHeader), + data: parseData(payload[:eof]), } return env, nil @@ -91,6 +93,9 @@ continue } l := strings.SplitN(string(envStr), "=", 2) + if len(l) == 1 { + panic(fmt.Sprintf("invalid line %q (corrupted file?)", envStr)) + } key := l[0] value := l[1] out[key] = value @@ -117,6 +122,9 @@ // Set an environment name to the given value, if the value is empty // the variable will be removed from the environment func (env *Env) Set(name, value string) { + if name == "" { + panic(fmt.Sprintf("Set() can not be called with empty key for value: %q", value)) + } if value == "" { delete(env.data, name) return @@ -134,6 +142,10 @@ sort.Strings(keys) for _, k := range keys { + if k == "" { + panic("iterEnv iterating over a empty key") + } + f(k, env.data[k]) } } @@ -145,13 +157,27 @@ // the buffer will be ok because we sized it correctly w.Grow(env.size - headerSize) + // write the payload env.iterEnv(func(key, value string) { w.Write([]byte(fmt.Sprintf("%s=%s", key, value))) w.Write([]byte{0}) }) - // ensure buffer is exactly the size we need it to be - w.Write(make([]byte, env.size-headerSize-w.Len())) + // write double \0 to mark the end of the env + w.Write([]byte{0}) + + // no keys, so no previous \0 was written so we write one here + if len(env.data) == 0 { + w.Write([]byte{0}) + } + + // write ff into the remaining parts + writtenSoFar := w.Len() + for i := 0; i < env.size-headerSize-writtenSoFar; i++ { + w.Write([]byte{0xff}) + } + + // checksum crc := crc32.ChecksumIEEE(w.Bytes()) // Note that we overwrite the existing file and do not do diff -Nru golang-uboot-go-0~2.git361f6eb/uenv/env_test.go golang-uboot-go-0~3.git69978a3/uenv/env_test.go --- golang-uboot-go-0~2.git361f6eb/uenv/env_test.go 2015-07-22 06:53:46.000000000 +0000 +++ golang-uboot-go-0~3.git69978a3/uenv/env_test.go 2015-07-23 08:17:10.000000000 +0000 @@ -1,6 +1,10 @@ package uenv import ( + "bytes" + "hash/crc32" + "io/ioutil" + "os" "path/filepath" "strings" "testing" @@ -34,7 +38,8 @@ c.Assert(err, IsNil) env.Set("foo", "bar") c.Assert(env.String(), Equals, "foo=bar\n") - env.Save() + err = env.Save() + c.Assert(err, IsNil) env2, err := Open(u.envFile) c.Assert(err, IsNil) @@ -83,3 +88,116 @@ env.Set("foo", "") c.Assert(env.String(), Equals, "") } + +func (u *uenvTestSuite) makeUbootEnvFromData(c *C, mockData []byte) { + w := bytes.NewBuffer(nil) + crc := crc32.ChecksumIEEE(mockData) + w.Write(writeUint32(crc)) + w.Write([]byte{0}) + w.Write(mockData) + + f, err := os.Create(u.envFile) + c.Assert(err, IsNil) + defer f.Close() + _, err = f.Write(w.Bytes()) + c.Assert(err, IsNil) +} + +// ensure that the data after \0\0 is discarded (except for crc) +func (u *uenvTestSuite) TestReadStopsAfterDoubleNull(c *C) { + mockData := []byte{ + // foo=bar + 0x66, 0x6f, 0x6f, 0x3d, 0x62, 0x61, 0x72, + // eof + 0x00, 0x00, + // junk after eof as written by fw_setenv sometimes + // =b + 0x3d, 62, + // empty + 0xff, 0xff, + } + u.makeUbootEnvFromData(c, mockData) + + env, err := Open(u.envFile) + c.Assert(err, IsNil) + c.Assert(env.String(), Equals, "foo=bar\n") +} + +func (u *uenvTestSuite) TestReadEmptyFile(c *C) { + mockData := []byte{ + // eof + 0x00, 0x00, + // empty + 0xff, 0xff, + } + u.makeUbootEnvFromData(c, mockData) + + env, err := Open(u.envFile) + c.Assert(err, IsNil) + c.Assert(env.String(), Equals, "") +} + +func (u *uenvTestSuite) TestWritesEmptyFileWithDoubleNewline(c *C) { + env, err := Create(u.envFile, 12) + c.Assert(err, IsNil) + err = env.Save() + c.Assert(err, IsNil) + + r, err := os.Open(u.envFile) + c.Assert(err, IsNil) + defer r.Close() + content, err := ioutil.ReadAll(r) + c.Assert(err, IsNil) + c.Assert(content, DeepEquals, []byte{ + // crc + 0x11, 0x38, 0xb3, 0x89, + // redundant + 0x0, + // eof + 0x0, 0x0, + // footer + 0xff, 0xff, 0xff, 0xff, 0xff, + }) + + env, err = Open(u.envFile) + c.Assert(err, IsNil) + c.Assert(env.String(), Equals, "") +} + +func (u *uenvTestSuite) TestWritesContentCorrectly(c *C) { + totalSize := 16 + + env, err := Create(u.envFile, totalSize) + c.Assert(err, IsNil) + env.Set("a", "b") + env.Set("c", "d") + err = env.Save() + c.Assert(err, IsNil) + + r, err := os.Open(u.envFile) + c.Assert(err, IsNil) + defer r.Close() + content, err := ioutil.ReadAll(r) + c.Assert(err, IsNil) + c.Assert(content, DeepEquals, []byte{ + // crc + 0xc7, 0xd9, 0x6b, 0xc5, + // redundant + 0x0, + // a=b + 0x61, 0x3d, 0x62, + // eol + 0x0, + // c=d + 0x63, 0x3d, 0x64, + // eof + 0x0, 0x0, + // footer + 0xff, 0xff, + }) + + env, err = Open(u.envFile) + c.Assert(err, IsNil) + c.Assert(env.String(), Equals, "a=b\nc=d\n") + c.Assert(env.size, Equals, totalSize) +}