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

userns: do not use an intermediate mount namespace #2730

Conversation

giuseppe
Copy link
Member

We have an issue in the current implementation where the cleanup
process is not able to umount the storage as it is running in a
separate namespace.

Simplify the implementation for user namespaces by not using an
intermediate mount namespace. For doing it, we need to relax the
permissions on the parent directories and allow browsing
them. Containers that are running without a user namespace, will still
maintain mode 0700 on their directory.

Alternative for: #2728

Signed-off-by: Giuseppe Scrivano [email protected]

@openshift-ci-robot openshift-ci-robot added approved Indicates a PR has been approved by an approver from all required OWNERS files. size/L labels Mar 21, 2019
@rhatdan
Copy link
Member

rhatdan commented Mar 21, 2019

But this means a non priv user can get to the images correct? This has the potential to allow information leak and opening up of more 777 directories for users to write into.

@giuseppe
Copy link
Member Author

But this means a non priv user can get to the images correct? This has the potential to allow information leak and opening up of more 777 directories for users to write into.

The directories under /var/lib/containers/storage/overlay still have mode 0700.

Let's get #2716 first, then I will rebase on top of that and verify there is nothing accessible by an unprivileged user

@rh-atomic-bot
Copy link
Collaborator

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

@giuseppe giuseppe force-pushed the userns-take-rid-of-intermediate-mountns branch from d892dba to 5e7caf7 Compare March 22, 2019 11:29
@giuseppe
Copy link
Member Author

I've verified there is nothing accessible to unprivileged users. All the directories that are owned by the final root in the container have mode 0700. Said so, we need to be more careful when we add more content in the storage directory.

In any case, even if I like the way this could simplify the implementation and need to worry of different code paths, I don't want to be the guy who caused CVEs in the storage :-) here there is a third option, that depends on a patch in conmon: #2730

@mheon
Copy link
Member

mheon commented Mar 22, 2019

If we can work through the security issues, I am definitely in favor of this one - the simplification of one of the most complex parts of libpod is a wonderful side effect of the fix.

@giuseppe
Copy link
Member Author

If we can work through the security issues, I am definitely in favor of this one - the simplification of one of the most complex parts of libpod is a wonderful side effect of the fix.

agreed. Having an intermediate mount namespace will always be somehow fragile, and difficult to debug

@rhatdan
Copy link
Member

rhatdan commented Mar 22, 2019

Is there a way we could at least add a test to prove that a world writable directory in containers/storage was not reachable via non root users.

su NONROOT find $STORAGEPATH -perm -o+w

@giuseppe
Copy link
Member Author

Is there a way we could at least add a test to prove that a world writable directory in containers/storage was not reachable via non root users.

good idea. We could add a test like:

find /var/run/libpod/ /var/lib/containers/storage -perm -o+w | while read i; do if chroot --userspec 1000:1000 / bash -c 'chmod +w $(dirname $i); chmod +w $i; echo hello > $i/test' 2> /dev/null ; then echo "HACKED"; fi; done

where would be the best place to add it? More stuff we have in the storage, the better it would be

@rhatdan
Copy link
Member

rhatdan commented Mar 22, 2019

I think adding this to libpod at least in the system tests. @edsantiago WDYT?

@giuseppe giuseppe force-pushed the userns-take-rid-of-intermediate-mountns branch from fbc4a26 to 1bc2d9e Compare March 22, 2019 17:11
@edsantiago
Copy link
Member

@rhatdan good idea; on my todo list for Monday, thanks.

@giuseppe
Copy link
Member Author

I've added a patch to test an unprivileged user cannot access files in the storage. We might need to add the check to more tests. @edsantiago could you review it?

@rhatdan
Copy link
Member

rhatdan commented Mar 25, 2019

@nalind PTAL

Copy link
Member

@edsantiago edsantiago left a comment

Choose a reason for hiding this comment

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

I love that you're extending the BATS tests, thank you! Some gotchas inline; and also a broader question: why add this as a function in helpers.bash? That would be appropriate if this were a general-purpose function useful for multiple subtests. This is a single independent one-time test, so I would recommend making it a new standalone .bats test instead. Look at 000-TEMPLATE, copy it to NNN-pick-a-name.bats, and put the code inside a @test context.

# Check that an unprivileged user cannot read or write to the storage
function check_no_unprivileged_access() {
GRAPH_ROOT=$(run_podman info --format json | jq .store.GraphRoot)
RUN_ROOT=$(run_podman info --format json | jq .store.RunRoot)
Copy link
Member

Choose a reason for hiding this comment

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

Unfortunately, in the BATS world, run_podman | xxx doesn't work. It has to be done as two steps, run_podman then operating on $output. And in these cases, I would probably write it as:

   run_podman info --format '{{.storage.Graphroot}}'           ! then the same for RunRoot
   GRAPH_ROOT="$output"

Copy link
Member Author

Choose a reason for hiding this comment

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

thanks! I've fixed it in the new version

function check_no_unprivileged_access() {
GRAPH_ROOT=$(run_podman info --format json | jq .store.GraphRoot)
RUN_ROOT=$(run_podman info --format json | jq .store.RunRoot)
find $GRAPH_ROOT $RUN_ROOT -perm -o+w | while read i; do
Copy link
Member

Choose a reason for hiding this comment

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

Did you mean to include -type f? Or ! -type l? There are an awful lot of symlinks that don't really seem to be useful to test.

Copy link
Member Author

Choose a reason for hiding this comment

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

no I meant that. I'd prefer to test as many files/directories as possible, if it turns to be too expensive we can tune it

Copy link
Member

Choose a reason for hiding this comment

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

What I mean is: can you try running that find command manually, with -ls instead of -print? I think you'll find that there are a lot of symlinks, because all symlinks are mode 777, but that's meaningless. There is no point whatsoever to testing those.

Copy link
Member Author

Choose a reason for hiding this comment

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

a lot of them in my current storage are coming from busybox, we could probably try to skip these as we are really testing the same thing multiple times. I'd still like though to test symlinks and that we don't have access to rm them

Copy link
Member

Choose a reason for hiding this comment

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

Let me try another way: can you explain what it is you think you are testing by paying attention to symlinks? I think there's a major misunderstanding going on here. Let's say the find produces output like this:

/x -> /y

What is the purpose of running any tests on /x? It is the same as running on /y, and:

  • if /y is a writable file or directory, the find command will emit it as part of its output
  • if /y is not a writable file or directory, there's no point in testing it

Copy link
Member Author

Choose a reason for hiding this comment

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

in the last version I've pushed, I am also checking for rm.

In the example you've given /x -> /y the unprivileged user could still be able to rm /x but not having privileges for doing it on /y

Copy link
Member

Choose a reason for hiding this comment

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

Permissions on /y are irrelevant for rm; only the parent directory permissions matter.

I'm working on a little bit of a rewrite; I'll push it when I'm comfortable with it. It might be in a few hours.

Copy link
Member Author

Choose a reason for hiding this comment

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

and symlink ownership. But given anyway that we are hardcoding the user, it probably doesn't make sense to test symlinks this way and we can safely skip them

GRAPH_ROOT=$(run_podman info --format json | jq .store.GraphRoot)
RUN_ROOT=$(run_podman info --format json | jq .store.RunRoot)
find $GRAPH_ROOT $RUN_ROOT -perm -o+w | while read i; do
if chroot --userspec 1000:1000 / bash -c 'chmod +w $(dirname $i); chmod +w $i; cat $i || echo hello > $i || echo hello > $i/test' 2> /dev/null; then
Copy link
Member

Choose a reason for hiding this comment

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

Careful with plain $i! Any space in the filename or any parent directory will cause all of these to fail. The convention is to double-quote every reference: "$i". (It's even better to use find ... -print0 | xargs -0, but that would be harder to read in this case.

Copy link
Member Author

Choose a reason for hiding this comment

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

thanks, fixed now

@giuseppe giuseppe force-pushed the userns-take-rid-of-intermediate-mountns branch from 1bc2d9e to 99f0495 Compare March 25, 2019 12:11
@test "podman run - basic tests --uidmapping" {
run_podman --uidmapping 0:10000:10000 run $IMAGE true

run_podman --uidmapping 0:10000:10000 -v foo:/foo run $IMAGE true
Copy link
Member

Choose a reason for hiding this comment

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

Neither of these work. Hint: you can test via PODMAN=/path/to/podman bats test/system/030-run.bats

There are other problems; I'm working on some modifications to the framework, will submit them as a PR on your PR.

@giuseppe giuseppe force-pushed the userns-take-rid-of-intermediate-mountns branch from 99f0495 to 85e3f99 Compare March 25, 2019 13:31
@edsantiago
Copy link
Member

giuseppe#1

@giuseppe giuseppe force-pushed the userns-take-rid-of-intermediate-mountns branch from 85e3f99 to 596ffa0 Compare March 25, 2019 16:25
var fd *os.File
fd, err = os.Open(fmt.Sprintf("/proc/%d/task/%d/ns/mnt", os.Getpid(), unix.Gettid()))
// makeAccessible changes the path permission and each parent directory to have --x--x--x
func makeAccessible(path string, uid, gid int) error {
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 @rhatdan @nalind this logic should probably be moved to containers/storage as it is not really specific to libpod

Copy link
Member

Choose a reason for hiding this comment

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

SGTM

Copy link
Member

Choose a reason for hiding this comment

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

Do we want to do this now, or merge this PR first and move later?

@giuseppe giuseppe force-pushed the userns-take-rid-of-intermediate-mountns branch from a684267 to 60f1bd5 Compare March 25, 2019 16:36
@rhatdan
Copy link
Member

rhatdan commented Mar 26, 2019

Are there other paths under /var/lib/containers/storage that we don't want a non privileged user to read?

Volumes directory?
DRIVER-containers?

@openshift-ci-robot
Copy link
Collaborator

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: edsantiago, giuseppe

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

@mheon
Copy link
Member

mheon commented Mar 26, 2019

@giuseppe Are we good to merge here?

@giuseppe
Copy link
Member Author

@rhatdan I've verified that volumes and anything overlay is not accessible to an unprivileged user.

I am fine with the PR as it is. Said so, I'd prefer if @nalind could review these changes.

@mheon
Copy link
Member

mheon commented Mar 26, 2019

I'd like to get this in before 1.2

@giuseppe giuseppe force-pushed the userns-take-rid-of-intermediate-mountns branch from 60f1bd5 to f575047 Compare March 26, 2019 18:03
@rhatdan
Copy link
Member

rhatdan commented Mar 27, 2019

LGTM

@mheon
Copy link
Member

mheon commented Mar 28, 2019

I'll ping @nalind in scrum to ask for a quick review

@rh-atomic-bot
Copy link
Collaborator

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

@giuseppe giuseppe force-pushed the userns-take-rid-of-intermediate-mountns branch from f575047 to 462e2b3 Compare March 29, 2019 09:00
@rh-atomic-bot
Copy link
Collaborator

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

giuseppe and others added 3 commits March 29, 2019 14:04
We have an issue in the current implementation where the cleanup
process is not able to umount the storage as it is running in a
separate namespace.

Simplify the implementation for user namespaces by not using an
intermediate mount namespace.  For doing it, we need to relax the
permissions on the parent directories and allow browsing
them. Containers that are running without a user namespace, will still
maintain mode 0700 on their directory.

Signed-off-by: Giuseppe Scrivano <[email protected]>
@giuseppe giuseppe force-pushed the userns-take-rid-of-intermediate-mountns branch from 462e2b3 to 1ae8a5b Compare March 29, 2019 13:04
@mheon
Copy link
Member

mheon commented Mar 29, 2019

/lgtm

@openshift-ci-robot openshift-ci-robot added the lgtm Indicates that a PR is ready to be merged. label Mar 29, 2019
@openshift-merge-robot openshift-merge-robot merged commit 83cea5d into containers:master Mar 29, 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.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants