/*
 * sakura_filesystem_test.c
 *
 * Testing program for fs/sakura_mount.c fs/sakura_umount.c fs/sakura_maymount.c
 * fs/sakura_chroot.c fs/sakura_pivot.c
 *
 * Copyright (C) 2005-2011  NTT DATA CORPORATION
 *
 * Version: 1.6.9   2011/04/01
 *
 */
#define _GNU_SOURCE
#include "include.h"

static void show_prompt(const char *str, const int is_enforce)
{
	printf("Testing %60s: (%s) ", str,
	       is_enforce ? "must fail" : "should success");
	errno = 0;
}

#define TEST_DIR         "/tmp/mount/"
#define TEST_DIR_PATTERN "/tmp/\\?\\?\\?\\?\\?/"
#define TEST_DIR_BIND    "/tmp/mount_bind/"
#define TEST_DIR_MOVE    "/tmp/mount_move/"

#ifndef MS_MOVE
#define MS_MOVE         8192
#endif

static const char *pivot_root_dir = "/proc/";

static int child(void *arg)
{
	errno = 0;
	pivot_root(pivot_root_dir, proc_policy_dir);
	return errno;
}

static int system_fd = EOF;

static void write_policy(const char *cp)
{
	write(system_fd, cp, strlen(cp));
}

static const unsigned char compressed_ext2_image_sample[1350] = {
	0x1F, 0x8B, 0x08, 0x00, 0xA8, 0xF2, 0x96, 0x4B, 0x02, 0x03, 0xED, 0xDC,
	0x3D, 0x4B, 0x5B, 0x51, 0x18, 0x07, 0xF0, 0xE7, 0xDE, 0xAB, 0x14, 0x8C,
	0xAB, 0xD5, 0x9A, 0xF8, 0x36, 0x0B, 0xA1, 0xE0, 0xE0, 0xDC, 0xD0, 0xAD,
	0xD0, 0xC5, 0xAF, 0x50, 0x9C, 0x42, 0x1D, 0x6A, 0xE6, 0xA6, 0x9B, 0x9B,
	0x8B, 0xD8, 0xA5, 0x5B, 0x97, 0x2E, 0xF9, 0x0E, 0x85, 0x4C, 0xF6, 0x23,
	0x74, 0x70, 0x55, 0x28, 0x52, 0xA8, 0xDD, 0xED, 0xB9, 0xB9, 0xB1, 0xA6,
	0xEA, 0x24, 0xA5, 0x81, 0xDE, 0xDF, 0x0F, 0x9E, 0xDC, 0xB7, 0x13, 0x2E,
	0xF7, 0xC0, 0xFF, 0x70, 0xCE, 0x85, 0x24, 0x02, 0xA8, 0xAB, 0x7E, 0xF9,
	0x31, 0x13, 0xB1, 0x95, 0x36, 0xA7, 0x45, 0x44, 0x2F, 0x6D, 0xB3, 0xC9,
	0x06, 0xEB, 0x55, 0xF5, 0xC7, 0x87, 0x9F, 0x7E, 0x1C, 0xBF, 0x88, 0x68,
	0xC5, 0xCE, 0xF7, 0x6C, 0xD4, 0x6E, 0x74, 0xFC, 0xF2, 0x62, 0x74, 0xED,
	0xFA, 0x7B, 0x8D, 0xB8, 0x69, 0x9F, 0x8F, 0xCF, 0x9F, 0x1D, 0x7E, 0x78,
	0xF7, 0x6D, 0xD8, 0x79, 0xFF, 0x71, 0xD0, 0xED, 0xBC, 0xCD, 0x9A, 0xBD,
	0x69, 0x3C, 0xEB, 0xE0, 0xCB, 0xF0, 0xA4, 0xF9, 0xF5, 0xF9, 0xCA, 0xE0,
	0xE0, 0x72, 0xBB, 0x7B, 0xD4, 0x1A, 0xE6, 0x13, 0xD7, 0xAA, 0xE7, 0x82,
	0x7A, 0x29, 0xAA, 0xF8, 0xC7, 0xEC, 0x28, 0xFF, 0xBD, 0xC8, 0x75, 0x09,
	0xD4, 0xC6, 0x55, 0x92, 0x4D, 0x71, 0xFA, 0x71, 0x05, 0x4C, 0xCF, 0xA3,
	0xBB, 0xE3, 0x01, 0x50, 0x0F, 0x93, 0xEB, 0xDF, 0xEB, 0xFA, 0x97, 0x13,
	0x80, 0x8B, 0x67, 0xD5, 0x02, 0xE4, 0xEE, 0xFD, 0x8B, 0x3F, 0xD6, 0x22,
	0x0B, 0xA6, 0x6A, 0xC0, 0x5F, 0xF6, 0xB9, 0x1C, 0x7F, 0x9E, 0xDE, 0x37,
	0xFE, 0xE4, 0xB1, 0x34, 0xD1, 0xEE, 0x71, 0xAA, 0xC5, 0x54, 0xE5, 0xB9,
	0x27, 0xA9, 0x96, 0x53, 0x35, 0xA3, 0x7C, 0x13, 0x1A, 0xB1, 0x92, 0x6A,
	0x35, 0xD5, 0xDA, 0xF8, 0x75, 0xE9, 0x86, 0x6E, 0x05, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x81,
	0xCA, 0xDF, 0xD8, 0xCF, 0x47, 0x96, 0xB7, 0x7F, 0xEF, 0xE7, 0x79, 0xBB,
	0x5D, 0xFD, 0x87, 0xDF, 0x79, 0x31, 0x97, 0x77, 0xF7, 0xDE, 0xEC, 0x6F,
	0xEE, 0xEE, 0xF5, 0x5E, 0xBF, 0xD2, 0x57, 0xF0, 0xBF, 0x69, 0xDC, 0xCA,
	0xFF, 0xCF, 0xA2, 0xCA, 0x3F, 0x50, 0x13, 0x33, 0xBA, 0x00, 0xE4, 0x1F,
	0x90, 0x7F, 0x40, 0xFE, 0x01, 0xF9, 0x07, 0xE4, 0x1F, 0x90, 0x7F, 0x40,
	0xFE, 0x01, 0xF9, 0x07, 0xE4, 0x1F, 0x90, 0x7F, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFA, 0xF9, 0x05, 0x34, 0xF2,
	0x14, 0x08, 0x00, 0x00, 0x10, 0x00
};

int main(int argc, char *argv[])
{
	char c = 0;
	ccs_test_init();
	if (strncmp(proc_policy_dir, "/proc/", 6))
		pivot_root_dir = "/sys/kernel/security/";
	system_fd = open(proc_policy_system_policy, O_RDWR);
	if (system_fd == EOF) {
		fprintf(stderr, "You can't use this program for this kernel."
			"\n");
		return 1;
	}
	if (write(system_fd, "", 0) != 0) {
		fprintf(stderr, "You need to register this program to %s to "
			"run this program.\n", proc_policy_manager);
		return 1;
	}

	/* Test mount(). */
	{
		write_status("RESTRICT_MOUNT=enforcing\n");
		show_prompt("mount('dev\\011name', '/', 'fs\\011name') ", 1);
		if (mount("dev\tname", "/", "fs\tname", 0, NULL) == EOF &&
		    errno == EPERM)
			printf("OK: Permission denied.\n");
		else if (errno == ENODEV)
			printf("OK: No such device.\n");
		else
			printf("BUG: %s\n", strerror(errno));
		write_status("RESTRICT_MOUNT=learning\n");
		show_prompt("mount('dev\\011name', '/', 'fs\\011name') ", 0);
		if (mount("dev\tname", "/", "fs\tname", 0, NULL) == EOF &&
		    errno == ENOMEM)
			printf("OK: Out of memory.\n");
		else if (errno == ENODEV)
			printf("OK: No such device.\n");
		else
			printf("BUG: %s\n", strerror(errno));
		write_status("RESTRICT_MOUNT=enforcing\n");
		show_prompt("mount('dev\\011name', '/', 'fs\\011name') ", 0);
		if (mount("dev\tname", "/", "fs\tname", 0, NULL) == EOF &&
		    errno == ENOMEM)
			printf("OK: Out of memory.\n");
		else if (errno == ENODEV)
			printf("OK: No such device.\n");
		else
			printf("BUG: %s\n", strerror(errno));
		write_policy("delete allow_mount dev\\011name / "
			     "fs\\011name 0\n");
		show_prompt("mount('dev\\011name', '/', 'fs\\011name') ", 1);
		if (mount("dev\tname", "/", "fs\tname", 0, NULL) == EOF &&
		    errno == EPERM)
			printf("OK: Permission denied.\n");
		else if (errno == ENODEV)
			printf("OK: No such device.\n");
		else
			printf("BUG: %s\n", strerror(errno));
		write_status("RESTRICT_MOUNT=learning\n");
		show_prompt("mount(NULL, '/', 'tmpfs') ", 0);
		if (mount(NULL, "/", "tmpfs", 0, NULL))
			printf("BUG: %s\n", strerror(errno));
		else
			printf("OK: Success\n");
		write_status("RESTRICT_MOUNT=enforcing\n");
		show_prompt("mount(NULL, '/', 'tmpfs') ", 0);
		if (mount(NULL, "/", "tmpfs", 0, NULL))
			printf("BUG: %s\n", strerror(errno));
		else
			printf("OK: Success\n");
		show_prompt("mount('anydev', '/', 'tmpfs') ", 0);
		if (mount("anydev", "/", "tmpfs", 0, NULL))
			printf("BUG: %s\n", strerror(errno));
		else
			printf("OK: Success\n");
		write_policy("delete allow_mount <NULL> / tmpfs 0\n");
		write_policy("allow_mount anydev / tmpfs 0\n");
		show_prompt("mount(NULL, '/', 'tmpfs') ", 0);
		if (mount(NULL, "/", "tmpfs", 0, NULL))
			printf("BUG: %s\n", strerror(errno));
		else
			printf("OK: Success\n");
		write_policy("delete allow_mount anydev / tmpfs 0\n");
		write_status("RESTRICT_MOUNT=permissive\n");
		show_prompt("mount(NULL, NULL, 'tmpfs') ", 1);
		if (mount(NULL, NULL, "tmpfs", 0, NULL))
			printf("OK: %s\n", strerror(errno));
		else
			printf("BUG: Did not fail.\n");
		show_prompt("mount(NULL, NULL, NULL) ", 1);
		if (mount(NULL, NULL, NULL, 0, NULL))
			printf("OK: %s\n", strerror(errno));
		else
			printf("BUG: Did not fail.\n");
		show_prompt("mount('/', NULL, NULL) ", 1);
		if (mount("/", NULL, NULL, 0, NULL))
			printf("OK: %s\n", strerror(errno));
		else
			printf("BUG: Did not fail.\n");
		show_prompt("mount('/', NULL, 'tmpfs') ", 1);
		if (mount("/", NULL, "tmpfs", 0, NULL))
			printf("OK: %s\n", strerror(errno));
		else
			printf("BUG: Did not fail.\n");
		show_prompt("mount('/', '/', 'nonexistentfs') ", 1);
		if (mount("/", "/", "nonexistentfs", 0, NULL))
			printf("OK: %s\n", strerror(errno));
		else
			printf("BUG: Did not fail.\n");
		write_status("RESTRICT_MOUNT=disabled\n");
	}

	mkdir(TEST_DIR, 0755);
	mkdir(TEST_DIR_BIND, 0755);
	mkdir(TEST_DIR_MOVE, 0755);

	/* Test mount(). */
	{
		static char buf[4096];
		char *dev_ram_path = canonicalize_file_name("/dev/ram0");
		if (!dev_ram_path)
			dev_ram_path = canonicalize_file_name("/dev/ram");
		if (!dev_ram_path) {
			dev_ram_path = "/dev/ram0";
			mknod(dev_ram_path, S_IFBLK, MKDEV(1, 0));
		}
		memset(buf, 0, sizeof(buf));
		{
			struct stat sbuf;
			FILE *fp = NULL;
			snprintf(buf, sizeof(buf) - 1, "zcat - > %s",
				 dev_ram_path);
			if (lstat(dev_ram_path, &sbuf) == 0 &&
			    S_ISBLK(sbuf.st_mode) && MAJOR(sbuf.st_rdev) == 1)
				fp = popen(buf, "w");
			if (fp) {
				fwrite(compressed_ext2_image_sample, 1,
				       sizeof(compressed_ext2_image_sample),
				       fp);
				pclose(fp);
			} else
				fprintf(stderr, "Can't write to %s .\n",
					dev_ram_path);
		}
		write_status("RESTRICT_MOUNT=enforcing\n");

		/* Test standard case */
		show_prompt("mount('none', '" TEST_DIR "', 'tmpfs') for '"
			   TEST_DIR "'", 1);
		if (mount("none", TEST_DIR, "tmpfs", 0, NULL) == EOF &&
		    errno == EPERM)
			printf("OK: Permission denied.\n");
		else
			printf("BUG: %s\n", strerror(errno));

		/* Test device_name with pattern */
		snprintf(buf, sizeof(buf) - 1, "mount('%s', '" TEST_DIR
			 "', 'ext2') for '%s\\*'", dev_ram_path, dev_ram_path);
		show_prompt(buf, 1);
		if (mount(dev_ram_path, TEST_DIR, "ext2", MS_RDONLY, NULL)
		    == EOF && errno == EPERM)
			printf("OK: Permission denied.\n");
		else
			printf("BUG: %s\n", strerror(errno));

		/* Test dir_name with pattern */
		show_prompt("mount('none', '" TEST_DIR "', 'tmpfs') for '"
			   TEST_DIR_PATTERN "'", 1);
		if (mount("none", TEST_DIR, "tmpfs", 0, NULL) == EOF &&
		    errno == EPERM)
			printf("OK: Permission denied.\n");
		else
			printf("BUG: %s\n", strerror(errno));

		/* Test standard case */
		write_policy("allow_mount none " TEST_DIR " tmpfs 0\n");
		show_prompt("mount('none', '" TEST_DIR "', 'tmpfs') for '"
			   TEST_DIR "'", 0);
		if (mount("none", TEST_DIR, "tmpfs", 0, NULL) == 0)
			printf("OK\n");
		else
			printf("FAILED: %s\n", strerror(errno));
		write_policy("delete allow_mount none " TEST_DIR " tmpfs 0\n");

		/* Test device_name with pattern */
		snprintf(buf, sizeof(buf) - 1, "allow_mount %s\\* " TEST_DIR
			 " ext2 1\n", dev_ram_path);
		write_policy(buf);
		snprintf(buf, sizeof(buf) - 1, "mount('%s', '" TEST_DIR
			 "', 'ext2') for '%s\\*'", dev_ram_path, dev_ram_path);
		show_prompt(buf, 0);
		if (mount(dev_ram_path, TEST_DIR, "ext2", MS_RDONLY, NULL) == 0)
			printf("OK\n");
		else
			printf("FAILED: %s\n", strerror(errno));
		snprintf(buf, sizeof(buf) - 1, "delete allow_mount %s\\* "
			 TEST_DIR " ext2 1\n", dev_ram_path);
		write_policy(buf);

		/* Test dir_name with pattern */
		write_policy("allow_mount none " TEST_DIR_PATTERN " tmpfs 0\n");
		show_prompt("mount('none', '" TEST_DIR "', 'tmpfs') for '"
			   TEST_DIR_PATTERN "'", 0);
		if (mount("none", TEST_DIR, "tmpfs", 0, NULL) == 0)
			printf("OK\n");
		else
			printf("FAILED: %s\n", strerror(errno));
		write_policy("delete allow_mount none " TEST_DIR_PATTERN
			    " tmpfs 0\n");

		write_status("RESTRICT_MOUNT=disabled\n");
		while (umount(TEST_DIR) == 0)
			c++; /* Dummy. */
	}

	/* Test mount(). */
	{
		mount("none", TEST_DIR, "tmpfs", 0, NULL);
		write_status("RESTRICT_MOUNT=enforcing\n");

		/* Test remount case */
		show_prompt("mount('" TEST_DIR "', MS_REMOUNT)", 1);
		if (mount("none", TEST_DIR, "tmpfs", MS_REMOUNT, NULL) == EOF
		    && errno == EPERM)
			printf("OK: Permission denied.\n");
		else
			printf("BUG: %s\n", strerror(errno));
		show_prompt("mount('" TEST_DIR "', MS_REMOUNT)", 1);
		if (mount(NULL, TEST_DIR, NULL, MS_REMOUNT, NULL) == EOF
		    && errno == EPERM)
			printf("OK: Permission denied.\n");
		else
			printf("BUG: %s\n", strerror(errno));
		write_policy("allow_mount something " TEST_DIR
			     " --remount 0\n");
		show_prompt("mount('" TEST_DIR "', MS_REMOUNT)", 0);
		if (mount(NULL, TEST_DIR, NULL, MS_REMOUNT, NULL))
			printf("BUG: %s\n", strerror(errno));
		else
			printf("OK: Success.\n");
		write_policy("delete allow_mount something " TEST_DIR
			     " --remount 0\n");

		/* Test bind case */
		show_prompt("mount('" TEST_DIR "', '" TEST_DIR_BIND
			   "', MS_BIND)", 1);
		if (mount(TEST_DIR, TEST_DIR_BIND, NULL, MS_BIND, NULL) == EOF
		    && errno == EPERM)
			printf("OK: Permission denied.\n");
		else
			printf("BUG: %s\n", strerror(errno));

		/* Test move case */
		show_prompt("mount('" TEST_DIR "', '" TEST_DIR_MOVE
			   "', MS_MOVE)", 1);
		if (mount(TEST_DIR, TEST_DIR_MOVE, NULL, MS_MOVE, NULL) == EOF
		    && errno == EPERM)
			printf("OK: Permission denied.\n");
		else
			printf("BUG: %s\n", strerror(errno));

		/* Test remount case */
		write_policy("allow_mount any " TEST_DIR " --remount 0\n");
		show_prompt("mount('" TEST_DIR "', MS_REMOUNT)", 0);
		if (mount("none", TEST_DIR, "tmpfs", MS_REMOUNT, NULL) == 0)
			printf("OK\n");
		else
			printf("FAILED: %s\n", strerror(errno));
		write_policy("delete allow_mount any " TEST_DIR
			    " --remount 0\n");

		/* Test bind case */
		write_policy("allow_mount " TEST_DIR " " TEST_DIR_BIND
			    " --bind 0\n");
		show_prompt("mount('" TEST_DIR "', '" TEST_DIR_BIND
			   "', MS_BIND)", 0);
		if (mount(TEST_DIR, TEST_DIR_BIND, NULL, MS_BIND, NULL) == 0)
			printf("OK\n");
		else
			printf("FAILED: %s\n", strerror(errno));
		umount(TEST_DIR_BIND);
		write_policy("delete allow_mount " TEST_DIR " " TEST_DIR_BIND
			    " --bind 0\n");

		/* Test move case */
		write_policy("allow_mount " TEST_DIR " " TEST_DIR_MOVE
			    " --move 0\n");
		show_prompt("mount('" TEST_DIR "', '" TEST_DIR_MOVE
			   "', MS_MOVE)", 0);
		if (mount(TEST_DIR, TEST_DIR_MOVE, NULL, MS_MOVE, NULL) == 0)
			printf("OK\n");
		else
			printf("FAILED: %s\n", strerror(errno));
		umount(TEST_DIR_MOVE);
		write_policy("delete allow_mount " TEST_DIR " " TEST_DIR_MOVE
			    " --move 0\n");

		write_status("RESTRICT_MOUNT=disabled\n");
		while (umount(TEST_DIR) == 0)
			c++; /* Dummy. */
	}

	/* Test mount(). */
	{
		mount("none", TEST_DIR, "tmpfs", 0, NULL);
		write_status("DENY_CONCEAL_MOUNT=enforcing\n");

		show_prompt("mount('none', '" TEST_DIR "', 'tmpfs')", 1);
		if (mount("none", TEST_DIR, "tmpfs", 0, NULL) == EOF &&
		    errno == EPERM)
			printf("OK: Permission denied.\n");
		else
			printf("BUG: %s\n", strerror(errno));

		show_prompt("mount('none', '/tmp/', 'tmpfs')", 1);
		if (mount("none", "/tmp/", "tmpfs", 0, NULL) == EOF &&
		    errno == EPERM)
			printf("OK: Permission denied.\n");
		else
			printf("BUG: %s\n", strerror(errno));

		show_prompt("mount('none', '/', 'tmpfs')", 1);
		if (mount("none", "/", "tmpfs", 0, NULL) == EOF &&
		    errno == EPERM)
			printf("OK: Permission denied.\n");
		else
			printf("BUG: %s\n", strerror(errno));

		write_status("DENY_CONCEAL_MOUNT=permissive\n");

		show_prompt("mount('none', '" TEST_DIR "', 'tmpfs')", 0);
		if (mount("none", TEST_DIR, "tmpfs", 0, NULL) == 0)
			printf("OK\n");
		else
			printf("FAILED: %s\n", strerror(errno));

		write_status("DENY_CONCEAL_MOUNT=disabled\n");
		while (umount(TEST_DIR) == 0)
			c++; /* Dummy. */
	}

	/* Test umount(). */
	{
		write_status("RESTRICT_UNMOUNT=enforcing\n");

		/* Test standard case */
		write_policy("deny_unmount " TEST_DIR "\n");

		mount("none", TEST_DIR, "tmpfs", 0, NULL);
		show_prompt("umount('" TEST_DIR "') for '" TEST_DIR "'", 1);
		if (umount(TEST_DIR) == EOF && errno == EPERM)
			printf("OK: Permission denied.\n");
		else
			printf("BUG: %s\n", strerror(errno));
		write_policy("delete deny_unmount " TEST_DIR "\n");

		mount("none", TEST_DIR, "tmpfs", 0, NULL);
		show_prompt("umount('" TEST_DIR "') for '" TEST_DIR "'", 0);
		if (umount(TEST_DIR) == 0)
			printf("OK\n");
		else
			printf("FAILED: %s\n", strerror(errno));

		/* Test pattern */
		write_policy("deny_unmount " TEST_DIR_PATTERN "\n");
		mount("none", TEST_DIR, "tmpfs", 0, NULL);
		show_prompt("umount('" TEST_DIR "') for '" TEST_DIR_PATTERN "'",
			   1);
		if (umount(TEST_DIR) == EOF && errno == EPERM)
			printf("OK: Permission denied.\n");
		else
			printf("BUG: %s\n", strerror(errno));
		write_policy("delete deny_unmount " TEST_DIR_PATTERN "\n");

		write_status("RESTRICT_UNMOUNT=disabled\n");
		while (umount(TEST_DIR) == 0)
			c++; /* Dummy. */
	}

	/* Test chroot(). */
	{
		write_status("RESTRICT_CHROOT=enforcing\n");

		/* Test standard case */
		write_policy("allow_chroot " TEST_DIR "\n");
		show_prompt("chroot('" TEST_DIR "') for '" TEST_DIR "'", 0);
		fflush(stdout);
		if (fork() == 0) {
			if (chroot(TEST_DIR) == 0)
				printf("OK\n");
			else
				printf("FAILED: %s\n", strerror(errno));
			fflush(stdout);
			_exit(0);
		}
		wait(NULL);
		write_policy("delete allow_chroot " TEST_DIR "\n");

		show_prompt("chroot('" TEST_DIR "') for '" TEST_DIR "'", 1);
		fflush(stdout);
		if (fork() == 0) {
			if (chroot(TEST_DIR) == EOF && errno == EPERM)
				printf("OK: Permission denied.\n");
			else
				printf("BUG: %s\n", strerror(errno));
			fflush(stdout);
			_exit(0);
		}
		wait(NULL);

		/* Test pattern */
		write_policy("allow_chroot " TEST_DIR_PATTERN "\n");
		show_prompt("chroot('" TEST_DIR "') for '" TEST_DIR_PATTERN "'",
			   0);
		fflush(stdout);
		if (fork() == 0) {
			if (chroot(TEST_DIR) == 0)
				printf("OK\n");
			else
				printf("FAILED: %s\n", strerror(errno));
			fflush(stdout);
			_exit(0);
		}
		wait(NULL);
		write_policy("delete allow_chroot " TEST_DIR_PATTERN "\n");

		write_status("RESTRICT_CHROOT=disabled\n");
	}

	/* Test pivot_root(). */
	{
		int error;
		char *stack = malloc(8192);
		write_status("RESTRICT_PIVOT_ROOT=enforcing\n");

		snprintf(stack, 8191, "allow_pivot_root %s %s\n",
			 pivot_root_dir, proc_policy_dir);
		write_policy(stack);
		snprintf(stack, 8191, "pivot_root('%s', '%s')", pivot_root_dir,
			 proc_policy_dir);
		show_prompt(stack, 0);
		{
			const pid_t pid = clone(child, stack + (8192 / 2),
						CLONE_NEWNS, NULL);
			while (waitpid(pid, &error, __WALL) == EOF &&
			       errno == EINTR)
				c++; /* Dummy. */
		}
		errno = WIFEXITED(error) ? WEXITSTATUS(error) : -1;
		if (errno == 0)
			printf("OK\n");
		else
			printf("FAILED: %s\n", strerror(errno));

		snprintf(stack, 8191, "delete allow_pivot_root %s %s\n",
			 pivot_root_dir, proc_policy_dir);
		write_policy(stack);
		snprintf(stack, 8191, "pivot_root('%s', '%s')", pivot_root_dir,
			 proc_policy_dir);
		show_prompt(stack, 1);
		{
			const pid_t pid = clone(child, stack + (8192 / 2),
						CLONE_NEWNS, NULL);
			while (waitpid(pid, &error, __WALL) == EOF &&
			       errno == EINTR)
				c++; /* Dummy. */
		}
		errno = WIFEXITED(error) ? WEXITSTATUS(error) : -1;
		if (errno == EPERM)
			printf("OK: Permission denied.\n");
		else
			printf("BUG: %s\n", strerror(errno));

		write_status("RESTRICT_PIVOT_ROOT=permissive\n");
		snprintf(stack, 8191, "pivot_root('%s', '%s')", pivot_root_dir,
			 proc_policy_dir);
		show_prompt(stack, 0);
		{
			const pid_t pid = clone(child, stack + (8192 / 2),
						CLONE_NEWNS, NULL);
			while (waitpid(pid, &error, __WALL) == EOF &&
			       errno == EINTR)
				c++; /* Dummy. */
		}
		errno = WIFEXITED(error) ? WEXITSTATUS(error) : -1;
		if (errno == 0)
			printf("OK\n");
		else
			printf("FAILED: %s\n", strerror(errno));

		write_status("RESTRICT_PIVOT_ROOT=disabled\n");

		free(stack);
	}

	rmdir(TEST_DIR_MOVE);
	rmdir(TEST_DIR_BIND);
	rmdir(TEST_DIR);

	close(system_fd);
	clear_status();
	return 0;
}
