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 <justin.cormack@docker.com>
This commit is contained in:
parent
083933fb90
commit
50acb55233
libcontainer
|
@ -120,8 +120,8 @@ func finalizeRootfs(config *configs.Config) (err error) {
|
|||
// remount dev as ro if specified
|
||||
for _, m := range config.Mounts {
|
||||
if libcontainerUtils.CleanPath(m.Destination) == "/dev" {
|
||||
if m.Flags&syscall.MS_RDONLY != 0 {
|
||||
if err := remountReadonly(m.Destination); err != nil {
|
||||
if m.Flags&syscall.MS_RDONLY == syscall.MS_RDONLY {
|
||||
if err := remountReadonly(m); err != nil {
|
||||
return newSystemErrorWithCausef(err, "remounting %q as readonly", m.Destination)
|
||||
}
|
||||
}
|
||||
|
@ -700,17 +700,26 @@ func createIfNotExists(path string, isDir bool) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// remountReadonly will bind over the top of an existing path and ensure that it is read-only.
|
||||
func remountReadonly(path string) error {
|
||||
// readonlyPath will make a path read only.
|
||||
func readonlyPath(path string) error {
|
||||
if err := syscall.Mount(path, path, "", syscall.MS_BIND|syscall.MS_REC, ""); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
return syscall.Mount(path, path, "", syscall.MS_BIND|syscall.MS_REMOUNT|syscall.MS_RDONLY|syscall.MS_REC, "")
|
||||
}
|
||||
|
||||
// remountReadonly will remount an existing mount point and ensure that it is read-only.
|
||||
func remountReadonly(m *configs.Mount) error {
|
||||
var (
|
||||
dest = m.Destination
|
||||
flags = m.Flags
|
||||
)
|
||||
for i := 0; i < 5; i++ {
|
||||
if err := syscall.Mount("", path, "", syscall.MS_REMOUNT|syscall.MS_RDONLY, ""); err != nil && !os.IsNotExist(err) {
|
||||
if err := syscall.Mount("", dest, "", uintptr(flags|syscall.MS_REMOUNT|syscall.MS_RDONLY), ""); err != nil {
|
||||
switch err {
|
||||
case syscall.EINVAL:
|
||||
// Probably not a mountpoint, use bind-mount
|
||||
if err := syscall.Mount(path, path, "", syscall.MS_BIND, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
return syscall.Mount(path, path, "", syscall.MS_BIND|syscall.MS_REMOUNT|syscall.MS_RDONLY|syscall.MS_REC|defaultMountFlags, "")
|
||||
case syscall.EBUSY:
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
continue
|
||||
|
@ -720,7 +729,7 @@ func remountReadonly(path string) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unable to mount %s as readonly max retries reached", path)
|
||||
return fmt.Errorf("unable to mount %s as readonly max retries reached", dest)
|
||||
}
|
||||
|
||||
// maskPath masks the top of the specified path inside a container to avoid
|
||||
|
|
|
@ -111,7 +111,7 @@ func (l *linuxStandardInit) Init() error {
|
|||
}
|
||||
}
|
||||
for _, path := range l.config.Config.ReadonlyPaths {
|
||||
if err := remountReadonly(path); err != nil {
|
||||
if err := readonlyPath(path); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue