diff --git a/SOURCES/cve-2024-21626-rhel7.patch b/SOURCES/cve-2024-21626-rhel7.patch
new file mode 100644
index 0000000..5f85d34
--- /dev/null
+++ b/SOURCES/cve-2024-21626-rhel7.patch
@@ -0,0 +1,265 @@
+diff -urN runc-dc9208a3303feef5b3839f4323d9beb36df0a9dd/libcontainer/container_linux.go runc-my/libcontainer/container_linux.go
+--- runc-dc9208a3303feef5b3839f4323d9beb36df0a9dd/libcontainer/container_linux.go	2020-01-22 08:19:15.000000000 -0800
++++ runc-my/libcontainer/container_linux.go	2024-01-23 15:03:45.697128791 -0800
+@@ -341,6 +341,17 @@
+ 		return newSystemErrorWithCause(err, "creating new parent process")
+ 	}
+ 	parent.forwardChildLogs()
++
++	// Before starting "runc init", mark all non-stdio open files as O_CLOEXEC
++	// to make sure we don't leak any files into "runc init". Any files to be
++	// passed to "runc init" through ExtraFiles will get dup2'd by the Go
++	// runtime and thus their O_CLOEXEC flag will be cleared. This is some
++	// additional protection against attacks like CVE-2024-21626, by making
++	// sure we never leak files to "runc init" we didn't intend to.
++	if err := utils.CloseExecFrom(3); err != nil {
++		return newSystemErrorWithCause(err, "unable to mark non-stdio fds as cloexec")
++	}
++
+ 	if err := parent.start(); err != nil {
+ 		// terminate the process to ensure that it properly is reaped.
+ 		if err := ignoreTerminateErrors(parent.terminate()); err != nil {
+diff -urN runc-dc9208a3303feef5b3839f4323d9beb36df0a9dd/libcontainer/init_linux.go runc-my/libcontainer/init_linux.go
+--- runc-dc9208a3303feef5b3839f4323d9beb36df0a9dd/libcontainer/init_linux.go	2020-01-22 08:19:15.000000000 -0800
++++ runc-my/libcontainer/init_linux.go	2024-01-23 15:25:54.398330999 -0800
+@@ -9,6 +9,7 @@
+ 	"io/ioutil"
+ 	"net"
+ 	"os"
++	"path/filepath"
+ 	"strings"
+ 	"syscall" // only for Errno
+ 	"unsafe"
+@@ -116,6 +117,32 @@
+ 	return nil
+ }
+ 
++// verifyCwd ensures that the current directory is actually inside the mount
++// namespace root of the current process.
++func verifyCwd() error {
++	// getcwd(2) on Linux detects if cwd is outside of the rootfs of the
++	// current mount namespace root, and in that case prefixes "(unreachable)"
++	// to the returned string. glibc's getcwd(3) and Go's Getwd() both detect
++	// when this happens and return ENOENT rather than returning a non-absolute
++	// path. In both cases we can therefore easily detect if we have an invalid
++	// cwd by checking the return value of getcwd(3). See getcwd(3) for more
++	// details, and CVE-2024-21626 for the security issue that motivated this
++	// check.
++	//
++	// We have to use unix.Getwd() here because os.Getwd() has a workaround for
++	// $PWD which involves doing stat(.), which can fail if the current
++	// directory is inaccessible to the container process.
++	if wd, err := unix.Getwd(); err == unix.ENOENT {
++		return errors.New("current working directory is outside of container mount namespace root -- possible container breakout detected")
++	} else if err != nil {
++		return fmt.Errorf("failed to verify if current working directory is safe: %s", err)
++	} else if !filepath.IsAbs(wd) {
++		// We shouldn't ever hit this, but check just in case.
++		return fmt.Errorf("current working directory is not absolute -- possible container breakout detected: cwd is %q", wd)
++	}
++	return nil
++}
++
+ // finalizeNamespace drops the caps, sets the correct user
+ // and working dir, and closes any leaked file descriptors
+ // before executing the command inside the namespace
+@@ -154,6 +181,10 @@
+ 	if err := setupUser(config); err != nil {
+ 		return errors.Wrap(err, "setup user")
+ 	}
++	// Make sure our final working directory is inside the container.
++	if err := verifyCwd(); err != nil {
++		return err
++	}
+ 	if err := system.ClearKeepCaps(); err != nil {
+ 		return errors.Wrap(err, "clear keep caps")
+ 	}
+diff -urN runc-dc9208a3303feef5b3839f4323d9beb36df0a9dd/libcontainer/setns_init_linux.go runc-my/libcontainer/setns_init_linux.go
+--- runc-dc9208a3303feef5b3839f4323d9beb36df0a9dd/libcontainer/setns_init_linux.go	2020-01-22 08:19:15.000000000 -0800
++++ runc-my/libcontainer/setns_init_linux.go	2024-01-23 15:26:54.230209188 -0800
+@@ -5,12 +5,15 @@
+ import (
+ 	"fmt"
+ 	"os"
++	"os/exec"
+ 	"runtime"
++	"syscall" //only for Exec
+ 
+ 	"github.com/opencontainers/runc/libcontainer/apparmor"
+ 	"github.com/opencontainers/runc/libcontainer/keys"
+ 	"github.com/opencontainers/runc/libcontainer/seccomp"
+ 	"github.com/opencontainers/runc/libcontainer/system"
++	"github.com/opencontainers/runc/libcontainer/utils"
+ 	"github.com/opencontainers/selinux/go-selinux/label"
+ 	"github.com/pkg/errors"
+ 
+@@ -80,6 +83,12 @@
+ 	if err := apparmor.ApplyProfile(l.config.AppArmorProfile); err != nil {
+ 		return err
+ 	}
++	// Check for the arg before waiting to make sure it exists and it is
++	// returned as a create time error.
++	name, err := exec.LookPath(l.config.Args[0])
++	if err != nil {
++		return err
++	}
+ 	// Set seccomp as close to execve as possible, so as few syscalls take
+ 	// place afterward (reducing the amount of syscalls that users need to
+ 	// enable in their seccomp profiles).
+@@ -88,5 +97,21 @@
+ 			return newSystemErrorWithCause(err, "init seccomp")
+ 		}
+ 	}
+-	return system.Execv(l.config.Args[0], l.config.Args[0:], os.Environ())
++	// Close all file descriptors we are not passing to the container. This is
++	// necessary because the execve target could use internal runc fds as the
++	// execve path, potentially giving access to binary files from the host
++	// (which can then be opened by container processes, leading to container
++	// escapes). Note that because this operation will close any open file
++	// descriptors that are referenced by (*os.File) handles from underneath
++	// the Go runtime, we must not do any file operations after this point
++	// (otherwise the (*os.File) finaliser could close the wrong file). See
++	// CVE-2024-21626 for more information as to why this protection is
++	// necessary.
++	if err := utils.UnsafeCloseFrom(l.config.PassedFilesCount + 3); err != nil {
++		return err
++	}
++	if err := syscall.Exec(name, l.config.Args[0:], os.Environ()); err != nil {
++		return newSystemErrorWithCause(err, "exec user process")
++	}
++	return nil
+ }
+diff -urN runc-dc9208a3303feef5b3839f4323d9beb36df0a9dd/libcontainer/standard_init_linux.go runc-my/libcontainer/standard_init_linux.go
+--- runc-dc9208a3303feef5b3839f4323d9beb36df0a9dd/libcontainer/standard_init_linux.go	2020-01-22 08:19:15.000000000 -0800
++++ runc-my/libcontainer/standard_init_linux.go	2024-01-23 15:27:25.396145744 -0800
+@@ -14,6 +14,7 @@
+ 	"github.com/opencontainers/runc/libcontainer/keys"
+ 	"github.com/opencontainers/runc/libcontainer/seccomp"
+ 	"github.com/opencontainers/runc/libcontainer/system"
++	"github.com/opencontainers/runc/libcontainer/utils"
+ 	"github.com/opencontainers/selinux/go-selinux/label"
+ 	"github.com/pkg/errors"
+ 
+@@ -207,6 +208,19 @@
+ 			return newSystemErrorWithCause(err, "init seccomp")
+ 		}
+ 	}
++	// Close all file descriptors we are not passing to the container. This is
++	// necessary because the execve target could use internal runc fds as the
++	// execve path, potentially giving access to binary files from the host
++	// (which can then be opened by container processes, leading to container
++	// escapes). Note that because this operation will close any open file
++	// descriptors that are referenced by (*os.File) handles from underneath
++	// the Go runtime, we must not do any file operations after this point
++	// (otherwise the (*os.File) finaliser could close the wrong file). See
++	// CVE-2024-21626 for more information as to why this protection is
++	// necessary.
++	if err := utils.UnsafeCloseFrom(l.config.PassedFilesCount + 3); err != nil {
++		return err
++	}
+ 	if err := syscall.Exec(name, l.config.Args[0:], os.Environ()); err != nil {
+ 		return newSystemErrorWithCause(err, "exec user process")
+ 	}
+diff -urN runc-dc9208a3303feef5b3839f4323d9beb36df0a9dd/libcontainer/utils/utils_unix.go runc-my/libcontainer/utils/utils_unix.go
+--- runc-dc9208a3303feef5b3839f4323d9beb36df0a9dd/libcontainer/utils/utils_unix.go	2020-01-22 08:19:15.000000000 -0800
++++ runc-my/libcontainer/utils/utils_unix.go	2024-01-23 15:27:53.435088668 -0800
+@@ -6,6 +6,7 @@
+ 	"fmt"
+ 	"os"
+ 	"strconv"
++	_ "unsafe" // for go:linkname
+ 
+ 	"golang.org/x/sys/unix"
+ )
+@@ -22,9 +23,11 @@
+ 	return nil
+ }
+ 
+-// CloseExecFrom applies O_CLOEXEC to all file descriptors currently open for
+-// the process (except for those below the given fd value).
+-func CloseExecFrom(minFd int) error {
++type fdFunc func(fd int)
++
++// fdRangeFrom calls the passed fdFunc for each file descriptor that is open in
++// the current process.
++func fdRangeFrom(minFd int, fn fdFunc) error {
+ 	fdDir, err := os.Open("/proc/self/fd")
+ 	if err != nil {
+ 		return err
+@@ -49,15 +52,60 @@
+ 		if fd < minFd {
+ 			continue
+ 		}
+-		// Intentionally ignore errors from unix.CloseOnExec -- the cases where
+-		// this might fail are basically file descriptors that have already
+-		// been closed (including and especially the one that was created when
+-		// ioutil.ReadDir did the "opendir" syscall).
+-		unix.CloseOnExec(fd)
++		// Ignore the file descriptor we used for readdir, as it will be closed
++		// when we return.
++		if uintptr(fd) == fdDir.Fd() {
++			continue
++		}
++		// Run the closure.
++		fn(fd)
+ 	}
+ 	return nil
+ }
+ 
++// CloseExecFrom sets the O_CLOEXEC flag on all file descriptors greater or
++// equal to minFd in the current process.
++func CloseExecFrom(minFd int) error {
++	return fdRangeFrom(minFd, unix.CloseOnExec)
++}
++
++//go:linkname runtime_IsPollDescriptor internal/poll.IsPollDescriptor
++
++// In order to make sure we do not close the internal epoll descriptors the Go
++// runtime uses, we need to ensure that we skip descriptors that match
++// "internal/poll".IsPollDescriptor. Yes, this is a Go runtime internal thing,
++// unfortunately there's no other way to be sure we're only keeping the file
++// descriptors the Go runtime needs. Hopefully nothing blows up doing this...
++func runtime_IsPollDescriptor(fd uintptr) bool //nolint:revive
++
++// UnsafeCloseFrom closes all file descriptors greater or equal to minFd in the
++// current process, except for those critical to Go's runtime (such as the
++// netpoll management descriptors).
++//
++// NOTE: That this function is incredibly dangerous to use in most Go code, as
++// closing file descriptors from underneath *os.File handles can lead to very
++// bad behaviour (the closed file descriptor can be re-used and then any
++// *os.File operations would apply to the wrong file). This function is only
++// intended to be called from the last stage of runc init.
++func UnsafeCloseFrom(minFd int) error {
++	// We must not close some file descriptors.
++	return fdRangeFrom(minFd, func(fd int) {
++		if runtime_IsPollDescriptor(uintptr(fd)) {
++			// These are the Go runtimes internal netpoll file descriptors.
++			// These file descriptors are operated on deep in the Go scheduler,
++			// and closing those files from underneath Go can result in panics.
++			// There is no issue with keeping them because they are not
++			// executable and are not useful to an attacker anyway. Also we
++			// don't have any choice.
++			return
++		}
++		// There's nothing we can do about errors from close(2), and the
++		// only likely error to be seen is EBADF which indicates the fd was
++		// already closed (in which case, we got what we wanted).
++		_ = unix.Close(fd)
++	})
++}
++
+ // NewSockPair returns a new unix socket pair
+ func NewSockPair(name string) (parent *os.File, child *os.File, err error) {
+ 	fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0)
+diff -urN runc-dc9208a3303feef5b3839f4323d9beb36df0a9dd/update.go runc-my/update.go
+--- runc-dc9208a3303feef5b3839f4323d9beb36df0a9dd/update.go	2020-01-22 08:19:15.000000000 -0800
++++ runc-my/update.go	2024-01-23 14:41:07.528142160 -0800
+@@ -173,6 +173,7 @@
+ 					return err
+ 				}
+ 			}
++			defer f.Close()
+ 			err = json.NewDecoder(f).Decode(&r)
+ 			if err != nil {
+ 				return err
diff --git a/SPECS/runc.spec b/SPECS/runc.spec
index 813c735..a10ed4d 100644
--- a/SPECS/runc.spec
+++ b/SPECS/runc.spec
@@ -27,13 +27,15 @@
 
 Name: %{repo}
 Version: 1.0.0
-Release: 69.rc10%{?dist}
+Release: 70.rc10%{?dist}
 Summary: CLI for running Open Containers
+ExcludeArch: %{ix86}
 License: ASL 2.0
 URL: %{git0}
 Source0: %{git0}/archive/%{commit0}/%{name}-%{shortcommit0}.tar.gz
 Patch0: 1807.patch
 Patch1: 0001-rootfs-add-mount-destination-validation.patch
+Patch2: cve-2024-21626-rhel7.patch
 # If go_compiler is not set to 1, there is no virtual provide. Use golang instead.
 %if 0%{?rhel} && ! 0%{?fedora}
 BuildRequires: go-toolset-1.12
@@ -43,9 +45,7 @@ BuildRequires: golang
 BuildRequires: git
 BuildRequires: go-md2man
 BuildRequires: libseccomp-devel
-%ifnarch %{ix86}
 Requires: criu
-%endif
 Requires(pre): container-selinux >= 2:2.2-2
 
 %description
@@ -105,6 +105,10 @@ install -p -m 0644 contrib/completions/bash/%{name} %{buildroot}%{_datadir}/bash
 %{_datadir}/bash-completion/completions/%{name}
 
 %changelog
+* Thu Feb 01 2024 Jindrich Novy <jnovy@redhat.com> - 1.0.0-70.rc10
+- apply patch for CVE-2024-21626
+- Resolves: RHEL-21862
+
 * Wed May 19 2021 Jindrich Novy <jnovy@redhat.com> - 1.0.0-69.rc10
 - fix CVE-2021-30465
 - Resolves: #1959474