diff --git a/kata-containers.spec b/kata-containers.spec index 2405ac4360bc9623ded153c94e54fb51c7a20d5c..c9dbd959dd02053650aa72d5b2d4fc4d00f50df1 100644 --- a/kata-containers.spec +++ b/kata-containers.spec @@ -2,7 +2,7 @@ %global debug_package %{nil} %define VERSION v1.11.1 -%define RELEASE 7 +%define RELEASE 8 Name: kata-containers Version: %{VERSION} @@ -90,6 +90,12 @@ install -p -m 640 -D ./runtime/cli/config/configuration-qemu.toml %{buildroot}/u %changelog +* Fri Feb 19 2021 xinghe - 1.11.1-8 +- Type:CVE +- ID:NA +- SUG:NA +- DESC:fix CVE-2020-28914 + * Tue Dec 22 2020 jiangpengfei - 1.11.1-7 - Type:enhancement - ID:NA diff --git a/runtime/patches/0066-CVE-2020-28914-1.patch b/runtime/patches/0066-CVE-2020-28914-1.patch new file mode 100644 index 0000000000000000000000000000000000000000..910d1eef9c45045068441c963f9f31a3ed9687c7 --- /dev/null +++ b/runtime/patches/0066-CVE-2020-28914-1.patch @@ -0,0 +1,78 @@ +From 228e6eb4b9c000fb105e3bf1401ac3938588fae2 Mon Sep 17 00:00:00 2001 +From: Peng Tao +Date: Fri, 30 Oct 2020 14:54:49 +0800 +Subject: [PATCH] runtime: readonly mounts should be readonly bindmount on the + host + +So that we get protected at the VM boundary not just the guest kernel. + +Signed-off-by: Peng Tao +Reference: https://github.com/kata-containers/runtime/commit/228e6eb4b9c000fb105e3bf1401ac3938588fae2 + https://github.com/kata-containers/community/blob/master/VMT/KCSA/KCSA-CVE-2020-28914.md +(cherry picked from commit 509eb6f850c0ceb60eb91a6095cceb8e4c7150f5) +--- + virtcontainers/container.go | 14 ++------------ + virtcontainers/pkg/oci/utils.go | 8 ++++++++ + 2 files changed, 10 insertions(+), 12 deletions(-) + +diff --git a/virtcontainers/container.go b/virtcontainers/container.go +index 88863ec42..6973c8328 100644 +--- a/virtcontainers/container.go ++++ b/virtcontainers/container.go +@@ -481,7 +481,7 @@ func (c *Container) shareFiles(m Mount, idx int, hostSharedDir, guestSharedDir s + } else { + // These mounts are created in the shared dir + mountDest := filepath.Join(hostSharedDir, filename) +- if err := bindMount(c.ctx, m.Source, mountDest, false, "private"); err != nil { ++ if err := bindMount(c.ctx, m.Source, mountDest, m.ReadOnly, "private"); err != nil { + return "", false, err + } + // Save HostPath mount value into the mount list of the container. +@@ -557,22 +557,12 @@ func (c *Container) mountSharedDirMounts(hostSharedDir, guestSharedDir string) ( + continue + } + +- // Check if mount is readonly, let the agent handle the readonly mount +- // within the VM. +- readonly := false +- for _, flag := range m.Options { +- if flag == "ro" { +- readonly = true +- break +- } +- } +- + sharedDirMount := Mount{ + Source: guestDest, + Destination: m.Destination, + Type: m.Type, + Options: m.Options, +- ReadOnly: readonly, ++ ReadOnly: m.ReadOnly, + } + + sharedDirMounts[sharedDirMount.Destination] = sharedDirMount +diff --git a/virtcontainers/pkg/oci/utils.go b/virtcontainers/pkg/oci/utils.go +index 0832a757c..9701df3d5 100644 +--- a/virtcontainers/pkg/oci/utils.go ++++ b/virtcontainers/pkg/oci/utils.go +@@ -162,11 +162,19 @@ func cmdEnvs(spec specs.Spec, envs []types.EnvVar) []types.EnvVar { + } + + func newMount(m specs.Mount) vc.Mount { ++ readonly := false ++ for _, flag := range m.Options { ++ if flag == "ro" { ++ readonly = true ++ break ++ } ++ } + return vc.Mount{ + Source: m.Source, + Destination: m.Destination, + Type: m.Type, + Options: m.Options, ++ ReadOnly: readonly, + } + } + diff --git a/runtime/patches/0067-CVE-2020-28914-2.patch b/runtime/patches/0067-CVE-2020-28914-2.patch new file mode 100644 index 0000000000000000000000000000000000000000..f61670d056f78fe562385b5c0e67cae26d43e51f --- /dev/null +++ b/runtime/patches/0067-CVE-2020-28914-2.patch @@ -0,0 +1,141 @@ +From 3f0e61c010556846e2f96811059d86cb10309748 Mon Sep 17 00:00:00 2001 +From: Peng Tao +Date: Fri, 30 Oct 2020 17:40:12 +0800 +Subject: [PATCH] runtime: mount shared mountpoint readonly + +bindmount remount events are not propagated through mount subtrees, +so we have to remount the shared dir mountpoint directly. + +E.g., +``` +mkdir -p source dest foo source/foo + +mount -o bind --make-shared source dest + +mount -o bind foo source/foo +echo bind mount rw +mount | grep foo +echo remount ro +mount -o remount,bind,ro source/foo +mount | grep foo +``` +would result in: +``` +bind mount rw +/dev/xvda1 on /home/ubuntu/source/foo type ext4 (rw,relatime,discard,data=ordered) +/dev/xvda1 on /home/ubuntu/dest/foo type ext4 (rw,relatime,discard,data=ordered) +remount ro +/dev/xvda1 on /home/ubuntu/source/foo type ext4 (ro,relatime,discard,data=ordered) +/dev/xvda1 on /home/ubuntu/dest/foo type ext4 (rw,relatime,discard,data=ordered) +``` + +The reason is that bind mount creats new mount structs and attaches them to different mount subtrees. +However, MS_REMOUNT only looks for existing mount structs to modify and does not try to propagate the +change to mount structs in other subtrees. + +Fixes: #3041 +Signed-off-by: Peng Tao +Reference: https://github.com/kata-containers/runtime/commit/3f0e61c010556846e2f96811059d86cb10309748 + https://github.com/kata-containers/community/blob/master/VMT/KCSA/KCSA-CVE-2020-28914.md +(cherry picked from commit 77399058bf3ded60aaeb08978073d000f178478f) +--- + virtcontainers/container.go | 15 +++++++++++---- + virtcontainers/kata_agent.go | 2 +- + virtcontainers/mount.go | 5 +++++ + virtcontainers/sandbox_test.go | 2 +- + 4 files changed, 18 insertions(+), 6 deletions(-) + +diff --git a/virtcontainers/container.go b/virtcontainers/container.go +index 6973c8328..37117d7e3 100644 +--- a/virtcontainers/container.go ++++ b/virtcontainers/container.go +@@ -446,7 +446,7 @@ func (c *Container) setContainerState(state types.StateString) error { + return nil + } + +-func (c *Container) shareFiles(m Mount, idx int, hostSharedDir, guestSharedDir string) (string, bool, error) { ++func (c *Container) shareFiles(m Mount, idx int, hostSharedDir, hostMountDir, guestSharedDir string) (string, bool, error) { + randBytes, err := utils.GenerateRandomBytes(8) + if err != nil { + return "", false, err +@@ -480,12 +480,19 @@ func (c *Container) shareFiles(m Mount, idx int, hostSharedDir, guestSharedDir s + } + } else { + // These mounts are created in the shared dir +- mountDest := filepath.Join(hostSharedDir, filename) ++ mountDest := filepath.Join(hostMountDir, filename) + if err := bindMount(c.ctx, m.Source, mountDest, m.ReadOnly, "private"); err != nil { + return "", false, err + } + // Save HostPath mount value into the mount list of the container. + c.mounts[idx].HostPath = mountDest ++ // bindmount remount event is not propagated to mount subtrees, so we have to remount the shared dir mountpoint directly. ++ if m.ReadOnly { ++ mountDest = filepath.Join(hostSharedDir, filename) ++ if err := remountRo(c.ctx, mountDest); err != nil { ++ return "", false, err ++ } ++ } + } + + return guestDest, false, nil +@@ -496,7 +503,7 @@ func (c *Container) shareFiles(m Mount, idx int, hostSharedDir, guestSharedDir s + // It also updates the container mount list with the HostPath info, and store + // container mounts to the storage. This way, we will have the HostPath info + // available when we will need to unmount those mounts. +-func (c *Container) mountSharedDirMounts(hostSharedDir, guestSharedDir string) (sharedDirMounts map[string]Mount, ignoredMounts map[string]Mount, err error) { ++func (c *Container) mountSharedDirMounts(hostSharedDir, hostMountDir, guestSharedDir string) (sharedDirMounts map[string]Mount, ignoredMounts map[string]Mount, err error) { + sharedDirMounts = make(map[string]Mount) + ignoredMounts = make(map[string]Mount) + var devicesToDetach []string +@@ -546,7 +553,7 @@ func (c *Container) mountSharedDirMounts(hostSharedDir, guestSharedDir string) ( + + var ignore bool + var guestDest string +- guestDest, ignore, err = c.shareFiles(m, idx, hostSharedDir, guestSharedDir) ++ guestDest, ignore, err = c.shareFiles(m, idx, hostSharedDir, hostMountDir, guestSharedDir) + if err != nil { + return nil, nil, err + } +diff --git a/virtcontainers/kata_agent.go b/virtcontainers/kata_agent.go +index a308952a8..a26e0411b 100644 +--- a/virtcontainers/kata_agent.go ++++ b/virtcontainers/kata_agent.go +@@ -1387,7 +1387,7 @@ func (k *kataAgent) createContainer(sandbox *Sandbox, c *Container) (p *Process, + } + + // Handle container mounts +- newMounts, ignoredMounts, err := c.mountSharedDirMounts(getMountPath(sandbox.id), kataGuestSharedDir()) ++ newMounts, ignoredMounts, err := c.mountSharedDirMounts(getSharePath(sandbox.id), getMountPath(sandbox.id), kataGuestSharedDir()) + if err != nil { + return nil, err + } +diff --git a/virtcontainers/mount.go b/virtcontainers/mount.go +index ab9e9f8d0..2f9846e80 100644 +--- a/virtcontainers/mount.go ++++ b/virtcontainers/mount.go +@@ -273,6 +273,11 @@ func remount(ctx context.Context, mountflags uintptr, src string) error { + return nil + } + ++// remount a mount point as readonly ++func remountRo(ctx context.Context, src string) error { ++ return remount(ctx, syscall.MS_BIND|syscall.MS_RDONLY, src) ++} ++ + // bindMountContainerRootfs bind mounts a container rootfs into a 9pfs shared + // directory between the guest and the host. + func bindMountContainerRootfs(ctx context.Context, shareDir, cid, cRootFs string, readonly bool) error { +diff --git a/virtcontainers/sandbox_test.go b/virtcontainers/sandbox_test.go +index 55e0ffea0..9f9d50ac1 100644 +--- a/virtcontainers/sandbox_test.go ++++ b/virtcontainers/sandbox_test.go +@@ -1377,7 +1377,7 @@ func TestPreAddDevice(t *testing.T) { + }, + } + +- mounts, ignoreMounts, err := container.mountSharedDirMounts("", "") ++ mounts, ignoreMounts, err := container.mountSharedDirMounts("", "", "") + assert.Nil(t, err) + assert.Equal(t, len(mounts), 0, + "mounts should contain nothing because it only contains a block device")