#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/mount.h>
#include "unveil.h"
const char *uv_flags = "rwxc";
static void
do_unveil(void)
{
if (unveil(uv_dir1, uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil(uv_file1, uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
}
static void
do_unveil2(void)
{
if (unveil(uv_dir1, uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
}
static int
test_openat(int do_uv)
{
int slashbefore;
int dirfd1before;
int dirfd2before;
int dirfd1after;
int dirfd2after;
UV_SHOULD_SUCCEED(((slashbefore = open("/", O_RDONLY | O_DIRECTORY)) == -1), "open");
UV_SHOULD_SUCCEED(((dirfd1before = open(uv_dir1, O_RDONLY | O_DIRECTORY)) == -1), "open");
UV_SHOULD_SUCCEED(((dirfd2before = open(uv_dir2, O_RDONLY | O_DIRECTORY)) == -1), "open");
if (do_uv) {
printf("testing openat\n");
do_unveil();
}
UV_SHOULD_SUCCEED(((dirfd1after = open(uv_dir1, O_RDONLY | O_DIRECTORY)) == -1), "open");
UV_SHOULD_ENOENT(((dirfd2after = open(uv_dir2, O_RDONLY | O_DIRECTORY)) == -1), "open");
UV_SHOULD_ENOENT((openat(slashbefore, "etc/hosts", O_RDONLY) == -1), "openat");
UV_SHOULD_SUCCEED((openat(slashbefore, uv_file1, O_RDWR) == -1), "openat");
UV_SHOULD_ENOENT((openat(slashbefore, uv_file2, O_RDWR) == -1), "openat");
UV_SHOULD_ENOENT((openat(dirfd1before, "/etc/hosts", O_RDONLY) == -1), "openat");
UV_SHOULD_SUCCEED((openat(dirfd1before, "hooray", O_RDWR|O_CREAT, 0644) == -1), "openat");
UV_SHOULD_SUCCEED((openat(dirfd1before, uv_file1, O_RDWR|O_CREAT, 0644) == -1), "openat");
UV_SHOULD_ENOENT((openat(dirfd1before, uv_file2, O_RDWR|O_CREAT, 0644) == -1), "openat");
UV_SHOULD_ENOENT((openat(dirfd2before, "/etc/hosts", O_RDONLY) == -1), "openat");
UV_SHOULD_ENOENT((openat(dirfd2before, "hooray", O_RDWR|O_CREAT, 0644) == -1), "openat");
UV_SHOULD_SUCCEED((openat(dirfd2before, uv_file1, O_RDWR|O_CREAT, 0644) == -1), "openat");
UV_SHOULD_ENOENT((openat(dirfd2before, uv_file2, O_RDWR|O_CREAT, 0644) == -1), "openat");
UV_SHOULD_ENOENT((openat(dirfd1after, "/etc/hosts", O_RDONLY) == -1), "openat");
UV_SHOULD_SUCCEED((openat(dirfd1after, "hooray", O_RDWR|O_CREAT, 0644) == -1), "openat");
UV_SHOULD_SUCCEED((openat(dirfd1after, uv_file1, O_RDWR|O_CREAT, 0644) == -1), "openat");
UV_SHOULD_ENOENT((openat(dirfd1after, uv_file2, O_RDWR|O_CREAT, 0644) == -1), "openat");
UV_SHOULD_SUCCEED(((dirfd2after = openat(dirfd1after, "subdir", O_RDONLY | O_DIRECTORY)) == -1), "openat");
UV_SHOULD_SUCCEED((openat(dirfd2after, "../derp", O_RDWR|O_CREAT, 0644) == -1), "openat");
UV_SHOULD_ENOENT((openat(dirfd2after, "../../derpyluvs", O_RDWR|O_CREAT, 0644) == -1), "openat");
UV_SHOULD_ENOENT((openat(dirfd2after, "/etc/hosts", O_RDONLY) == -1), "openat");
UV_SHOULD_SUCCEED((openat(dirfd2after, "hooray", O_RDWR|O_CREAT, 0644) == -1), "openat");
UV_SHOULD_SUCCEED((openat(dirfd2after, uv_file1, O_RDWR|O_CREAT, 0644) == -1), "openat");
UV_SHOULD_ENOENT((openat(dirfd2after, uv_file2, O_RDWR|O_CREAT, 0644) == -1), "openat");
return 0;
}
static int
test_open(int do_uv)
{
char filename[256];
int dirfd;
int dirfd2;
int dirfd3;
UV_SHOULD_SUCCEED(((dirfd = open("/", O_RDONLY | O_DIRECTORY)) == -1), "open");
UV_SHOULD_SUCCEED(((dirfd2 = open(uv_dir2, O_RDONLY | O_DIRECTORY)) == -1), "open");
if (do_uv) {
printf("testing open\n");
do_unveil();
if (unveil("/tmp/alpha", uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/tmp/bravo", uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/tmp/charlie", uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/tmp/delta", uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/tmp/echo", uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/tmp/foxtrot", uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/tmp/golf", uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/tmp/hotel", uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/tmp/india", uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/tmp/juliet", uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/tmp/kilo", uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/tmp/lima", uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/tmp/money", uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/tmp/november", uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/tmp/oscar", uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/tmp/papa", uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/tmp/quebec", uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/tmp/romeo", uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/tmp/sierra", uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/tmp/tango", uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/tmp/uniform", uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/tmp/victor", uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/tmp/whiskey", uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/tmp/xray", uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/tmp/yankee", uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/tmp/zulu", uv_flags) == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
}
UV_SHOULD_SUCCEED((pledge("unveil stdio rpath cpath wpath exec", NULL) == -1), "pledge");
UV_SHOULD_ENOENT((open(uv_file2, O_RDWR) == -1), "open");
UV_SHOULD_ENOENT(((dirfd3= open(uv_dir2, O_RDONLY | O_DIRECTORY)) == -1), "open");
UV_SHOULD_SUCCEED((open(uv_file1, O_RDWR) == -1), "open");
if (!do_uv) {
UV_SHOULD_SUCCEED((unlink(uv_file1) == -1), "unlink");
UV_SHOULD_SUCCEED((open(uv_file1, O_RDWR|O_CREAT, 0644) == -1), "open");
}
sleep(1);
UV_SHOULD_SUCCEED((open(uv_file1, O_RDWR) == -1), "open");
UV_SHOULD_ENOENT((open(uv_file2, O_RDWR) == -1), "open");
(void) snprintf(filename, sizeof(filename), "%s/%s", uv_dir1, "newfile");
UV_SHOULD_SUCCEED((open(filename, O_RDWR|O_CREAT, 0644) == -1), "open");
(void) snprintf(filename, sizeof(filename), "/%s/%s", uv_dir1, "doubleslash");
UV_SHOULD_SUCCEED((open(filename, O_RDWR|O_CREAT, 0644) == -1), "open");
(void) snprintf(filename, sizeof(filename), "/%s//%s", uv_dir1, "doubleslash2");
UV_SHOULD_SUCCEED((open(filename, O_RDWR|O_CREAT, 0644) == -1), "open");
(void) snprintf(filename, sizeof(filename), "%s/%s", uv_dir2, "newfile");
UV_SHOULD_ENOENT((open(filename, O_RDWR|O_CREAT, 0644) == -1), "open");
if (do_uv) {
printf("testing flag escalation\n");
if (unveil(uv_file1, "x") == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil(uv_file1, "rx") == -1)
if (errno != EPERM)
err(1, "%s:%d - unveil", __FILE__,
__LINE__);
}
return 0;
}
static int
test_opendir(int do_uv)
{
char filename[256];
if (do_uv) {
printf("testing opendir\n");
do_unveil();
}
UV_SHOULD_SUCCEED((opendir(uv_dir1) == NULL), "opendir");
UV_SHOULD_ENOENT((opendir(uv_dir2) == NULL), "opendir");
(void) snprintf(filename, sizeof(filename), "/%s/.", uv_dir1);
UV_SHOULD_SUCCEED((opendir(filename) == NULL), "opendir");
(void) snprintf(filename, sizeof(filename), "/%s/..", uv_dir1);
UV_SHOULD_ENOENT((opendir(filename) == NULL), "opendir");
(void) snprintf(filename, sizeof(filename), "/%s/subdir", uv_dir1);
UV_SHOULD_SUCCEED((opendir(filename) == NULL), "opendir");
(void) snprintf(filename, sizeof(filename), "/%s/subdir/../subdir", uv_dir1);
UV_SHOULD_SUCCEED((opendir(filename) == NULL), "opendir");
(void) snprintf(filename, sizeof(filename), "/%s/../../%s/subdir", uv_dir1, uv_dir1);
UV_SHOULD_SUCCEED((opendir(filename) == NULL), "opendir");
(void) snprintf(filename, sizeof(filename), "/%s/subdir", uv_dir2);
UV_SHOULD_ENOENT((opendir(filename) == NULL), "opendir");
UV_SHOULD_ENOENT((opendir(filename) == NULL), "opendir");
(void) snprintf(filename, sizeof(filename), "%s/../..%s/subdir", uv_dir1, uv_dir2);
UV_SHOULD_ENOENT((opendir(filename) == NULL), "opendir");
return 0;
}
static int
test_realpath(int do_uv)
{
char buf[PATH_MAX];
if (do_uv) {
printf("testing realpath\n");
do_unveil();
}
UV_SHOULD_SUCCEED((realpath(uv_dir1, buf) == NULL), "realpath");
UV_SHOULD_ENOENT((realpath(uv_dir2, buf) == NULL), "realpath");
return 0;
}
static int
test_r(int do_uv)
{
if (do_uv) {
printf("testing \"r\"\n");
if (unveil(uv_file1, "r") == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/", "") == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
}
UV_SHOULD_SUCCEED((open(uv_file1, O_RDONLY) == -1), "open");
UV_SHOULD_EACCES((open(uv_file1, O_RDWR) == -1), "open");
return 0;
}
static int
test_rw(int do_uv)
{
if (do_uv) {
printf("testing \"rw\"\n");
if (unveil(uv_file1, "rw") == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/", "") == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
}
UV_SHOULD_SUCCEED((open(uv_file1, O_RDWR) == -1), "open");
UV_SHOULD_SUCCEED((open(uv_file1, O_RDONLY) == -1), "open");
return 0;
}
static int
test_x(int do_uv)
{
struct stat sb;
if (do_uv) {
printf("testing \"x\"\n");
if (unveil(uv_file1, "x") == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/", "") == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
}
UV_SHOULD_EACCES((lstat(uv_file1, &sb) == -1), "lstat");
UV_SHOULD_EACCES((open(uv_file1, O_RDONLY) == -1), "open");
UV_SHOULD_EACCES((open(uv_file1, O_RDONLY) == -1), "open");
UV_SHOULD_ENOENT((open(uv_file2, O_RDWR) == -1), "open");
return 0;
}
static int
test_noflags(int do_uv)
{
char filename[256];
if (do_uv) {
printf("testing clearing flags\n");
do_unveil();
}
UV_SHOULD_SUCCEED((pledge("unveil stdio rpath cpath wpath exec", NULL) == -1), "pledge");
UV_SHOULD_SUCCEED((open(uv_file1, O_RDWR) == -1), "open");
if (do_uv) {
if (unveil(uv_dir1, "") == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
}
(void) snprintf(filename, sizeof(filename), "%s/%s", uv_dir1, "noflagsiamboned");
UV_SHOULD_ENOENT((open(filename, O_RDWR|O_CREAT, 0644) == -1), "open");
UV_SHOULD_SUCCEED((open(uv_file1, O_RDWR) == -1), "open");
return 0;
}
static int
test_drounveil(int do_uv)
{
if (do_uv) {
printf("(testing unveil after pledge)\n");
do_unveil();
}
UV_SHOULD_SUCCEED((pledge("unveil stdio rpath cpath wpath exec", NULL) == -1), "pledge");
if (do_uv) {
do_unveil();
}
UV_SHOULD_SUCCEED((pledge("stdio rpath cpath wpath", NULL) == -1), "pledge");
UV_SHOULD_ENOENT((open(uv_file2, O_RDWR) == -1), "open");
UV_SHOULD_SUCCEED((open(uv_file1, O_RDWR) == -1), "open");
return 0;
}
static int
test_unlink(int do_uv)
{
char filename1[256];
char filename2[256];
char filename3[] = "/tmp/nukeme.XXXXXX";
int fd;
(void) snprintf(filename1, sizeof(filename1), "%s/%s", uv_dir1,
"nukeme");
(void) snprintf(filename2, sizeof(filename2), "%s/%s", uv_dir2,
"nukeme");
UV_SHOULD_SUCCEED((open(filename1, O_RDWR|O_CREAT, 0644) == -1), "open");
UV_SHOULD_SUCCEED((open(filename2, O_RDWR|O_CREAT, 0644) == -1), "open");
if ((fd = mkstemp(filename3)) == -1)
err(1, "%s:%d - mkstemp", __FILE__, __LINE__);
if (do_uv) {
printf("testing unlink\n");
do_unveil();
if (unveil(filename3, "rw") == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
}
UV_SHOULD_SUCCEED((pledge("unveil stdio fattr rpath cpath wpath", NULL) == -1),
"pledge");
UV_SHOULD_SUCCEED((unlink(filename1) == -1), "unlink");
UV_SHOULD_ENOENT((unlink(filename2) == -1), "unlink");
UV_SHOULD_EACCES((unlink(filename3) == -1), "unlink");
return 0;
}
static int
test_link(int do_uv)
{
char filename[256];
char filename2[256];
if (do_uv) {
printf("testing link\n");
do_unveil();
}
UV_SHOULD_SUCCEED((pledge("unveil stdio fattr rpath cpath wpath", NULL) == -1),
"pledge");
(void) snprintf(filename, sizeof(filename), "%s/%s", uv_dir1,
"linkuv1");
(void) snprintf(filename2, sizeof(filename2), "%s/%s", uv_dir2,
"linkuv2");
unlink(filename);
unlink(filename2);
UV_SHOULD_SUCCEED((link(uv_file1, filename) == -1), "link");
unlink(filename);
UV_SHOULD_ENOENT((link(uv_file2, filename) == -1), "link");
UV_SHOULD_ENOENT((link(uv_file1, filename2) == -1), "link");
if (do_uv) {
printf("testing link without O_CREAT\n");
if (unveil(filename, "rw") == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
}
UV_SHOULD_EACCES((link(uv_file1, filename) == -1), "link");
unlink(filename);
return 0;
}
static int
test_chdir(int do_uv)
{
if (do_uv) {
printf("testing chdir\n");
do_unveil2();
}
UV_SHOULD_SUCCEED((pledge("stdio fattr rpath", NULL) == -1), "pledge");
UV_SHOULD_ENOENT((chdir(uv_dir2) == -1), "chdir");
UV_SHOULD_SUCCEED((chdir(uv_dir1) == -1), "chdir");
UV_SHOULD_ENOENT((chdir(uv_dir2) == -1), "chdir");
return 0;
}
static int
test_parent_dir(int do_uv)
{
char filename[255];
if (do_uv) {
printf("testing parent dir\n");
do_unveil2();
} else {
(void) snprintf(filename, sizeof(filename), "/%s/doof", uv_dir1);
UV_SHOULD_SUCCEED((mkdir(filename, 0777) == -1), "mkdir");
(void) snprintf(filename, sizeof(filename), "/%s/doof/subdir2", uv_dir1);
UV_SHOULD_SUCCEED((mkdir(filename, 0777) == -1), "mkdir");
(void) snprintf(filename, sizeof(filename), "/%s/doof/subdir1", uv_dir1);
UV_SHOULD_SUCCEED((mkdir(filename, 0777) == -1), "mkdir");
(void) snprintf(filename, sizeof(filename), "/%s/doof/subdir1/poop", uv_dir1);
UV_SHOULD_SUCCEED((open(filename, O_RDWR|O_CREAT, 0644) == -1), "open");
(void) snprintf(filename, sizeof(filename), "/%s/doof/subdir1/link", uv_dir1);
UV_SHOULD_SUCCEED((symlink("../subdir1/poop", filename) == -1), "symlink");
}
sleep(1);
(void) snprintf(filename, sizeof(filename), "/%s/doof/subdir1/link", uv_dir1);
UV_SHOULD_SUCCEED((access(filename, R_OK) == -1), "access");
(void) snprintf(filename, sizeof(filename), "/%s/doof/subdir1/poop", uv_dir1);
UV_SHOULD_SUCCEED((access(filename, R_OK) == -1), "access");
UV_SHOULD_SUCCEED((chdir(uv_dir1) == -1), "chdir");
(void) snprintf(filename, sizeof(filename), "/%s/doof/subdir1", uv_dir1);
UV_SHOULD_SUCCEED((chdir(filename) == -1), "chdir");
UV_SHOULD_SUCCEED((access("poop", R_OK) == -1), "access");
UV_SHOULD_SUCCEED((chdir("../subdir2") == -1), "chdir");
UV_SHOULD_SUCCEED((chdir("../subdir1") == -1), "chdir");
UV_SHOULD_SUCCEED((chdir(filename) == -1), "chdir");
UV_SHOULD_SUCCEED((chdir("../../doof/subdir2") == -1), "chdir");
UV_SHOULD_SUCCEED((chdir("../../doof/subdir1") == -1), "chdir");
UV_SHOULD_SUCCEED((chdir("../../doof/subdir2") == -1), "chdir");
UV_SHOULD_SUCCEED((chdir("../../doof/subdir1") == -1), "chdir");
UV_SHOULD_SUCCEED((access("poop", R_OK) == -1), "access");
UV_SHOULD_SUCCEED((access("../subdir1/poop", R_OK) == -1), "access");
UV_SHOULD_ENOENT((chdir("../../..") == -1), "chdir");
UV_SHOULD_ENOENT((chdir(uv_dir2) == -1), "chdir");
return(0);
}
static int
test_rename(int do_uv)
{
char filename1[256];
char filename2[256];
char rfilename1[256];
char rfilename2[256];
int dirfd1, dirfd2;
if ((dirfd1 = open(uv_dir1, O_RDONLY | O_DIRECTORY)) == -1)
err(1, "%s:%d - open of dir1", __FILE__, __LINE__);
if ((dirfd2 = open(uv_dir2, O_RDONLY | O_DIRECTORY)) == -1)
err(1, "%s:%d - open of dir2", __FILE__, __LINE__);
(void) snprintf(filename1, sizeof(filename1), "%s/%s", uv_dir1,
"file1");
UV_SHOULD_SUCCEED((open(filename1, O_RDWR|O_CREAT, 0644) == -1), "open");
(void) snprintf(filename2, sizeof(filename2), "%s/%s", uv_dir2,
"file2");
UV_SHOULD_SUCCEED((open(filename2, O_RDWR|O_CREAT, 0644) == -1), "open");
(void) snprintf(rfilename1, sizeof(rfilename1), "%s/%s", uv_dir1,
"rfile1");
(void) snprintf(rfilename2, sizeof(rfilename2), "%s/%s", uv_dir2,
"rfile2");
if (do_uv) {
printf("testing rename\n");
do_unveil();
}
UV_SHOULD_SUCCEED((pledge("stdio fattr rpath wpath cpath", NULL) == -1),
"pledge");
UV_SHOULD_SUCCEED((rename(filename1, rfilename1) == -1), "rename");
UV_SHOULD_ENOENT((rename(filename2, rfilename2) == -1), "rename");
UV_SHOULD_SUCCEED((open(filename1, O_RDWR|O_CREAT, 0644) == -1), "open");
UV_SHOULD_ENOENT((rename(filename1, rfilename2) == -1), "rename");
UV_SHOULD_SUCCEED((open(filename1, O_RDWR|O_CREAT, 0644) == -1), "open");
UV_SHOULD_ENOENT((rename(filename1, uv_file2) == -1), "rename");
UV_SHOULD_SUCCEED((open(filename1, O_RDWR|O_CREAT, 0644) == -1), "open");
UV_SHOULD_ENOENT((renameat(dirfd1, "file1", dirfd2, "rfile2") == -1),
"renameat");
UV_SHOULD_SUCCEED((open(filename1, O_RDWR|O_CREAT, 0644) == -1), "open");
UV_SHOULD_ENOENT((renameat(dirfd1, "file1", dirfd2, rfilename2) == -1),
"renameat");
return (0);
}
static int
test_access(int do_uv)
{
if (do_uv) {
printf("testing access\n");
do_unveil();
}
UV_SHOULD_SUCCEED((access(uv_file1, R_OK) == -1), "access");
UV_SHOULD_ENOENT((access(uv_file2, R_OK) == -1), "access");
UV_SHOULD_ENOENT((access("/etc/passwd", R_OK) == -1), "access");
UV_SHOULD_SUCCEED((access(uv_dir1, R_OK) == -1), "access");
UV_SHOULD_ENOENT((access(uv_dir2, R_OK) == -1), "access");
UV_SHOULD_ENOENT((access("/", R_OK) == -1), "access");
UV_SHOULD_ENOENT((access("/home", F_OK) == -1), "access");
UV_SHOULD_SUCCEED((pledge("stdio fattr rpath", NULL) == -1), "pledge");
UV_SHOULD_SUCCEED((access(uv_file1, R_OK) == -1), "access");
UV_SHOULD_ENOENT((access(uv_file2, R_OK) == -1), "access");
UV_SHOULD_SUCCEED((access(uv_dir1, R_OK) == -1), "access");
UV_SHOULD_ENOENT((access(uv_dir2, R_OK) == -1), "access");
UV_SHOULD_ENOENT((access("/", R_OK) == -1), "access");
UV_SHOULD_ENOENT((access("/home", F_OK) == -1), "access");
return 0;
}
static int
test_chflags(int do_uv)
{
if (do_uv) {
printf("testing chflags\n");
do_unveil();
}
UV_SHOULD_SUCCEED((pledge("stdio fattr rpath", NULL) == -1), "pledge");
UV_SHOULD_SUCCEED((chflags(uv_file1, UF_NODUMP) == -1), "chflags");
UV_SHOULD_ENOENT((chflags(uv_file2, UF_NODUMP) == -1), "chflags");
return 0;
}
static int
test_stat(int do_uv)
{
if (do_uv) {
printf("testing stat\n");
do_unveil();
}
struct stat sb;
UV_SHOULD_SUCCEED((pledge("stdio fattr rpath", NULL) == -1), "pledge");
UV_SHOULD_SUCCEED((stat(uv_file1, &sb) == -1), "stat");
UV_SHOULD_ENOENT((stat(uv_file2, &sb) == -1), "stat");
UV_SHOULD_SUCCEED((stat(uv_dir1, &sb) == -1), "stat");
UV_SHOULD_ENOENT((stat(uv_dir2, &sb) == -1), "stat");
UV_SHOULD_ENOENT((stat("/", &sb) == -1), "stat");
return 0;
}
static int
test_stat2(int do_uv)
{
if (do_uv) {
printf("testing stat components to nonexistent \"rw\"\n");
if (unveil("/usr/share/man/nonexistent", "rw") == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
}
struct stat sb;
UV_SHOULD_SUCCEED((pledge("stdio fattr rpath", NULL) == -1), "pledge");
UV_SHOULD_ENOENT((stat("/", &sb) == -1), "stat");
UV_SHOULD_ENOENT((stat("/usr", &sb) == -1), "stat");
UV_SHOULD_ENOENT((stat("/usr/share", &sb) == -1), "stat");
UV_SHOULD_ENOENT((stat("/usr/share/man", &sb) == -1), "stat");
UV_SHOULD_ENOENT((stat("/usr/share/man/nonexistent", &sb) == -1), "stat");
return 0;
}
static int
test_statfs(int do_uv)
{
if (do_uv) {
printf("testing statfs\n");
do_unveil();
}
struct statfs sb;
UV_SHOULD_SUCCEED((statfs("/home", &sb) == -1), "statfs");
UV_SHOULD_SUCCEED((statfs("/", &sb) == -1), "statfs");
UV_SHOULD_SUCCEED((statfs(uv_file1, &sb) == -1), "statfs");
UV_SHOULD_SUCCEED((statfs(uv_file2, &sb) == -1), "statfs");
UV_SHOULD_SUCCEED((statfs(uv_dir1, &sb) == -1), "statfs");
UV_SHOULD_SUCCEED((statfs(uv_dir2, &sb) == -1), "statfs");
UV_SHOULD_SUCCEED((pledge("stdio fattr rpath", NULL) == -1), "pledge");
UV_SHOULD_SUCCEED((statfs(uv_file1, &sb) == -1), "statfs");
UV_SHOULD_SUCCEED((statfs(uv_file2, &sb) == -1), "statfs");
UV_SHOULD_SUCCEED((statfs(uv_dir1, &sb) == -1), "statfs");
UV_SHOULD_SUCCEED((statfs(uv_dir2, &sb) == -1), "statfs");
return 0;
}
static int
test_symlink(int do_uv)
{
char filename[256];
char filename2[256];
char buf[256];
struct stat sb;
if (do_uv) {
printf("testing symlink and lstat and readlink\n");
do_unveil();
}
UV_SHOULD_SUCCEED((pledge("unveil stdio fattr rpath cpath wpath", NULL) == -1),
"pledge");
(void) snprintf(filename, sizeof(filename), "%s/%s", uv_dir1,
"slinkuv1");
(void) snprintf(filename2, sizeof(filename2), "%s/%s", uv_dir2,
"slinkuv2");
unlink(filename);
unlink(filename2);
UV_SHOULD_SUCCEED((symlink(uv_file1, filename) == -1), "symlink");
UV_SHOULD_SUCCEED((lstat(filename, &sb) == -1), "lstat");
UV_SHOULD_SUCCEED((lstat(uv_file1, &sb) == -1), "lstat");
UV_SHOULD_SUCCEED((readlink(filename, buf, sizeof(buf)) == -1), "readlink");
unlink(filename);
UV_SHOULD_SUCCEED((symlink(uv_file2, filename) == -1), "symlink");
UV_SHOULD_SUCCEED((lstat(filename, &sb) == -1), "lstat");
UV_SHOULD_SUCCEED((readlink(filename, buf, sizeof(buf)) == -1), "readlink");
UV_SHOULD_ENOENT((lstat(uv_file2, &sb) == -1), "lstat");
UV_SHOULD_ENOENT((symlink(uv_file1, filename2) == -1), "symlink");
UV_SHOULD_ENOENT((readlink(filename2, buf, sizeof(buf)) == -1), "readlink");
unlink(filename);
if (do_uv) {
printf("testing symlink with \"rw\"\n");
if (unveil(filename, "rw") == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
}
UV_SHOULD_EACCES((symlink(uv_file1, filename) == -1), "symlink");
return 0;
}
static int
test_chmod(int do_uv)
{
if (do_uv) {
printf("testing chmod\n");
do_unveil();
}
UV_SHOULD_SUCCEED((pledge("stdio fattr rpath unveil", NULL) == -1), "pledge");
UV_SHOULD_SUCCEED((chmod(uv_file1, S_IRWXU) == -1), "chmod");
UV_SHOULD_ENOENT((chmod(uv_file2, S_IRWXU) == -1), "chmod");
UV_SHOULD_SUCCEED((chmod(uv_dir1, S_IRWXU) == -1), "chmod");
UV_SHOULD_ENOENT((chmod(uv_dir2, S_IRWXU) == -1), "chmod");
if (do_uv) {
printf("testing chmod should fail for read\n");
if (unveil(uv_file1, "r") == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
}
UV_SHOULD_EACCES((chmod(uv_file1, S_IRWXU) == -1), "chmod");
return 0;
}
static int
test_fork_body(int do_uv)
{
UV_SHOULD_SUCCEED((open(uv_file1, O_RDWR|O_CREAT, 0644) == -1), "open after fork");
UV_SHOULD_SUCCEED((opendir(uv_dir1) == NULL), "opendir after fork");
UV_SHOULD_ENOENT((opendir(uv_dir2) == NULL), "opendir after fork");
UV_SHOULD_ENOENT((open(uv_file2, O_RDWR|O_CREAT, 0644) == -1), "open after fork");
return 0;
}
static int
test_fork(int do_uv)
{
printf("testing fork inhertiance\n");
do_unveil();
return runcompare_internal(test_fork_body, 0);
}
static int
test_exec(int do_uv)
{
char *argv[] = {"/usr/bin/true", NULL};
extern char **environ;
if (do_uv) {
printf("testing execve with \"x\"\n");
if (unveil("/usr/bin/true", "x") == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/usr/lib", "r") == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/usr/libexec/ld.so", "r") == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
}
UV_SHOULD_SUCCEED((pledge("unveil stdio fattr exec", NULL) == -1), "pledge");
UV_SHOULD_SUCCEED((execve(argv[0], argv, environ) == -1), "execve");
return 0;
}
static int
test_exec2(int do_uv)
{
char *argv[] = {"/usr/bin/true", NULL};
extern char **environ;
if (do_uv) {
printf("testing execve with \"rw\"\n");
if (unveil("/usr/bin/true", "rw") == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/usr/lib", "r") == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/usr/libexec/ld.so", "r") == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
}
UV_SHOULD_SUCCEED((pledge("unveil stdio fattr exec", NULL) == -1), "pledge");
UV_SHOULD_EACCES((execve(argv[0], argv, environ) == -1), "execve");
return 0;
}
static int
test_slash(int do_uv)
{
extern char **environ;
if (do_uv) {
printf("testing unveil(\"/\")\n");
if (unveil("/bin/sh", "x") == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/", "r") == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
}
return 0;
}
static int
test_dot(int do_uv)
{
extern char **environ;
if (do_uv) {
printf("testing dot(\".\")\n");
if (unveil(".", "rwxc") == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if ((unlink(".") == -1) && errno != EPERM)
err(1, "%s:%d - unlink", __FILE__, __LINE__);
printf("testing dot flags(\".\")\n");
if (unveil(".", "r") == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if ((unlink(".") == -1) && errno != EACCES)
warn("%s:%d - unlink", __FILE__, __LINE__);
}
return 0;
}
static int
test_bypassunveil(int do_uv)
{
if (do_uv) {
printf("testing BYPASSUNVEIL\n");
do_unveil2();
}
char filename3[] = "/tmp/nukeme.XXXXXX";
UV_SHOULD_SUCCEED((pledge("stdio tmppath", NULL) == -1), "pledge");
UV_SHOULD_SUCCEED((mkstemp(filename3) == -1), "mkstemp");
return 0;
}
static int
test_dotdotup(int do_uv)
{
UV_SHOULD_SUCCEED((open("/tmp/hello", O_RDWR|O_CREAT, 0644) == -1), "open");
if (do_uv) {
printf("testing dotdotup\n");
do_unveil2();
}
if ((chdir(uv_dir1) == -1)) {
err(1, "chdir");
}
UV_SHOULD_SUCCEED((open("./derp", O_RDWR|O_CREAT, 0644) == -1), "open");
UV_SHOULD_SUCCEED((open("derp", O_RDWR|O_CREAT, 0644) == -1), "open");
UV_SHOULD_ENOENT((open("../hello", O_RDWR|O_CREAT, 0644) == -1), "open");
UV_SHOULD_ENOENT((open(".././hello", O_RDWR|O_CREAT, 0644) == -1), "open");
return 0;
}
static int
test_kn(int do_uv)
{
if (do_uv) {
printf("testing read only with one writeable file\n");
if (unveil("/", "r") == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
if (unveil("/dev/null", "rw") == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
}
UV_SHOULD_SUCCEED((open("/dev/null", O_RDWR) == -1), "open");
UV_SHOULD_SUCCEED((open("/dev/zero", O_RDONLY) == -1), "open");
UV_SHOULD_EACCES((open("/dev/zero", O_RDWR) == -1), "open");
return 0;
}
static int
test_pathdiscover(int do_uv)
{
struct stat sb;
if (do_uv) {
printf("testing path discovery\n");
if (unveil("/usr/share/man", "rx") == -1)
err(1, "%s:%d - unveil", __FILE__, __LINE__);
}
UV_SHOULD_SUCCEED((lstat("/usr/share/man", &sb) == -1), "lstat");
UV_SHOULD_SUCCEED((lstat("/usr/share/man/../../share/man", &sb) == -1), "lstat");
UV_SHOULD_SUCCEED((lstat("/usr/share/man/../../local/../share/man", &sb) == -1), "lstat");
return 0;
}
static int
test_fchdir(int do_uv)
{
int fd2, fd;
UV_SHOULD_SUCCEED(((fd2 = open(uv_dir2, O_RDONLY | O_DIRECTORY)) == -1), "open");
if (do_uv) {
printf("testing fchdir\n");
do_unveil2();
}
UV_SHOULD_SUCCEED((pledge("stdio fattr rpath", NULL) == -1), "pledge");
UV_SHOULD_SUCCEED((chdir(uv_dir1) == -1), "chdir");
UV_SHOULD_SUCCEED((fchdir(fd2) == -1), "fchdir");
UV_SHOULD_ENOENT((fd = (open("subdir", O_RDONLY | O_DIRECTORY)) == -1), "open");
return 0;
}
static int
test_fork_locked(int do_uv)
{
int status;
pid_t pid;
if (do_uv) {
printf("testing unveil locked fork\n");
unveil(NULL, NULL);
}
pid = fork();
if (pid == 0) {
UV_SHOULD_EPERM((unveil("/", "rwx") == -1), "unveil");
exit(0);
}
status = 0;
waitpid(pid, &status, 0);
if (WIFSIGNALED(status))
errx(1, "child exited with signal %d", WTERMSIG(status));
if (WEXITSTATUS(status) == 0)
return 0;
else
return 1;
}
static int
test_intermediate_node(int do_uv)
{
struct stat st;
if (do_uv) {
printf("testing unveil on intermediate node\n");
UV_SHOULD_SUCCEED((unveil("/", "r") == -1), "unveil");
UV_SHOULD_SUCCEED((unveil("/usr/bin/id", "rx") == -1),
"unveil");
UV_SHOULD_SUCCEED((unveil(NULL, NULL) == -1), "unveil");
}
UV_SHOULD_SUCCEED((stat("/usr/bin", &st) == -1), "stat");
return 0;
}
static int
test_noaccess_node(int do_uv)
{
struct stat st;
if (do_uv) {
printf("testing unveil on noaccess node\n");
UV_SHOULD_SUCCEED((unveil("/", "r") == -1), "unveil");
UV_SHOULD_SUCCEED((unveil("/usr/bin/id", "rx") == -1),
"unveil");
UV_SHOULD_SUCCEED((unveil("/usr/bin", "") == -1), "unveil");
UV_SHOULD_SUCCEED((unveil(NULL, NULL) == -1), "unveil");
}
UV_SHOULD_ENOENT((stat("/usr/bin", &st) == -1), "stat");
return 0;
}
int
main(int argc, char *argv[])
{
int failures = 0;
test_setup();
failures += runcompare(test_open);
failures += runcompare(test_openat);
failures += runcompare(test_opendir);
failures += runcompare(test_noflags);
failures += runcompare(test_drounveil);
failures += runcompare(test_r);
failures += runcompare(test_rw);
failures += runcompare(test_x);
failures += runcompare(test_unlink);
failures += runcompare(test_link);
failures += runcompare(test_chdir);
failures += runcompare(test_rename);
failures += runcompare(test_access);
failures += runcompare(test_chflags);
failures += runcompare(test_stat);
failures += runcompare(test_stat2);
failures += runcompare(test_statfs);
failures += runcompare(test_symlink);
failures += runcompare(test_chmod);
failures += runcompare(test_exec);
failures += runcompare(test_exec2);
failures += runcompare(test_realpath);
failures += runcompare(test_parent_dir);
failures += runcompare(test_slash);
failures += runcompare(test_dot);
failures += runcompare(test_bypassunveil);
failures += runcompare_internal(test_fork, 0);
failures += runcompare(test_dotdotup);
failures += runcompare(test_kn);
failures += runcompare(test_pathdiscover);
failures += runcompare(test_fchdir);
failures += runcompare(test_fork_locked);
failures += runcompare(test_intermediate_node);
failures += runcompare(test_noaccess_node);
exit(failures);
}