From cf93ff9627b70a495e617a23b5bb6d56f61f88b2 Mon Sep 17 00:00:00 2001 From: apostasie Date: Sat, 24 Aug 2024 13:15:35 -0700 Subject: [PATCH] Hardening lifecycle state store Signed-off-by: apostasie --- pkg/ocihook/ocihook.go | 7 +++---- pkg/ocihook/state/state.go | 12 +++++++++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/pkg/ocihook/ocihook.go b/pkg/ocihook/ocihook.go index f8afc6c7c18..e37f4083a51 100644 --- a/pkg/ocihook/ocihook.go +++ b/pkg/ocihook/ocihook.go @@ -514,10 +514,9 @@ func onCreateRuntime(opts *handlerOpts) error { // Set StartedAt lf := state.NewLifecycleState(opts.state.Annotations[labels.StateDir]) return lf.WithLock(func() error { - err := lf.Load() - if err != nil { - return err - } + // Errors are voluntarily ignored here, as they should not be fatal. + // The lifecycle struct is also already warning about the issue. + _ = lf.Load() lf.StartedAt = time.Now() return lf.Save() }) diff --git a/pkg/ocihook/state/state.go b/pkg/ocihook/state/state.go index 0c0295cdd83..a109b0955f3 100644 --- a/pkg/ocihook/state/state.go +++ b/pkg/ocihook/state/state.go @@ -24,6 +24,8 @@ import ( "path/filepath" "time" + "github.com/containerd/log" + "github.com/containerd/nerdctl/v2/pkg/lockutil" ) @@ -71,6 +73,9 @@ func (lf *LifecycleState) Load() error { } else { err = json.Unmarshal(data, lf) if err != nil { + backout := filepath.Join(lf.stateDir, lifecycleFile, ".bak") + log.L.Errorf("unable to unmarshall lifecycle data: %w - broken file has been moved to: %q - "+ + "you should investigate manually and possibly report as a bug", err, backout) return fmt.Errorf("unable to unmarshall lifecycle data: %w", err) } } @@ -78,11 +83,16 @@ func (lf *LifecycleState) Load() error { } func (lf *LifecycleState) Save() error { + // Write atomically (write, then move) to avoid incomplete writes from happening data, err := json.Marshal(lf) if err != nil { return fmt.Errorf("unable to marshall lifecycle data: %w", err) } - err = os.WriteFile(filepath.Join(lf.stateDir, lifecycleFile), data, 0600) + err = os.WriteFile(filepath.Join(lf.stateDir, "."+lifecycleFile), data, 0600) + if err != nil { + return fmt.Errorf("unable to write lifecycle file: %w", err) + } + err = os.Rename(filepath.Join(lf.stateDir, "."+lifecycleFile), filepath.Join(lf.stateDir, lifecycleFile)) if err != nil { return fmt.Errorf("unable to write lifecycle file: %w", err) }