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

Allow suid, exec, dev mount options to cancel nosuid/noexec/nodev #3876

Merged
merged 8 commits into from
Sep 4, 2019

Conversation

mheon
Copy link
Member

@mheon mheon commented Aug 22, 2019

Previously, we explicitly set noexec/nosuid/nodev on every mount, with no ability to disable them. The 'mount' command on Linux will accept their inverses without complaint, though - 'noexec' is counteracted by 'exec', 'nosuid' by 'suid', etc. Add support for passing these options at the command line to disable our explicit forcing of security options.

This also cleans up mount option handling significantly. We are still parsing options in more than one place, which isn't good, but option parsing for bind and tmpfs mounts has been unified.

Fixes: #3819
Fixes: #3803

@openshift-ci-robot
Copy link
Collaborator

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: mheon

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci-robot openshift-ci-robot added approved Indicates a PR has been approved by an approver from all required OWNERS files. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. labels Aug 22, 2019
pkg/spec/spec.go Show resolved Hide resolved
@mheon
Copy link
Member Author

mheon commented Aug 22, 2019

I'll add a few tests after lunch.

@@ -13,7 +13,7 @@ require (
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc // indirect
github.com/containernetworking/cni v0.7.1
github.com/containernetworking/plugins v0.8.1
github.com/containers/buildah v1.10.1
github.com/containers/buildah v1.8.4-0.20190821140209-376e52ee0142
Copy link
Member Author

Choose a reason for hiding this comment

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

@vrothberg So I grabbed the top of buildah/master, and it appears to have downgraded, version-wise. We might want to look into that?

Copy link
Member

Choose a reason for hiding this comment

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

The important part is behind the last dash (i.e., the commit 376e52ee0142). It's a bug in go (no joke) which is trying to match a commit to a tag.

Commit 376e52ee0142 looks good.

Copy link
Member

Choose a reason for hiding this comment

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

If we want to get rid of that, we can do podman run --privileged -v pwd:/src:Z -it --rm golang:1.13-rc-buster and go get github.com/containers/buildah@376e52ee0142 inside the container. Go 1.13 will set the correct version/tag.

The annoying thing about that bug is that go mod's min-version algorithm can break here and downgrade a whole bunch of other dependencies.

@mheon mheon force-pushed the fix_mount_flags branch 2 times, most recently from 5150078 to e5f0781 Compare August 22, 2019 15:59
pkg/spec/spec.go Show resolved Hide resolved
if _, ok := baseMounts[dest]; ok {
continue
}
localOpts := options
if dest == "/run" {
localOpts = append(localOpts, "noexec", "size=65536k")
localOpts = append(localOpts, "dev", "suid", "noexec", "size=65536k")
Copy link
Member

Choose a reason for hiding this comment

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

Why are you doing this?

Copy link
Member Author

Choose a reason for hiding this comment

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

Need to make sure that the parser doesn't see the mount is missing nodev/nosuid and add those

}
if m.Type == TypeTmpfs && filepath.Clean(m.Destination) != "/dev" {
m.Options = append(m.Options, "tmpcopyup")
Copy link
Member

Choose a reason for hiding this comment

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

Do you still have tmpcopyup by default for tmpfs?

Copy link
Member Author

Choose a reason for hiding this comment

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

Still defaulted

@rhatdan
Copy link
Member

rhatdan commented Aug 22, 2019

You need to make sure that the mounts look the same with old podman as with this.
Make sure
podman run fedora mount

matches
./bin/podman run fedora mount

Then add a few other mounts using -v, --tmpfs and --mount and make sure everything is the same.

@mheon
Copy link
Member Author

mheon commented Aug 22, 2019

Test failures seem to be a mixed bag. It looks like my bind-mount options parsing code simplification over-simplified and broke things, but some of the rest seem like underlying bugs that are now being detected and reported.

@mheon
Copy link
Member Author

mheon commented Aug 23, 2019

Re-added functionality to infer mount options from those used on the base system.

@mheon
Copy link
Member Author

mheon commented Aug 23, 2019

I think tests will go green now. Still need to add a few more to cover new functionality.

@mheon
Copy link
Member Author

mheon commented Aug 26, 2019

Added tests. Good to go once this goes green.

@mheon
Copy link
Member Author

mheon commented Aug 27, 2019

One flake, otherwise green
@rhatdan @baude @vrothberg @TomSweeneyRedHat PTAL

@vrothberg
Copy link
Member

vrothberg commented Aug 28, 2019

I did a bigger chunk of review this morning. Maybe I'll find time this afternoon, latest tomorrow morning (EU).

@rh-atomic-bot
Copy link
Collaborator

☔ The latest upstream changes (presumably #3728) made this pull request unmergeable. Please resolve the merge conflicts.

Vendor some changes to parsing code that we need for Podman.

Signed-off-by: Matthew Heon <matthew.heon@pm.me>
Previously, we explicitly set noexec/nosuid/nodev on every mount,
with no ability to disable them. The 'mount' command on Linux
will accept their inverses without complaint, though - 'noexec'
is counteracted by 'exec', 'nosuid' by 'suid', etc. Add support
for passing these options at the command line to disable our
explicit forcing of security options.

This also cleans up mount option handling significantly. We are
still parsing options in more than one place, which isn't good,
but option parsing for bind and tmpfs mounts has been unified.

Fixes: containers#3819
Fixes: containers#3803

Signed-off-by: Matthew Heon <matthew.heon@pm.me>
We already process the options on all tmpfs filesystems during
final addition of mounts to the spec. We don't need to do it
before that in parseVolumes.

Signed-off-by: Matthew Heon <matthew.heon@pm.me>
If I mount, say, /usr/bin into my container - I expect to be able
to run the executables in that mount. Unconditionally applying
noexec would be a bad idea.

Before my patches to change mount options and allow exec/dev/suid
being set explicitly, we inferred the mount options from where on
the base system the mount originated, and the options it had
there. Implement the same functionality for the new option
handling.

There's a lot of performance left on the table here, but I don't
know that this is ever going to take enough time to make it worth
optimizing.

Signed-off-by: Matthew Heon <matthew.heon@pm.me>
Signed-off-by: Matthew Heon <matthew.heon@pm.me>
For read-only containers set to create tmpfs filesystems over
/run and other common destinations, we were incorrectly setting
mount options, resulting in duplicate mount options.

Signed-off-by: Matthew Heon <matthew.heon@pm.me>
Signed-off-by: Matthew Heon <matthew.heon@pm.me>
Copy link
Member

@vrothberg vrothberg left a comment

Choose a reason for hiding this comment

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

Just nits. Nice work, @mheon!

Expect(matches[0]).To(Not(ContainSubstring("noexec")))
Expect(matches[0]).To(Not(ContainSubstring("nodev")))
Expect(matches[0]).To(Not(ContainSubstring("nosuid")))
})
Copy link
Member

Choose a reason for hiding this comment

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

Can we add an additional block box test?

A trivial one could be an executable test.sh:

#!/bin/sh
echo "Hello World!"

And then mount & execute it once with exec and grep for Hello World! and then mount & execute it with noexec and grep for Permission denied.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done - I just mounted in /bin from the host, but it should be a sufficient test.

@@ -13,7 +13,7 @@ require (
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc // indirect
github.com/containernetworking/cni v0.7.1
github.com/containernetworking/plugins v0.8.1
github.com/containers/buildah v1.10.1
github.com/containers/buildah v1.8.4-0.20190821140209-376e52ee0142
Copy link
Member

Choose a reason for hiding this comment

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

If we want to get rid of that, we can do podman run --privileged -v pwd:/src:Z -it --rm golang:1.13-rc-buster and go get github.com/containers/buildah@376e52ee0142 inside the container. Go 1.13 will set the correct version/tag.

The annoying thing about that bug is that go mod's min-version algorithm can break here and downgrade a whole bunch of other dependencies.

// (Is this necessary?)
case "nosuid", "suid":
if setSuid {
return newMount, errors.Wrapf(optionArgError, "cannot pass 'nosuid' and 'suid' options more than once")
Copy link
Member

Choose a reason for hiding this comment

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

Clever trick to group them 👍

return nil, errors.Wrapf(err, "error retrieving system mounts to look up mount options")
}

// TODO: We probably don't need to re-build the mounts array
Copy link
Member

Choose a reason for hiding this comment

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

Nit: I think so too. Operating on inputMounts[i] should work.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'll leave it off for now, this is large enough already

@TomSweeneyRedHat
Copy link
Member

LGTM, nothing beyond @vrothbergs comments.

Signed-off-by: Matthew Heon <matthew.heon@pm.me>
@mheon
Copy link
Member Author

mheon commented Sep 4, 2019

Should be ready for merge.
@baude @rhatdan @vrothberg @giuseppe PTAL

@rhatdan
Copy link
Member

rhatdan commented Sep 4, 2019

/lgtm

@openshift-ci-robot openshift-ci-robot added the lgtm Indicates that a PR is ready to be merged. label Sep 4, 2019
@openshift-merge-robot openshift-merge-robot merged commit ab44484 into containers:master Sep 4, 2019
@github-actions github-actions bot added the locked - please file new issue/PR Assist humans wanting to comment on an old issue or PR with locked comments. label Sep 26, 2023
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 26, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. lgtm Indicates that a PR is ready to be merged. locked - please file new issue/PR Assist humans wanting to comment on an old issue or PR with locked comments. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

tmpfs mounts do not accept exec option Always mount tmpfs with noexec
7 participants