From f2699686c2b872def3e6d0cf6bfd5a2932e485cb Mon Sep 17 00:00:00 2001 From: Nashwan Azhari Date: Wed, 28 Aug 2024 13:42:23 +0300 Subject: [PATCH] Add checks for CNIBinDir ownership/permissions. (#606) --------- Signed-off-by: Nashwan Azhari --- .github/workflows/go.yaml | 4 +- src/k8s/pkg/k8sd/setup/directories.go | 54 ++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/.github/workflows/go.yaml b/.github/workflows/go.yaml index 4d88a233e..c29585c09 100644 --- a/.github/workflows/go.yaml +++ b/.github/workflows/go.yaml @@ -63,7 +63,9 @@ jobs: - name: go test working-directory: src/k8s - run: make go.unit + # NOTE: there are a handful of tests checking/setting + # root ownership so the tests must be run as root: + run: sudo make go.unit test-binary: name: Binaries diff --git a/src/k8s/pkg/k8sd/setup/directories.go b/src/k8s/pkg/k8sd/setup/directories.go index 218843ad4..f4b8c4779 100644 --- a/src/k8s/pkg/k8sd/setup/directories.go +++ b/src/k8s/pkg/k8sd/setup/directories.go @@ -1,16 +1,23 @@ package setup import ( + "errors" "fmt" + "io/fs" "os" + "syscall" + "github.com/canonical/k8s/pkg/log" "github.com/canonical/k8s/pkg/snap" ) // EnsureAllDirectories ensures all required configuration and state directories are created. func EnsureAllDirectories(snap snap.Snap) error { + if err := ensureCniBinDir(snap.CNIBinDir()); err != nil { + return err + } + for _, dir := range []string{ - snap.CNIBinDir(), snap.CNIConfDir(), snap.ContainerdConfigDir(), snap.ContainerdExtraConfigDir(), @@ -32,3 +39,48 @@ func EnsureAllDirectories(snap snap.Snap) error { } return nil } + +// Ensures that the provided path is a directory with the appropriate +// ownership/permissions for it to be used as the CNI binary directory. +// https://github.com/canonical/k8s-snap/issues/567 +// https://github.com/cilium/cilium/issues/23838 +func ensureCniBinDir(cniBinDir string) error { + l := log.L().WithValues("cniBinDir", cniBinDir) + if cniBinDir == "" { + l.V(1).Info("Skipping creation of cni bin directory since it was not set") + return nil + } + + var stat syscall.Stat_t + if err := syscall.Stat(cniBinDir, &stat); err != nil { + if !errors.Is(err, fs.ErrNotExist) { + return fmt.Errorf("failed to syscall.Stat(%q): %w", cniBinDir, err) + } + + l.Info("Creating cni bin directory") + if err := os.MkdirAll(cniBinDir, 0o0700); err != nil { + return fmt.Errorf("failed to os.MkdirAll(%s): %w", cniBinDir, err) + } + + if err := syscall.Stat(cniBinDir, &stat); err != nil { + return fmt.Errorf("failed to syscall.Stat(%q) newly-created cni bin dir: %w", cniBinDir, err) + } + } + + if stat.Uid != 0 || stat.Gid != 0 { + l.Info("Ensuring ownership of cni bin directory") + if err := os.Chown(cniBinDir, 0, 0); err != nil { + return fmt.Errorf("failed to os.Chown(%q, 0, 0): %w", cniBinDir, err) + } + } + + if (stat.Mode & 0o700) != 0o700 { + l.Info("Ensuring permissions of cni bin directory") + mode := os.FileMode(stat.Mode | 0o700) + if err := os.Chmod(cniBinDir, mode); err != nil { + return fmt.Errorf("failed to os.Chmod(%q, %o): %w", cniBinDir, mode, err) + } + } + + return nil +}