/******************************************************************************/ /* */ /* Copyright (c) Tetsuo Handa , 2009 */ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */ /* the GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* */ /******************************************************************************/ /* * include.h * * Common functions for testing TOMOYO Linux's kernel. * * Copyright (C) 2005-2010 NTT DATA CORPORATION */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "test.h" /* * Some architectures like mips n32 don't have __NR_uselib defined in the * system headers. */ #ifdef __NR_uselib static inline int uselib(const char *library) { return syscall(__NR_uselib, library); } #else static inline int uselib(const char *library) { errno = ENOSYS; return -1; } #endif /* Is there an architecture without __NR_pivot_root defined? */ #ifdef __NR_pivot_root static inline int pivot_root(const char *new_root, const char *put_old) { return syscall(__NR_pivot_root, new_root, put_old); } #else static inline int pivot_root(const char *new_root, const char *put_old) { errno = ENOSYS; return -1; } #endif /* The sysctl() wrapper is dead and newer arches omit it now. */ static inline int write_sysctl(const char *path, const char *value) { FILE *fp = fopen(path, "w"); if (!fp) return 1; fputs(value, fp); fclose(fp); return 0; } static inline int read_sysctl(const char *path, char *value, int len) { char scratch[100]; FILE *fp = fopen(path, "r"); if (!fp) return 1; if (!value) { value = scratch; len = sizeof(scratch); } if (fgets(value, len, fp)) /* ignore */; fclose(fp); return 0; } /* Should be a fairly benign path to bang on. */ #define TEST_SYSCTL_PATH "/proc/sys/net/ipv4/ip_local_port_range" #define proc_policy_dir "/sys/kernel/security/tomoyo/" #define proc_policy_domain_policy "/sys/kernel/security/tomoyo/domain_policy" #define proc_policy_exception_policy "/sys/kernel/security/tomoyo/exception_policy" #define proc_policy_profile "/sys/kernel/security/tomoyo/profile" #define proc_policy_manager "/sys/kernel/security/tomoyo/manager" #define proc_policy_query "/sys/kernel/security/tomoyo/query" #define proc_policy_grant_log "/sys/kernel/security/tomoyo/grant_log" #define proc_policy_reject_log "/sys/kernel/security/tomoyo/reject_log" #define proc_policy_domain_status "/sys/kernel/security/tomoyo/.domain_status" #define proc_policy_process_status "/sys/kernel/security/tomoyo/.process_status" #define proc_policy_self_domain "/sys/kernel/security/tomoyo/self_domain" static FILE *profile_fp = NULL; static FILE *domain_fp = NULL; static FILE *exception_fp = NULL; static char self_domain[4096] = ""; static pid_t pid = 0; static void clear_status(void) { static const char *keywords[] = { "file::execute", "file::open", "file::create", "file::unlink", "file::mkdir", "file::rmdir", "file::mkfifo", "file::mksock", "file::truncate", "file::symlink", "file::rewrite", "file::mkblock", "file::mkchar", "file::link", "file::rename", "file::chmod", "file::chown", "file::chgrp", "file::ioctl", "file::chroot", "file::mount", "file::umount", "file::pivot_root", NULL }; int i; FILE *fp = fopen(proc_policy_profile, "r"); static char buffer[4096]; if (!fp) { fprintf(stderr, "Can't open %s\n", proc_policy_profile); exit(1); } for (i = 0; keywords[i]; i++) fprintf(profile_fp, "255-CONFIG::%s={ mode=disabled }\n", keywords[i]); while (memset(buffer, 0, sizeof(buffer)), fgets(buffer, sizeof(buffer) - 10, fp)) { const char *mode; char *cp = strchr(buffer, '='); if (!cp) continue; *cp = '\0'; mode = cp + 1; cp = strchr(buffer, '-'); if (!cp) continue; *cp++ = '\0'; if (strcmp(buffer, "0")) continue; fprintf(profile_fp, "255-%s", cp); if (!strcmp(cp, "COMMENT")) mode = "Profile for kernel test\n"; else mode = "{ mode=disabled verbose=no }\n"; fprintf(profile_fp, "255-%s=%s", cp, mode); } fprintf(profile_fp, "255-PREFERENCE::learning= verbose=no\n"); fprintf(profile_fp, "255-PREFERENCE::enforcing= verbose=no\n"); fprintf(profile_fp, "255-PREFERENCE::permissive= verbose=no\n"); fprintf(profile_fp, "255-PREFERENCE::disabled= verbose=no\n"); fprintf(profile_fp, "255-PREFERENCE::learning= max_entry=2048\n"); fflush(profile_fp); fclose(fp); } static void tomoyo_test_init(void) { pid = getpid(); if (access(proc_policy_dir, F_OK)) { fprintf(stderr, "You can't use this program for this kernel." "\n"); exit(1); } profile_fp = fopen(proc_policy_profile, "w"); if (!profile_fp) { fprintf(stderr, "Can't open %s .\n", proc_policy_profile); exit(1); } setlinebuf(profile_fp); domain_fp = fopen(proc_policy_domain_policy, "w"); if (!domain_fp) { fprintf(stderr, "Can't open %s .\n", proc_policy_domain_policy); exit(1); } setlinebuf(domain_fp); exception_fp = fopen(proc_policy_exception_policy, "w"); if (!exception_fp) { fprintf(stderr, "Can't open %s .\n", proc_policy_exception_policy); exit(1); } setlinebuf(exception_fp); if (fputc('\n', profile_fp) != '\n' || fflush(profile_fp)) { fprintf(stderr, "You need to register this program to %s to " "run this program.\n", proc_policy_manager); exit(1); } clear_status(); { FILE *fp = fopen(proc_policy_self_domain, "r"); memset(self_domain, 0, sizeof(self_domain)); if (!fp || !fgets(self_domain, sizeof(self_domain) - 1, fp) || fclose(fp)) { fprintf(stderr, "Can't open %s .\n", proc_policy_self_domain); exit(1); } } fprintf(domain_fp, "select pid=%u\n", pid); fprintf(domain_fp, "use_profile 255\n"); fprintf(domain_fp, "allow_read/write /sys/kernel/security/tomoyo/domain_policy\n"); fprintf(domain_fp, "allow_truncate /sys/kernel/security/tomoyo/domain_policy\n"); fprintf(domain_fp, "allow_read/write /sys/kernel/security/tomoyo/exception_policy\n"); fprintf(domain_fp, "allow_truncate /sys/kernel/security/tomoyo/exception_policy\n"); fprintf(domain_fp, "allow_read/write /sys/kernel/security/tomoyo/profile\n"); fprintf(domain_fp, "allow_truncate /sys/kernel/security/tomoyo/profile\n"); } static void BUG(const char *fmt, ...) __attribute__ ((format(printf, 1, 2))); static void BUG(const char *fmt, ...) { va_list args; printf("BUG: "); va_start(args, fmt); vprintf(fmt, args); va_end(args); putchar('\n'); fflush(stdout); while (1) sleep(100); } int write_domain_policy(const char *policy, int is_delete) { FILE *fp = fopen(proc_policy_domain_policy, "r"); char buffer[8192]; int domain_found = 0; int policy_found = 0; memset(buffer, 0, sizeof(buffer)); if (!fp) { BUG("Can't read %s", proc_policy_domain_policy); return 0; } if (is_delete) fprintf(domain_fp, "delete "); fprintf(domain_fp, "%s\n", policy); while (fgets(buffer, sizeof(buffer) - 1, fp)) { char *cp = strchr(buffer, '\n'); if (cp) *cp = '\0'; if (!strncmp(buffer, "", 8)) domain_found = !strcmp(self_domain, buffer); if (!domain_found) continue; /* printf("<%s>\n", buffer); */ if (strcmp(buffer, policy)) continue; policy_found = 1; break; } fclose(fp); if (policy_found == is_delete) { BUG("Can't %s %s", is_delete ? "delete" : "append", policy); return 0; } errno = 0; return 1; } int write_exception_policy(const char *policy, int is_delete) { FILE *fp = fopen(proc_policy_exception_policy, "r"); char buffer[8192]; int policy_found = 0; memset(buffer, 0, sizeof(buffer)); if (!fp) { BUG("Can't read %s", proc_policy_exception_policy); return 0; } if (is_delete) fprintf(exception_fp, "delete "); fprintf(exception_fp, "%s\n", policy); while (fgets(buffer, sizeof(buffer) - 1, fp)) { char *cp = strchr(buffer, '\n'); if (cp) *cp = '\0'; if (strcmp(buffer, policy)) continue; policy_found = 1; break; } fclose(fp); if (policy_found == is_delete) { BUG("Can't %s %s", is_delete ? "delete" : "append", policy); return 0; } errno = 0; return 1; } int set_profile(const int mode, const char *name) { static const char *modes[4] = { "disabled", "learning", "permissive", "enforcing" }; FILE *fp = fopen(proc_policy_profile, "r"); char buffer[8192]; int policy_found = 0; const int len = strlen(name); if (!fp) { BUG("Can't read %s", proc_policy_profile); return 0; } fprintf(profile_fp, "255-CONFIG::%s=%s\n", name, modes[mode]); while (memset(buffer, 0, sizeof(buffer)), fgets(buffer, sizeof(buffer) - 1, fp)) { char *cp = strchr(buffer, '\n'); if (cp) *cp = '\0'; if (strncmp(buffer, "255-CONFIG::", 12) || strncmp(buffer + 12, name, len) || buffer[12 + len] != '=') continue; if (strstr(buffer + 13 + len, modes[mode])) policy_found = 1; break; } fclose(fp); if (!policy_found) { BUG("Can't change profile to 255-CONFIG::%s=%s", name, modes[mode]); return 0; } errno = 0; return 1; }