From 5fe7c6b7595ba83bc7cd0693d5b75952631bfa72 Mon Sep 17 00:00:00 2001 From: Paul Gaiduk Date: Thu, 23 May 2024 19:10:17 +0200 Subject: [PATCH] Allow device access when loading OCI spec from file Since the update to runc v1.1.0 and containerd v1.6.1 in 158cecdb9a021a403461f466b1eb0a72ffc009cf we need to explicitly allow device access in the OCI config. This is done when generating a new OCI spec. However, when loading an OCI config from a file, we need to make sure that the device access is added, because older OCI configs may lack this configuration. Signed-off-by: Paul Gaiduk (cherry picked from commit 17d9a41e309db043db854a8caa658005f11fbea5) --- pkg/pillar/containerd/oci.go | 12 ++++++++ pkg/pillar/containerd/oci_test.go | 47 ++++++++++++++++++++++++++++--- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/pkg/pillar/containerd/oci.go b/pkg/pillar/containerd/oci.go index ce0063e7be..1c3bb48849 100644 --- a/pkg/pillar/containerd/oci.go +++ b/pkg/pillar/containerd/oci.go @@ -244,6 +244,18 @@ func (s *ociSpec) Load(file *os.File) error { if s.Annotations == nil { s.Annotations = map[string]string{} } + // default OCI specs have all devices being denied by default, + // we flip it back to all allow for now, but later on we may + // need to get more fine-grained + if s.Linux == nil { + s.Linux = &specs.Linux{} + } + if s.Linux.Resources == nil { + s.Linux.Resources = &specs.LinuxResources{} + } + if s.Linux.Resources.Devices == nil { + s.Linux.Resources.Devices = []specs.LinuxDeviceCgroup{{Type: "a", Allow: true, Access: "rwm"}} + } return nil } diff --git a/pkg/pillar/containerd/oci_test.go b/pkg/pillar/containerd/oci_test.go index 7dfd3ae051..df21efcf33 100644 --- a/pkg/pillar/containerd/oci_test.go +++ b/pkg/pillar/containerd/oci_test.go @@ -403,6 +403,7 @@ func TestOciSpec(t *testing.T) { } s := spec.Get() + assert.NotNil(t, s.Linux.Resources.Devices) assert.Equal(t, int64(1234*1024), *s.Linux.Resources.Memory.Limit) assert.Equal(t, float64(4), float64(*s.Linux.Resources.CPU.Quota)/float64(*s.Linux.Resources.CPU.Period)) assert.Equal(t, tmpdir+"/rootfs", s.Root.Path) @@ -513,23 +514,21 @@ func TestCreateMountPointExecEnvFiles(t *testing.T) { t.Errorf("createMountPointExecEnvFiles failed %v", err) } - execpathStr := "\"/bin/sh\"" cmdlineFile := path.Join(rootDir, "cmdline") cmdline, err := os.ReadFile(cmdlineFile) if err != nil { t.Errorf("createMountPointExecEnvFiles failed to create cmdline file %s %v", cmdlineFile, err) } - if string(cmdline) != execpathStr { + if execpathStr := "\"/bin/sh\""; string(cmdline) != execpathStr { t.Errorf("mismatched cmdline file content, actual '%s' expected '%s'", string(cmdline), execpathStr) } mountFile := path.Join(rootDir, "mountPoints") - mountExpected := "" mounts, err := os.ReadFile(mountFile) if err != nil { t.Errorf("createMountPointExecEnvFiles failed to create mountPoints file %s %v", mountFile, err) } - if string(mounts) != mountExpected { + if mountExpected := ""; string(mounts) != mountExpected { t.Errorf("mismatched mountpoints file content, actual '%s' expected '%s'", string(mounts), mountExpected) } @@ -850,3 +849,43 @@ func deepCopy(in interface{}) interface{} { val = val.Elem() return val.Interface() } + +func TestAllowAllDevicesInSpec(t *testing.T) { + t.Parallel() + + // create a temp dir to hold resulting files + dir, _ := os.MkdirTemp("/tmp", "podfiles") + rootDir := path.Join(dir, "runx") + rootFsDir := path.Join(rootDir, "rootfs") + rsPath := path.Join(rootDir, ociRuntimeSpecFilename) + err := os.MkdirAll(rootFsDir, 0777) + if err != nil { + t.Errorf("failed to create temporary dir") + } else { + defer os.RemoveAll(dir) + } + + // ...and a loader runtime spec + if err := os.WriteFile(rsPath, []byte(loaderRuntimeSpec), 0600); err != nil { + t.Errorf("failed to write to a runtime spec file %v", err) + } + + client := &Client{} + spec, err := client.NewOciSpec("test", false) + if err != nil { + t.Errorf("failed to create new OCI spec %v", err) + } + if err := spec.UpdateFromVolume(rootDir); err != nil { + t.Errorf("failed to load OCI image spec %v", err) + } + spec.Get().Root.Path = rootFsDir + err = spec.AddLoader(rootDir) + if err != nil { + t.Errorf("AddLoader failed %v", err) + } + + // Check that the devices are allowed + assert.NotNil(t, spec.Get().Linux) + assert.NotNil(t, spec.Get().Linux.Resources) + assert.Equal(t, []specs.LinuxDeviceCgroup{{Type: "a", Allow: true, Access: "rwm"}}, spec.Get().Linux.Resources.Devices) +}