From: Chen Qi <[email protected]>

Backport patch to fix CVE-2024-9676.

Signed-off-by: Chen Qi <[email protected]>
---
 recipes-containers/cri-o/cri-o_git.bb         |   1 +
 ...SecureJoin-when-forming-userns-paths.patch | 191 ++++++++++++++++++
 2 files changed, 192 insertions(+)
 create mode 100644 
recipes-containers/cri-o/files/0001-Use-securejoin.SecureJoin-when-forming-userns-paths.patch

diff --git a/recipes-containers/cri-o/cri-o_git.bb 
b/recipes-containers/cri-o/cri-o_git.bb
index d74a17fc..429c49a7 100644
--- a/recipes-containers/cri-o/cri-o_git.bb
+++ b/recipes-containers/cri-o/cri-o_git.bb
@@ -19,6 +19,7 @@ SRC_URI = "\
        
git://github.com/kubernetes-sigs/cri-o.git;branch=release-1.23;name=cri-o;protocol=https
 \
        file://0001-Makefile-force-symlinks.patch \
         file://crio.conf \
+        
file://0001-Use-securejoin.SecureJoin-when-forming-userns-paths.patch;patchdir=src/import/vendor/github.com/containers/storage
 \
        "
 
 # Apache-2.0 for docker
diff --git 
a/recipes-containers/cri-o/files/0001-Use-securejoin.SecureJoin-when-forming-userns-paths.patch
 
b/recipes-containers/cri-o/files/0001-Use-securejoin.SecureJoin-when-forming-userns-paths.patch
new file mode 100644
index 00000000..1cb7eb0e
--- /dev/null
+++ 
b/recipes-containers/cri-o/files/0001-Use-securejoin.SecureJoin-when-forming-userns-paths.patch
@@ -0,0 +1,191 @@
+From 03aff6270b389f27bc1edc4985dab753a38e7c7b Mon Sep 17 00:00:00 2001
+From: Matt Heon <[email protected]>
+Date: Wed, 9 Oct 2024 09:54:22 -0400
+Subject: [PATCH] Use securejoin.SecureJoin when forming userns paths
+
+We need to read /etc/passwd and /etc/group in the container to
+get an idea of how many UIDs and GIDs we need to allocate for a
+user namespace when `--userns=auto` is specified. We were forming
+paths for these using filepath.Join, which is not safe for paths
+within a container, resulting in this CVE allowing crafted
+symlinks in the container to access paths on the host instead.
+
+Cherry-pick conflict fixed for v1.51 branch, and converted to use
+the old securejoin API (securejoin.SecureJoin and then os.Open)
+as this branch is too old to have the new API.
+
+Addresses CVE-2024-9676
+
+Signed-off-by: Matt Heon <[email protected]>
+
+Upstream-Status: Backport [0dc4fc9bb826e08b6e25af0af6a296ac172b5e15]
+
+CVE: CVE-2024-9676
+
+Signed-off-by: Chen Qi <[email protected]>
+---
+ userns.go             | 93 ++++++++++++++++++++++++++++++-------------
+ userns_unsupported.go | 14 +++++++
+ 2 files changed, 80 insertions(+), 27 deletions(-)
+ create mode 100644 userns_unsupported.go
+
+diff --git a/userns.go b/userns.go
+index 523c92dc8..c234414ef 100644
+--- a/userns.go
++++ b/userns.go
+@@ -1,18 +1,21 @@
++//go:build linux
++
+ package storage
+ 
+ import (
+       "os"
+       "os/user"
+-      "path/filepath"
+       "strconv"
+ 
+       drivers "github.com/containers/storage/drivers"
+       "github.com/containers/storage/pkg/idtools"
+       "github.com/containers/storage/pkg/unshare"
+       "github.com/containers/storage/types"
++      securejoin "github.com/cyphar/filepath-securejoin"
+       libcontainerUser "github.com/opencontainers/runc/libcontainer/user"
+       "github.com/pkg/errors"
+       "github.com/sirupsen/logrus"
++      "golang.org/x/sys/unix"
+ )
+ 
+ // getAdditionalSubIDs looks up the additional IDs configured for
+@@ -78,43 +81,63 @@ func (s *store) getAvailableIDs() (*idSet, *idSet, error) {
+       return u, g, nil
+ }
+ 
++const nobodyUser = 65534
+ // parseMountedFiles returns the maximum UID and GID found in the /etc/passwd 
and
+ // /etc/group files.
+ func parseMountedFiles(containerMount, passwdFile, groupFile string) uint32 {
++      var (
++              passwd *os.File
++              group  *os.File
++              size   int
++              err    error
++      )
+       if passwdFile == "" {
+-              passwdFile = filepath.Join(containerMount, "etc/passwd")
+-      }
+-      if groupFile == "" {
+-              groupFile = filepath.Join(groupFile, "etc/group")
++              passwd, err = secureOpen(containerMount, "/etc/passwd")
++      } else {
++              // User-specified override from a volume. Will not be in
++              // container root.
++              passwd, err = os.Open(passwdFile)
+       }
+-
+-      size := 0
+-
+-      users, err := libcontainerUser.ParsePasswdFile(passwdFile)
+       if err == nil {
+-              for _, u := range users {
+-                      // Skip the "nobody" user otherwise we end up with 65536
+-                      // ids with most images
+-                      if u.Name == "nobody" {
+-                              continue
+-                      }
+-                      if u.Uid > size {
+-                              size = u.Uid
+-                      }
+-                      if u.Gid > size {
+-                              size = u.Gid
++              defer passwd.Close()
++
++              users, err := libcontainerUser.ParsePasswd(passwd)
++              if err == nil {
++                      for _, u := range users {
++                              // Skip the "nobody" user otherwise we end up 
with 65536
++                              // ids with most images
++                              if u.Name == "nobody" || u.Name == "nogroup" {
++                                      continue
++                              }
++                              if u.Uid > size && u.Uid != nobodyUser {
++                                      size = u.Uid + 1
++                              }
++                              if u.Gid > size && u.Gid != nobodyUser {
++                                      size = u.Gid + 1
++                              }
+                       }
+               }
+       }
+ 
+-      groups, err := libcontainerUser.ParseGroupFile(groupFile)
++      if groupFile == "" {
++              group, err = secureOpen(containerMount, "/etc/group")
++      } else {
++              // User-specified override from a volume. Will not be in
++              // container root.
++              group, err = os.Open(groupFile)
++      }
+       if err == nil {
+-              for _, g := range groups {
+-                      if g.Name == "nobody" {
+-                              continue
+-                      }
+-                      if g.Gid > size {
+-                              size = g.Gid
++              defer group.Close()
++
++              groups, err := libcontainerUser.ParseGroup(group)
++              if err == nil {
++                      for _, g := range groups {
++                              if g.Name == "nobody" || g.Name == "nogroup" {
++                                      continue
++                              }
++                              if g.Gid > size && g.Gid != nobodyUser {
++                                      size = g.Gid + 1
++                              }
+                       }
+               }
+       }
+@@ -300,3 +323,19 @@ func getAutoUserNSIDMappings(
+       gidMap := append(availableGIDs.zip(requestedContainerGIDs), 
additionalGIDMappings...)
+       return uidMap, gidMap, nil
+ }
++
++// Securely open (read-only) a file in a container mount.
++func secureOpen(containerMount, file string) (*os.File, error) {
++      filePath, err := securejoin.SecureJoin(containerMount, file)
++      if err != nil {
++              return nil, err
++      }
++
++      flags := unix.O_PATH | unix.O_CLOEXEC | unix.O_RDONLY
++      fileHandle, err := os.OpenFile(filePath, flags, 0)
++      if err != nil {
++              return nil, err
++      }
++
++      return fileHandle, nil
++}
+diff --git a/userns_unsupported.go b/userns_unsupported.go
+new file mode 100644
+index 000000000..e37c18fe4
+--- /dev/null
++++ b/userns_unsupported.go
+@@ -0,0 +1,14 @@
++//go:build !linux
++
++package storage
++
++import (
++      "errors"
++
++      "github.com/containers/storage/pkg/idtools"
++      "github.com/containers/storage/types"
++)
++
++func (s *store) getAutoUserNS(_ *types.AutoUserNsOptions, _ *Image, _ 
rwLayerStore, _ []roLayerStore) ([]idtools.IDMap, []idtools.IDMap, error) {
++      return nil, nil, errors.New("user namespaces are not supported on this 
platform")
++}
+-- 
+2.25.1
+
-- 
2.25.1

-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#9108): 
https://lists.yoctoproject.org/g/meta-virtualization/message/9108
Mute This Topic: https://lists.yoctoproject.org/mt/110749646/21656
Group Owner: [email protected]
Unsubscribe: https://lists.yoctoproject.org/g/meta-virtualization/unsub 
[[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to