containers / bubblewrap

Low-level unprivileged sandboxing tool used by Flatpak and similar projects
Other
3.75k stars 230 forks source link

not immediately obvious that `--file` can overwrite a file mounted rw from outside the container #617

Open WxNzEMof opened 5 months ago

WxNzEMof commented 5 months ago

Sorry if this is a duplicate, GitHub isn't letting me search for --file.

I'm finding the following behavior surprising:

$ echo real > file                                                         
$ cat file                                                                             
real
$ echo fake | bwrap --dev-bind / / --file 0 "$PWD"/file cat file    
fake
$ cat file                                                      
fake

This seems surprising because most other options only affect the wrapped command.

If this behavior is intentional, I think a clarification in the man page would not go amiss.

Thank you.

rusty-snake commented 5 months ago

This seems surprising because most other options only affect the wrapped command.

This is because the most options (--[ro-|dev-]bind[-try], --proc, ...) work by mounting which is isolated by --unshare-mnt. --file is documented to copy from FD to DEST (i.e. read FD, then write its content to DEST) since you asked bubblewrap to mount a host path at (or above) DEST, imho this is a you get what you ask for case.

--bind-data on the other hand is documented to write to "a file" that is bind-mounted over DEST.

WxNzEMof commented 5 months ago

Thank you for the clarification. I think making the man page clearly explain the differences between them would be a good improvement.

smcv commented 5 months ago

Please propose a pull request for the man page that would have told you what to expect, in the location where you would have expected to read it?

most other options only affect the wrapped command

That's not really true: options like --symlink will also write the symlink into the destination directory. Mount instructions like --bind mostly only affect the sandbox/container namespace, but even those might need to create a directory or empty file to mount onto, and if they do, that I/O really happens. For example bwrap --dev-bind / / --bind /foobar /tmp/foo will create /tmp/foo on the real filesystem if it doesn't already exist (because otherwise, it would be unable to mount /foobar onto it).

I think the fundamental misunderstanding here might be that you might have imagined that bwrap would magically mount a temporary overlayfs that would cause all I/O to be discarded? But it doesn't do that. There is a pull request open to teach it to mount overlayfs, but even with that PR, it will only happen if you specifically ask for it to happen.

WxNzEMof commented 5 months ago

Please propose a pull request for the man page that would have told you what to expect, in the location where you would have expected to read it?

OK, it's open.

That's not really true: options like --symlink will also write the symlink into the destination directory.

Yes, thank you for pointing that out. I think that should be included in the clarification.

Mount instructions like --bind mostly only affect the sandbox/container namespace, but even those might need to create a directory or empty file to mount onto, and if they do, that I/O really happens.

Okay. Not that it matters, since creating an empty directory in almost always harmless, but I'm wondering if perhaps bwrap's CLI could have been designed to more explicit about which operations can have lasting effects, e.g. by requiring a --mkdir to precede a possibly-nonexistent --bind target.

I think the fundamental misunderstanding here might be that you might have imagined that bwrap would magically mount a temporary overlayfs that would cause all I/O to be discarded?

That's correct - at least in the moment when I made the mistake that led me to write a buggy script that actually overwrote a file. :) Well, bwrap is a very powerful tool, but maintaining a mental model of how each switch works on top of the filesystem hierarchy you're trying to build inside the namespace for the problem you're trying to solve leaves room for error, so I think clearer documentation of what can have what kind of effects and how similar options differ would be helpful.

Thanks!