Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split the code for remounting mount points and mounting paths. #1222

Merged
merged 1 commit into from
Dec 27, 2016

Conversation

justincormack
Copy link
Contributor

@justincormack justincormack commented Dec 11, 2016

fix #1223

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

@justincormack
Copy link
Contributor Author

Fixed the CI issue, sorry about that.

@cyphar
Copy link
Member

cyphar commented Dec 16, 2016

Sorry for not looking into this earlier, I will take a look later today.

@justincormack
Copy link
Contributor Author

@cyphar no problem, thanks.

@@ -121,7 +121,7 @@ func finalizeRootfs(config *configs.Config) (err error) {
for _, m := range config.Mounts {
if libcontainerUtils.CleanPath(m.Destination) == "/dev" {
if m.Flags&syscall.MS_RDONLY != 0 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While you're changing this can you also switch this to be:

if m.Flags&syscall.MS_RDONLY == syscall.MS_RDONLY {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}
return err
}
return syscall.Mount(path, path, "", syscall.MS_BIND|syscall.MS_REMOUNT|syscall.MS_RDONLY|syscall.MS_REC, "")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure we should've dropped the |defaultMountFlags from here.

Copy link
Contributor Author

@justincormack justincormack Dec 16, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I specifically mention that in the commit message, bind mounts do not accept arbitrary mount flags, you can only set RDONLY. All other mount flags are inherited from the underlying mount and cannot be changed (because it is actually the same mount and hence same kernel datastructure). Thats one reason I had to split the code as the remount case is different...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So why is it not included in the MS_BIND command (the first one)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, good point. From my quick testing, it looks like doing it one shot should work.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@justincormack What I mean is why not make the first Mount line like this:

if err := syscall.Mount(path, path, "", syscall.MS_BIND|syscall.MS_REC|defaultMountFlags, ""); err != nil {

I accidentally commented on the wrong line.

Copy link
Member

@cyphar cyphar Dec 20, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, but I just tried to add nosuid to a bind mount. You're right that it doesn't work with the initial mount (sorry for misunderstanding what you said in that regard), but it does work with the remount (so we could apply them in the second mount):

% sudo mount --bind -o nosuid /usr/bin bin
% mount | grep /home/cyphar/bin
/dev/mapper/system-root on /home/cyphar/bin type btrfs (rw,relatime,space_cache,subvolid=259,subvol=/@/.snapshots/1/snapshot/usr/bin)
% sudo mount -o remount,nosuid bin bin
% mount | grep /home/cyphar/bin
/dev/mapper/system-root on /home/cyphar/bin type btrfs (rw,nosuid,relatime,space_cache,subvolid=259,subvol=/@/.snapshots/1/snapshot/usr/bin)
% ./bin/sudo
sudo: effective uid is not 0, is ./bin/sudo on a file system with the 'nosuid' option set or an NFS file system without root privileges?

The reason I'm harping on this is because defaultMountFlags contains security-related flags and I want to make sure that there's a good reason that we aren't going to be applying them for bindmounts anymore (though it looks like we never applied them).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. But in this case if you wanted this path nosuid you would have mounted it like that in the config? Having the read-only masked part only being nosuid but not the read-write part seems weird.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But in this case if you wanted this path nosuid you would have mounted it like that in the config?

Yeah, by my concern is with paths marked as readonlyPaths, which don't have an entry in the config. The spec just mentions that the path needs to be readonly, so this is probably fine. I was just concerned about suddenly allowing something that wasn't intended to be allowed previously.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But there will always be an entry for the mountpoint above, where the flags can be set. I don;t think anyone should rely on read only also setting other flags, and if they are set on the writeable part they are far more dangerous.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@rhatdan
Copy link
Contributor

rhatdan commented Dec 16, 2016

@rhvgoyal PTAL

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>
@cyphar
Copy link
Member

cyphar commented Dec 25, 2016

LGTM

Approved with PullApprove

1 similar comment
@hqhq
Copy link
Contributor

hqhq commented Dec 27, 2016

LGTM

Approved with PullApprove

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

mount flags on /dev are lost when remounting read only
5 participants