Skip to content

Commit 36bbb4d

Browse files
authored
Merge pull request #10210 from swagatbora90/preserve-flags-cherry-pick-1.7
[release/1.7] Preserve CL_UNPRIVILEGED locked flags during remount of bind mounts
2 parents f2cce98 + ad85652 commit 36bbb4d

1 file changed

Lines changed: 46 additions & 1 deletion

File tree

mount/mount_linux.go

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"strings"
2727
"time"
2828

29+
"github.com/containerd/containerd/pkg/userns"
2930
"golang.org/x/sys/unix"
3031
)
3132

@@ -114,12 +115,56 @@ func (m *Mount) mount(target string) (err error) {
114115

115116
const broflags = unix.MS_BIND | unix.MS_RDONLY
116117
if oflags&broflags == broflags {
118+
// Preserve CL_UNPRIVILEGED "locked" flags of the
119+
// bind mount target when we remount to make the bind readonly.
120+
// This is necessary to ensure that
121+
// bind-mounting "with options" will not fail with user namespaces, due to
122+
// kernel restrictions that require user namespace mounts to preserve
123+
// CL_UNPRIVILEGED locked flags.
124+
var unprivFlags int
125+
if userns.RunningInUserNS() {
126+
unprivFlags, err = getUnprivilegedMountFlags(target)
127+
if err != nil {
128+
return err
129+
}
130+
}
117131
// Remount the bind to apply read only.
118-
return unix.Mount("", target, "", uintptr(oflags|unix.MS_REMOUNT), "")
132+
return unix.Mount("", target, "", uintptr(oflags|unprivFlags|unix.MS_REMOUNT), "")
119133
}
120134
return nil
121135
}
122136

137+
// Get the set of mount flags that are set on the mount that contains the given
138+
// path and are locked by CL_UNPRIVILEGED.
139+
//
140+
// From https://github.com/moby/moby/blob/v23.0.1/daemon/oci_linux.go#L430-L460
141+
func getUnprivilegedMountFlags(path string) (int, error) {
142+
var statfs unix.Statfs_t
143+
if err := unix.Statfs(path, &statfs); err != nil {
144+
return 0, err
145+
}
146+
147+
// The set of keys come from https://github.com/torvalds/linux/blob/v4.13/fs/namespace.c#L1034-L1048.
148+
unprivilegedFlags := []int{
149+
unix.MS_RDONLY,
150+
unix.MS_NODEV,
151+
unix.MS_NOEXEC,
152+
unix.MS_NOSUID,
153+
unix.MS_NOATIME,
154+
unix.MS_RELATIME,
155+
unix.MS_NODIRATIME,
156+
}
157+
158+
var flags int
159+
for flag := range unprivilegedFlags {
160+
if int(statfs.Flags)&flag == flag {
161+
flags |= flag
162+
}
163+
}
164+
165+
return flags, nil
166+
}
167+
123168
// Unmount the provided mount path with the flags
124169
func Unmount(target string, flags int) error {
125170
if err := unmount(target, flags); err != nil && err != unix.EINVAL {

0 commit comments

Comments
 (0)