OpenBSD 6.4-current (GENERIC.MP) #562: Sat Jan  5 04:37:18 MST 2019
    [email protected]:/usr/src/sys/arch/amd64/compile/GENERIC.MP

1. unveil a file under an arbitrary directory
2. unveil root for default read-only
3. disable further unveils
4. open (RO) a file under the same directory the first file was in

$ cd /tmp
$ touch foo bar
$ cat poc.c
#include <err.h>
#include <fcntl.h>
#include <paths.h>
#include <unistd.h>

int
main(int argc, char *argv[]) {
        int fd;

        if (unveil(argv[1] ? argv[1] : "/tmp/foo", "rw") == -1)
                err(1, "unveil");

        if (unveil("/", "r") == -1)
                err(1, "unveil");

        if (unveil(NULL, NULL) == -1)
                err(1, "unveil");

        if ((fd = open("/tmp/bar", O_RDONLY)) == -1)
                err(1, "open");

        return close(fd);
}
$ cc poc.c
$ ./a.out
a.out: open: No such file or directory

unveil(2) says

        A path that is a directory will enable all filesystem access underneath
        path using permissions if and only if no more specific matching unveil()
        exists at a lower level.  Directories 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.

Since /tmp/foo and /tmp/bar are distinct files, /tmp/foo is strictly
more specific than /, so all files except /tmp/bar should be readable
after the second unveil call.

Passing other files change the first unveil demonstrates this:

$ mkdir dir
$ ./a.out /tmp/dir
a.out: open: No such file or directory
$ touch dir/file
$ ./a.out /tmp/dir/file
a.out: open: No such file or directory
$ touch ~/something
$ ./a.out ~/something && echo $?
0

Reply via email to