
Unveil(2) – Unveil parts of a restricted filesystem view - notaplumber
https://man.openbsd.org/unveil
======
gshrikant
Not a very insightful comment but I really like the way OpenBSD names system
calls - both `unveil` and `pledge` are great, descriptive Unix-y names for
what these system calls do.

~~~
setzer22
I'm curious. To me, unveil means reveal information, while the intended
purpose for this tool is to hide it. Why do you think it's such a descriptive
name?

~~~
jakobegger
While it implicitely hides everything on the first call, it unveils the
arguments. Reads really natural. I imagine typical usage would be:

    
    
        fork();
        unveil("/home/jakob/", "w");
        unveil("/etc/some_config_file", "r");
        unveil(0,0);
        exec();

~~~
masklinn
> While it implicitely hides everything on the first call

I think that's the really weird bit, I guess they didn't want multiple
functions but it would make more sense to veil() (hide everything),
unveil(path, mode) (show that path) and lockveil(), something along those
lines. Or maybe use some sort of mode constants e.g. veil(VEIL_INIT),
veil(VEIL_REVEAL, path, mode), veil(VEIL_LOCK).

~~~
jakobegger
What benefit would requiring veil() before unveil() have? There is no point in
calling unveil() if the file system isn't hidden. Making the hiding implicit
reduces the number of possible mistakes people can make when using the API.

~~~
daveFNbuck
You could be more sure that something else didn't already unveil things you
want hidden in your current invocation.

------
avar
This seems like a pretty major limitation of the interface:

QUOTE

It is important to consider that directory results are remembered at the time
of a call to unveil(). This means that a directory that is removed and
recreated after a call to unveil() will appear to not exist. Non directories
are remembered by name within their containing directory, and so may be
created, removed, or re-created after a call to unveil() and still appear to
exist.

ENDQUOTE

So it's not really path-based, but rather translates a path at the the time of
the call to some UUID (or just an inode? But then how is inode re-use
handled?) for _that_ particular directory.

So if you unveil("~/myapp", ...) and the user does something like `mv ~/myapp
~/myapp.back && mkdir ~/myapp` the program won't see anything under ~/myapp
anymore, since it's not the same directory, even thought it's at the same
path.

~~~
blattimwind
> or just an inode? But then how is inode re-use handled?

inodes have generations. Each reuse increments generation. (ino, generation)
tuple uniquely identifies an object within the file system.

~~~
dchest
This is correct, however generation is mostly needed (and was created) for
NFS, and rarely used for anything else. Unveal lives in kernel, it just keeps
a reference to vnode
([https://github.com/openbsd/src/blob/03249988e9bbffb48a568839...](https://github.com/openbsd/src/blob/03249988e9bbffb48a56883955bda316855561b9/sys/sys/proc.h#L428-L433))

------
shawn
This design is so thoughtful. Thanks to fork, you can easily sandbox a child
process to a specific subtree of the filesystem: fork, unveil(0, 0), run
untrusted user code.

I wish OS X and windows had this.

~~~
saagarjha
Is sandboxing on macOS not exactly this (albeit with a different API)?

~~~
floatboth
It is. You have to write the rules as a Lisp script, and there's a scary "this
is sort of deprecated, use the new Mac App Store stuff" paragraph in the
manpage, but yes, it does allow exactly that.

------
shaggyfrog
Here's a presentation from Bob Beck entitled Pledge, and Unveil, in OpenBSD:
[https://www.openbsd.org/papers/BeckPledgeUnveilBSDCan2018.pd...](https://www.openbsd.org/papers/BeckPledgeUnveilBSDCan2018.pdf)

------
stevesimmons
This discussion from 39 days ago has some good links plus whether there is a
Linux equivalent:

[https://news.ycombinator.com/item?id=17277067](https://news.ycombinator.com/item?id=17277067)

~~~
specialist
I want a "merge" or "link" posts UX feature. Conceptually like merging bug
reports.

~~~
sctb
We do merge posts while the discussion is still happening, but afterwards we
aim to preserve context as much as possible.

------
rphlx
This is neat but I am still partial to slower but fully generic approaches for
syscall filtering, such as BPF.

Sooner or later you run out of clever English verbs for the plethora of fixed-
function ones.

~~~
floatboth
> fully generic approaches for syscall filtering, such as BPF

How do you constrain filesystem access to be under a list of allowed
directories using BPF?

I briefly looked at it, and there doesn't seem to be a good way to manipulate
strings. Everyone seems to be using chroot / bind mounts for that on Linux,
which adds crap lines to `mount` output.

------
Panino
> unveil can be locked, preventing further filesytem exposure by calling
> unveil with two NULL arguments.

This is nice and I bet it will be preferable to blocking further unveil calls
via pledge. Doing it with pledge would depend on the code path. Just as an
example, are you connecting to an IP address or a hostname (requiring a "dns"
pledge)? Are you reading from stdin or opening a file directly (requiring an
"rpath" pledge)? The current pledge state wouldn't matter when removing unveil
access via unveil itself, much simpler.

Pledge is already outstanding but combined with unveil I feel like a kid in a
candy store.

------
aomix
I don't think the unveil(0,0) call to disable/ignore further calls is
intuitive. But I'm not sure how you would improve on it beyond creating an
unveil_disable() call.

~~~
imtringued
The hardcoded zero literal for the flags could be replaced by a named
constant.

unveil(0, UNV_LOCK)

