Home | History | Annotate | Download | only in tomoyo
      1 /******************************************************************************/
      2 /*                                                                            */
      3 /* Copyright (c) Tetsuo Handa <penguin-kernel (at) I-love.SAKURA.ne.jp>, 2009      */
      4 /*                                                                            */
      5 /* This program is free software;  you can redistribute it and/or modify      */
      6 /* it under the terms of the GNU General Public License as published by       */
      7 /* the Free Software Foundation; either version 2 of the License, or          */
      8 /* (at your option) any later version.                                        */
      9 /*                                                                            */
     10 /* This program is distributed in the hope that it will be useful,            */
     11 /* but WITHOUT ANY WARRANTY;  without even the implied warranty of            */
     12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See                  */
     13 /* the GNU General Public License for more details.                           */
     14 /*                                                                            */
     15 /* You should have received a copy of the GNU General Public License          */
     16 /* along with this program;  if not, write to the Free Software               */
     17 /* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA    */
     18 /*                                                                            */
     19 /******************************************************************************/
     20 /*
     21  * include.h
     22  *
     23  * Common functions for testing TOMOYO Linux's kernel.
     24  *
     25  * Copyright (C) 2005-2010  NTT DATA CORPORATION
     26  */
     27 #include <errno.h>
     28 #include <fcntl.h>
     29 #include <linux/kdev_t.h>
     30 #include <linux/unistd.h>
     31 #include <pty.h>
     32 #include <stdio.h>
     33 #include <stdlib.h>
     34 #include <string.h>
     35 #include <sys/socket.h>
     36 #include <sys/stat.h>
     37 #include <sys/syscall.h>
     38 #include <sys/time.h>
     39 #include <sys/timex.h>
     40 #include <sys/types.h>
     41 #include <sys/un.h>
     42 #include <sys/wait.h>
     43 #include <time.h>
     44 #include <unistd.h>
     45 #include <utime.h>
     46 #include <sched.h>
     47 #include <stdarg.h>
     48 #include <sys/mount.h>
     49 #include <arpa/inet.h>
     50 #include <net/if.h>
     51 #include <linux/ip.h>
     52 #include <err.h>
     53 #include "test.h"
     54 
     55 /*
     56  * Some architectures like mips n32 don't have __NR_uselib defined in the
     57  * system headers.
     58  */
     59 #ifdef __NR_uselib
     60 static inline int uselib(const char *library)
     61 {
     62 	return syscall(__NR_uselib, library);
     63 }
     64 #else
     65 static inline int uselib(const char *library)
     66 {
     67 	errno = ENOSYS;
     68 	return -1;
     69 }
     70 #endif
     71 
     72 /* Is there an architecture without __NR_pivot_root defined? */
     73 #ifdef __NR_pivot_root
     74 static inline int pivot_root(const char *new_root, const char *put_old)
     75 {
     76 	return syscall(__NR_pivot_root, new_root, put_old);
     77 }
     78 #else
     79 static inline int pivot_root(const char *new_root, const char *put_old)
     80 {
     81 	errno = ENOSYS;
     82 	return -1;
     83 }
     84 #endif
     85 
     86 /* The sysctl() wrapper is dead and newer arches omit it now. */
     87 static inline int write_sysctl(const char *path, const char *value)
     88 {
     89 	FILE *fp = fopen(path, "w");
     90 	if (!fp)
     91 		return 1;
     92 	fputs(value, fp);
     93 	fclose(fp);
     94 	return 0;
     95 }
     96 
     97 static inline int read_sysctl(const char *path, char *value, int len)
     98 {
     99 	char scratch[100];
    100 	FILE *fp = fopen(path, "r");
    101 	if (!fp)
    102 		return 1;
    103 	if (!value) {
    104 		value = scratch;
    105 		len = sizeof(scratch);
    106 	}
    107 	if (fgets(value, len, fp))
    108 		/* ignore */;
    109 	fclose(fp);
    110 	return 0;
    111 }
    112 
    113 /* Should be a fairly benign path to bang on. */
    114 #define TEST_SYSCTL_PATH "/proc/sys/net/ipv4/ip_local_port_range"
    115 
    116 #define proc_policy_dir              "/sys/kernel/security/tomoyo/"
    117 #define proc_policy_domain_policy    "/sys/kernel/security/tomoyo/domain_policy"
    118 #define proc_policy_exception_policy "/sys/kernel/security/tomoyo/exception_policy"
    119 #define proc_policy_profile          "/sys/kernel/security/tomoyo/profile"
    120 #define proc_policy_manager          "/sys/kernel/security/tomoyo/manager"
    121 #define proc_policy_query            "/sys/kernel/security/tomoyo/query"
    122 #define proc_policy_grant_log        "/sys/kernel/security/tomoyo/grant_log"
    123 #define proc_policy_reject_log       "/sys/kernel/security/tomoyo/reject_log"
    124 #define proc_policy_domain_status    "/sys/kernel/security/tomoyo/.domain_status"
    125 #define proc_policy_process_status   "/sys/kernel/security/tomoyo/.process_status"
    126 #define proc_policy_self_domain      "/sys/kernel/security/tomoyo/self_domain"
    127 
    128 static FILE *profile_fp = NULL;
    129 static FILE *domain_fp = NULL;
    130 static FILE *exception_fp = NULL;
    131 static char self_domain[4096] = "";
    132 static pid_t pid = 0;
    133 
    134 static void clear_status(void)
    135 {
    136 	static const char *keywords[] = {
    137 		"file::execute",
    138 		"file::open",
    139 		"file::create",
    140 		"file::unlink",
    141 		"file::mkdir",
    142 		"file::rmdir",
    143 		"file::mkfifo",
    144 		"file::mksock",
    145 		"file::truncate",
    146 		"file::symlink",
    147 		"file::rewrite",
    148 		"file::mkblock",
    149 		"file::mkchar",
    150 		"file::link",
    151 		"file::rename",
    152 		"file::chmod",
    153 		"file::chown",
    154 		"file::chgrp",
    155 		"file::ioctl",
    156 		"file::chroot",
    157 		"file::mount",
    158 		"file::umount",
    159 		"file::pivot_root",
    160 		NULL
    161 	};
    162 	int i;
    163 	FILE *fp = fopen(proc_policy_profile, "r");
    164 	static char buffer[4096];
    165 	if (!fp) {
    166 		fprintf(stderr, "Can't open %s\n", proc_policy_profile);
    167 		exit(1);
    168 	}
    169 	for (i = 0; keywords[i]; i++)
    170 		fprintf(profile_fp,
    171 			"255-CONFIG::%s={ mode=disabled }\n",
    172 			keywords[i]);
    173 	while (memset(buffer, 0, sizeof(buffer)),
    174 	       fgets(buffer, sizeof(buffer) - 10, fp)) {
    175 		const char *mode;
    176 		char *cp = strchr(buffer, '=');
    177 		if (!cp)
    178 			continue;
    179 		*cp = '\0';
    180 		mode = cp + 1;
    181 		cp = strchr(buffer, '-');
    182 		if (!cp)
    183 			continue;
    184 		*cp++ = '\0';
    185 		if (strcmp(buffer, "0"))
    186 			continue;
    187 		fprintf(profile_fp, "255-%s", cp);
    188 		if (!strcmp(cp, "COMMENT"))
    189 			mode = "Profile for kernel test\n";
    190 		else
    191 			mode = "{ mode=disabled verbose=no }\n";
    192 		fprintf(profile_fp, "255-%s=%s", cp, mode);
    193 	}
    194 	fprintf(profile_fp, "255-PREFERENCE::learning= verbose=no\n");
    195 	fprintf(profile_fp, "255-PREFERENCE::enforcing= verbose=no\n");
    196 	fprintf(profile_fp, "255-PREFERENCE::permissive= verbose=no\n");
    197 	fprintf(profile_fp, "255-PREFERENCE::disabled= verbose=no\n");
    198 	fprintf(profile_fp, "255-PREFERENCE::learning= max_entry=2048\n");
    199 	fflush(profile_fp);
    200 	fclose(fp);
    201 }
    202 
    203 static void tomoyo_test_init(void)
    204 {
    205 	pid = getpid();
    206 	if (access(proc_policy_dir, F_OK)) {
    207 		fprintf(stderr, "You can't use this program for this kernel."
    208 			"\n");
    209 		exit(1);
    210 	}
    211 	profile_fp = fopen(proc_policy_profile, "w");
    212 	if (!profile_fp) {
    213 		fprintf(stderr, "Can't open %s .\n", proc_policy_profile);
    214 		exit(1);
    215 	}
    216 	setlinebuf(profile_fp);
    217 	domain_fp = fopen(proc_policy_domain_policy, "w");
    218 	if (!domain_fp) {
    219 		fprintf(stderr, "Can't open %s .\n",
    220 			proc_policy_domain_policy);
    221 		exit(1);
    222 	}
    223 	setlinebuf(domain_fp);
    224 	exception_fp = fopen(proc_policy_exception_policy, "w");
    225 	if (!exception_fp) {
    226 		fprintf(stderr, "Can't open %s .\n",
    227 			proc_policy_exception_policy);
    228 		exit(1);
    229 	}
    230 	setlinebuf(exception_fp);
    231 	if (fputc('\n', profile_fp) != '\n' || fflush(profile_fp)) {
    232 		fprintf(stderr, "You need to register this program to %s to "
    233 			"run this program.\n", proc_policy_manager);
    234 		exit(1);
    235 	}
    236 	clear_status();
    237 	{
    238 		FILE *fp = fopen(proc_policy_self_domain, "r");
    239 		memset(self_domain, 0, sizeof(self_domain));
    240 		if (!fp || !fgets(self_domain, sizeof(self_domain) - 1, fp) ||
    241 		    fclose(fp)) {
    242 			fprintf(stderr, "Can't open %s .\n",
    243 				proc_policy_self_domain);
    244 			exit(1);
    245 		}
    246 	}
    247 	fprintf(domain_fp, "select pid=%u\n", pid);
    248 	fprintf(domain_fp, "use_profile 255\n");
    249 	fprintf(domain_fp, "allow_read/write /sys/kernel/security/tomoyo/domain_policy\n");
    250 	fprintf(domain_fp, "allow_truncate /sys/kernel/security/tomoyo/domain_policy\n");
    251 	fprintf(domain_fp, "allow_read/write /sys/kernel/security/tomoyo/exception_policy\n");
    252 	fprintf(domain_fp, "allow_truncate /sys/kernel/security/tomoyo/exception_policy\n");
    253 	fprintf(domain_fp, "allow_read/write /sys/kernel/security/tomoyo/profile\n");
    254 	fprintf(domain_fp, "allow_truncate /sys/kernel/security/tomoyo/profile\n");
    255 }
    256 
    257 static void BUG(const char *fmt, ...)
    258 	__attribute__ ((format(printf, 1, 2)));
    259 
    260 static void BUG(const char *fmt, ...)
    261 {
    262 	va_list args;
    263 	printf("BUG: ");
    264 	va_start(args, fmt);
    265 	vprintf(fmt, args);
    266 	va_end(args);
    267 	putchar('\n');
    268 	fflush(stdout);
    269 	while (1)
    270 		sleep(100);
    271 }
    272 
    273 int write_domain_policy(const char *policy, int is_delete)
    274 {
    275 	FILE *fp = fopen(proc_policy_domain_policy, "r");
    276 	char buffer[8192];
    277 	int domain_found = 0;
    278 	int policy_found = 0;
    279 	memset(buffer, 0, sizeof(buffer));
    280 	if (!fp) {
    281 		BUG("Can't read %s", proc_policy_domain_policy);
    282 		return 0;
    283 	}
    284 	if (is_delete)
    285 		fprintf(domain_fp, "delete ");
    286 	fprintf(domain_fp, "%s\n", policy);
    287 	while (fgets(buffer, sizeof(buffer) - 1, fp)) {
    288 		char *cp = strchr(buffer, '\n');
    289 		if (cp)
    290 			*cp = '\0';
    291 		if (!strncmp(buffer, "<kernel>", 8))
    292 			domain_found = !strcmp(self_domain, buffer);
    293 		if (!domain_found)
    294 			continue;
    295 		/* printf("<%s>\n", buffer); */
    296 		if (strcmp(buffer, policy))
    297 			continue;
    298 		policy_found = 1;
    299 		break;
    300 	}
    301 	fclose(fp);
    302 	if (policy_found == is_delete) {
    303 		BUG("Can't %s %s", is_delete ? "delete" : "append",
    304 		    policy);
    305 		return 0;
    306 	}
    307 	errno = 0;
    308 	return 1;
    309 
    310 }
    311 
    312 int write_exception_policy(const char *policy, int is_delete)
    313 {
    314 	FILE *fp = fopen(proc_policy_exception_policy, "r");
    315 	char buffer[8192];
    316 	int policy_found = 0;
    317 	memset(buffer, 0, sizeof(buffer));
    318 	if (!fp) {
    319 		BUG("Can't read %s", proc_policy_exception_policy);
    320 		return 0;
    321 	}
    322 	if (is_delete)
    323 		fprintf(exception_fp, "delete ");
    324 	fprintf(exception_fp, "%s\n", policy);
    325 	while (fgets(buffer, sizeof(buffer) - 1, fp)) {
    326 		char *cp = strchr(buffer, '\n');
    327 		if (cp)
    328 			*cp = '\0';
    329 		if (strcmp(buffer, policy))
    330 			continue;
    331 		policy_found = 1;
    332 		break;
    333 	}
    334 	fclose(fp);
    335 	if (policy_found == is_delete) {
    336 		BUG("Can't %s %s", is_delete ? "delete" : "append",
    337 		    policy);
    338 		return 0;
    339 	}
    340 	errno = 0;
    341 	return 1;
    342 
    343 }
    344 
    345 int set_profile(const int mode, const char *name)
    346 {
    347 	static const char *modes[4] = { "disabled", "learning", "permissive",
    348 					"enforcing" };
    349 	FILE *fp = fopen(proc_policy_profile, "r");
    350 	char buffer[8192];
    351 	int policy_found = 0;
    352 	const int len = strlen(name);
    353 	if (!fp) {
    354 		BUG("Can't read %s", proc_policy_profile);
    355 		return 0;
    356 	}
    357 	fprintf(profile_fp, "255-CONFIG::%s=%s\n", name, modes[mode]);
    358 	while (memset(buffer, 0, sizeof(buffer)),
    359 	       fgets(buffer, sizeof(buffer) - 1, fp)) {
    360 		char *cp = strchr(buffer, '\n');
    361 		if (cp)
    362 			*cp = '\0';
    363 		if (strncmp(buffer, "255-CONFIG::", 12) ||
    364 		    strncmp(buffer + 12, name, len) ||
    365 		    buffer[12 + len] != '=')
    366 			continue;
    367 		if (strstr(buffer + 13 + len, modes[mode]))
    368 			policy_found = 1;
    369 		break;
    370 	}
    371 	fclose(fp);
    372 	if (!policy_found) {
    373 		BUG("Can't change profile to 255-CONFIG::%s=%s",
    374 		    name, modes[mode]);
    375 		return 0;
    376 	}
    377 	errno = 0;
    378 	return 1;
    379 }
    380