fix(keystore): avoid racy filesystem access
Instead of checking then performing a file operation, perform the file operation and check the error.
Steven Allen committed
Mar 15, 2020 at 23:40 UTC
7a4c377bbb05b68e39c917c6a394885816504efa
1 file changed
+10
-17
keystore/keystore.go
+10
-17
@@ -47,16 +47,13 @@ type FSKeystore struct {
47
48
// NewFSKeystore returns a new filesystem-backed keystore.
49
func NewFSKeystore(dir string) (*FSKeystore, error) {
50
- _, err := os.Stat(dir)
51
- if err != nil {
52
- if !os.IsNotExist(err) {
53
- return nil, err
54
- }
55
- if err := os.Mkdir(dir, 0700); err != nil {
56
- return nil, err
57
- }
50
+ err := os.Mkdir(dir, 0700)
51
+ switch {
52
+ case os.IsExist(err):
53
+ case err == nil:
54
+ default:
55
+ return nil, err
56
}
59
-
57
return &FSKeystore{dir}, nil
58
}
59
@@ -91,15 +88,11 @@ func (ks *FSKeystore) Put(name string, k ci.PrivKey) error {
88
89
kp := filepath.Join(ks.dir, name)
90
94
- _, err = os.Stat(kp)
95
- if err == nil {
96
- return ErrKeyExists
97
- } else if !os.IsNotExist(err) {
98
- return err
99
- }
100
-
101
- fi, err := os.Create(kp)
91
+ fi, err := os.OpenFile(kp, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0600)
92
if err != nil {
93
+ if os.IsExist(err) {
94
+ err = ErrKeyExists
95
+ }
96
return err
97
}
98
defer fi.Close()