From fcdaa2d6b320542325962f949f4149fc9a58eeba Mon Sep 17 00:00:00 2001 From: Derek McGowan Date: Mon, 27 Jun 2016 15:54:39 -0700 Subject: [PATCH] Atomically save libtrust key file The libtrust keyfile which is used to set the "ID" property of a daemon must be generated or loaded on every startup. If the process crashes during startup this could cause the file to be incomplete causing future startup errors. Ensure that the file is written atomically to ensure the file is never in an incomplete state. Fixes #23985 Signed-off-by: Derek McGowan (github: dmcgowan) (cherry picked from commit 9836162446bd0deadecbf0eed38ef3c134754f16) Signed-off-by: Tibor Vass --- api/common.go | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/api/common.go b/api/common.go index f83097c087..d62e65e8af 100644 --- a/api/common.go +++ b/api/common.go @@ -1,14 +1,18 @@ package api import ( + "encoding/json" + "encoding/pem" "fmt" "mime" + "os" "path/filepath" "sort" "strconv" "strings" "github.com/Sirupsen/logrus" + "github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/system" "github.com/docker/engine-api/types" "github.com/docker/libtrust" @@ -135,7 +139,11 @@ func LoadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) { if err != nil { return nil, fmt.Errorf("Error generating key: %s", err) } - if err := libtrust.SaveKey(trustKeyPath, trustKey); err != nil { + encodedKey, err := serializePrivateKey(trustKey, filepath.Ext(trustKeyPath)) + if err != nil { + return nil, fmt.Errorf("Error serializing key: %s", err) + } + if err := ioutils.AtomicWriteFile(trustKeyPath, encodedKey, os.FileMode(0600)); err != nil { return nil, fmt.Errorf("Error saving key file: %s", err) } } else if err != nil { @@ -143,3 +151,19 @@ func LoadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) { } return trustKey, nil } + +func serializePrivateKey(key libtrust.PrivateKey, ext string) (encoded []byte, err error) { + if ext == ".json" || ext == ".jwk" { + encoded, err = json.Marshal(key) + if err != nil { + return nil, fmt.Errorf("unable to encode private key JWK: %s", err) + } + } else { + pemBlock, err := key.PEMBlock() + if err != nil { + return nil, fmt.Errorf("unable to encode private key PEM: %s", err) + } + encoded = pem.EncodeToMemory(pemBlock) + } + return +}