Skip to content

Commit 50acb55

Browse files
committed
Split the code for remounting mount points and mounting paths.
A remount of a mount point must include all the current flags or these will be cleared: ``` The mountflags and data arguments should match the values used in the original mount() call, except for those parameters that are being deliberately changed. ``` The current code does not do this; the bug manifests in the specified flags for `/dev` being lost on remount read only at present. As we need to specify flags, split the code path for this from remounting paths which are not mount points, as these can only inherit the existing flags of the path, and these cannot be changed. In the bind case, remove extra flags from the bind remount. A bind mount can only be remounted read only, no other flags can be set, all other flags are inherited from the parent. From the man page: ``` Since Linux 2.6.26, this flag can also be used to make an existing bind mount read-only by specifying mountflags as: MS_REMOUNT | MS_BIND | MS_RDONLY Note that only the MS_RDONLY setting of the bind mount can be changed in this manner. ``` MS_REC can only be set on the original bind, so move this. See note in man page on bind mounts: ``` The remaining bits in the mountflags argument are also ignored, with the exception of MS_REC. ``` Signed-off-by: Justin Cormack <[email protected]>
1 parent 083933f commit 50acb55

File tree

2 files changed

+22
-13
lines changed

2 files changed

+22
-13
lines changed

libcontainer/rootfs_linux.go

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,8 @@ func finalizeRootfs(config *configs.Config) (err error) {
120120
// remount dev as ro if specified
121121
for _, m := range config.Mounts {
122122
if libcontainerUtils.CleanPath(m.Destination) == "/dev" {
123-
if m.Flags&syscall.MS_RDONLY != 0 {
124-
if err := remountReadonly(m.Destination); err != nil {
123+
if m.Flags&syscall.MS_RDONLY == syscall.MS_RDONLY {
124+
if err := remountReadonly(m); err != nil {
125125
return newSystemErrorWithCausef(err, "remounting %q as readonly", m.Destination)
126126
}
127127
}
@@ -700,17 +700,26 @@ func createIfNotExists(path string, isDir bool) error {
700700
return nil
701701
}
702702

703-
// remountReadonly will bind over the top of an existing path and ensure that it is read-only.
704-
func remountReadonly(path string) error {
703+
// readonlyPath will make a path read only.
704+
func readonlyPath(path string) error {
705+
if err := syscall.Mount(path, path, "", syscall.MS_BIND|syscall.MS_REC, ""); err != nil {
706+
if os.IsNotExist(err) {
707+
return nil
708+
}
709+
return err
710+
}
711+
return syscall.Mount(path, path, "", syscall.MS_BIND|syscall.MS_REMOUNT|syscall.MS_RDONLY|syscall.MS_REC, "")
712+
}
713+
714+
// remountReadonly will remount an existing mount point and ensure that it is read-only.
715+
func remountReadonly(m *configs.Mount) error {
716+
var (
717+
dest = m.Destination
718+
flags = m.Flags
719+
)
705720
for i := 0; i < 5; i++ {
706-
if err := syscall.Mount("", path, "", syscall.MS_REMOUNT|syscall.MS_RDONLY, ""); err != nil && !os.IsNotExist(err) {
721+
if err := syscall.Mount("", dest, "", uintptr(flags|syscall.MS_REMOUNT|syscall.MS_RDONLY), ""); err != nil {
707722
switch err {
708-
case syscall.EINVAL:
709-
// Probably not a mountpoint, use bind-mount
710-
if err := syscall.Mount(path, path, "", syscall.MS_BIND, ""); err != nil {
711-
return err
712-
}
713-
return syscall.Mount(path, path, "", syscall.MS_BIND|syscall.MS_REMOUNT|syscall.MS_RDONLY|syscall.MS_REC|defaultMountFlags, "")
714723
case syscall.EBUSY:
715724
time.Sleep(100 * time.Millisecond)
716725
continue
@@ -720,7 +729,7 @@ func remountReadonly(path string) error {
720729
}
721730
return nil
722731
}
723-
return fmt.Errorf("unable to mount %s as readonly max retries reached", path)
732+
return fmt.Errorf("unable to mount %s as readonly max retries reached", dest)
724733
}
725734

726735
// maskPath masks the top of the specified path inside a container to avoid

libcontainer/standard_init_linux.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ func (l *linuxStandardInit) Init() error {
111111
}
112112
}
113113
for _, path := range l.config.Config.ReadonlyPaths {
114-
if err := remountReadonly(path); err != nil {
114+
if err := readonlyPath(path); err != nil {
115115
return err
116116
}
117117
}

0 commit comments

Comments
 (0)