diff --git a/ipn/prefs.go b/ipn/prefs.go index d70dded6a..539d8df5b 100644 --- a/ipn/prefs.go +++ b/ipn/prefs.go @@ -5,6 +5,7 @@ package ipn import ( + "bytes" "encoding/json" "fmt" "io/ioutil" @@ -276,6 +277,9 @@ func LoadPrefs(filename string) (*Prefs, error) { if err != nil { return nil, fmt.Errorf("LoadPrefs open: %w", err) // err includes path } + if bytes.Contains(data, jsonEscapedZero) { + return nil, os.ErrNotExist + } p, err := PrefsFromBytes(data, false) if err != nil { return nil, fmt.Errorf("LoadPrefs(%q) decode: %w", filename, err) diff --git a/ipn/prefs_test.go b/ipn/prefs_test.go index 8b95d87a4..105683511 100644 --- a/ipn/prefs_test.go +++ b/ipn/prefs_test.go @@ -7,6 +7,7 @@ package ipn import ( "errors" "fmt" + "io/ioutil" "os" "reflect" "testing" @@ -371,3 +372,25 @@ func TestLoadPrefsNotExist(t *testing.T) { } t.Fatalf("unexpected prefs=%#v, err=%v", p, err) } + +// TestLoadPrefsFileWithZeroInIt verifies that LoadPrefs hanldes corrupted input files. +// See issue #954 for details. +func TestLoadPrefsFileWithZeroInIt(t *testing.T) { + f, err := ioutil.TempFile("", "TestLoadPrefsFileWithZeroInIt") + if err != nil { + t.Fatal(err) + } + path := f.Name() + if _, err := f.Write(jsonEscapedZero); err != nil { + t.Fatal(err) + } + f.Close() + defer os.Remove(path) + + p, err := LoadPrefs(path) + if errors.Is(err, os.ErrNotExist) { + // expected. + return + } + t.Fatalf("unexpected prefs=%#v, err=%v", p, err) +}