19590837bSKentaro Takeda /* 29590837bSKentaro Takeda * security/tomoyo/common.c 39590837bSKentaro Takeda * 49590837bSKentaro Takeda * Common functions for TOMOYO. 59590837bSKentaro Takeda * 6c3ef1500STetsuo Handa * Copyright (C) 2005-2010 NTT DATA CORPORATION 79590837bSKentaro Takeda */ 89590837bSKentaro Takeda 99590837bSKentaro Takeda #include <linux/uaccess.h> 105a0e3ad6STejun Heo #include <linux/slab.h> 119590837bSKentaro Takeda #include <linux/security.h> 129590837bSKentaro Takeda #include "common.h" 139590837bSKentaro Takeda 1457c2590fSTetsuo Handa static struct tomoyo_profile tomoyo_default_profile = { 1557c2590fSTetsuo Handa .learning = &tomoyo_default_profile.preference, 1657c2590fSTetsuo Handa .permissive = &tomoyo_default_profile.preference, 1757c2590fSTetsuo Handa .enforcing = &tomoyo_default_profile.preference, 1857c2590fSTetsuo Handa .preference.enforcing_verbose = true, 1957c2590fSTetsuo Handa .preference.learning_max_entry = 2048, 2057c2590fSTetsuo Handa .preference.learning_verbose = false, 2157c2590fSTetsuo Handa .preference.permissive_verbose = true 2257c2590fSTetsuo Handa }; 2357c2590fSTetsuo Handa 2457c2590fSTetsuo Handa /* Profile version. Currently only 20090903 is defined. */ 2557c2590fSTetsuo Handa static unsigned int tomoyo_profile_version; 2657c2590fSTetsuo Handa 2757c2590fSTetsuo Handa /* Profile table. Memory is allocated as needed. */ 2857c2590fSTetsuo Handa static struct tomoyo_profile *tomoyo_profile_ptr[TOMOYO_MAX_PROFILES]; 2957c2590fSTetsuo Handa 309590837bSKentaro Takeda /* String table for functionality that takes 4 modes. */ 319590837bSKentaro Takeda static const char *tomoyo_mode_4[4] = { 329590837bSKentaro Takeda "disabled", "learning", "permissive", "enforcing" 339590837bSKentaro Takeda }; 349590837bSKentaro Takeda 3557c2590fSTetsuo Handa /* String table for /sys/kernel/security/tomoyo/profile */ 3657c2590fSTetsuo Handa static const char *tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX 3757c2590fSTetsuo Handa + TOMOYO_MAX_MAC_CATEGORY_INDEX] = { 3857c2590fSTetsuo Handa [TOMOYO_MAC_FILE_EXECUTE] = "file::execute", 3957c2590fSTetsuo Handa [TOMOYO_MAC_FILE_OPEN] = "file::open", 4057c2590fSTetsuo Handa [TOMOYO_MAC_FILE_CREATE] = "file::create", 4157c2590fSTetsuo Handa [TOMOYO_MAC_FILE_UNLINK] = "file::unlink", 4257c2590fSTetsuo Handa [TOMOYO_MAC_FILE_MKDIR] = "file::mkdir", 4357c2590fSTetsuo Handa [TOMOYO_MAC_FILE_RMDIR] = "file::rmdir", 4457c2590fSTetsuo Handa [TOMOYO_MAC_FILE_MKFIFO] = "file::mkfifo", 4557c2590fSTetsuo Handa [TOMOYO_MAC_FILE_MKSOCK] = "file::mksock", 4657c2590fSTetsuo Handa [TOMOYO_MAC_FILE_TRUNCATE] = "file::truncate", 4757c2590fSTetsuo Handa [TOMOYO_MAC_FILE_SYMLINK] = "file::symlink", 4857c2590fSTetsuo Handa [TOMOYO_MAC_FILE_REWRITE] = "file::rewrite", 4957c2590fSTetsuo Handa [TOMOYO_MAC_FILE_MKBLOCK] = "file::mkblock", 5057c2590fSTetsuo Handa [TOMOYO_MAC_FILE_MKCHAR] = "file::mkchar", 5157c2590fSTetsuo Handa [TOMOYO_MAC_FILE_LINK] = "file::link", 5257c2590fSTetsuo Handa [TOMOYO_MAC_FILE_RENAME] = "file::rename", 5357c2590fSTetsuo Handa [TOMOYO_MAC_FILE_CHMOD] = "file::chmod", 5457c2590fSTetsuo Handa [TOMOYO_MAC_FILE_CHOWN] = "file::chown", 5557c2590fSTetsuo Handa [TOMOYO_MAC_FILE_CHGRP] = "file::chgrp", 5657c2590fSTetsuo Handa [TOMOYO_MAC_FILE_IOCTL] = "file::ioctl", 5757c2590fSTetsuo Handa [TOMOYO_MAC_FILE_CHROOT] = "file::chroot", 5857c2590fSTetsuo Handa [TOMOYO_MAC_FILE_MOUNT] = "file::mount", 5957c2590fSTetsuo Handa [TOMOYO_MAC_FILE_UMOUNT] = "file::umount", 6057c2590fSTetsuo Handa [TOMOYO_MAC_FILE_PIVOT_ROOT] = "file::pivot_root", 6157c2590fSTetsuo Handa [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file", 629590837bSKentaro Takeda }; 639590837bSKentaro Takeda 649590837bSKentaro Takeda /* Permit policy management by non-root user? */ 659590837bSKentaro Takeda static bool tomoyo_manage_by_non_root; 669590837bSKentaro Takeda 679590837bSKentaro Takeda /* Utility functions. */ 689590837bSKentaro Takeda 697762fbffSTetsuo Handa /** 7057c2590fSTetsuo Handa * tomoyo_yesno - Return "yes" or "no". 7157c2590fSTetsuo Handa * 7257c2590fSTetsuo Handa * @value: Bool value. 7357c2590fSTetsuo Handa */ 7457c2590fSTetsuo Handa static const char *tomoyo_yesno(const unsigned int value) 7557c2590fSTetsuo Handa { 7657c2590fSTetsuo Handa return value ? "yes" : "no"; 7757c2590fSTetsuo Handa } 7857c2590fSTetsuo Handa 7957c2590fSTetsuo Handa /** 807762fbffSTetsuo Handa * tomoyo_print_name_union - Print a tomoyo_name_union. 817762fbffSTetsuo Handa * 827762fbffSTetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 837762fbffSTetsuo Handa * @ptr: Pointer to "struct tomoyo_name_union". 847762fbffSTetsuo Handa * 857762fbffSTetsuo Handa * Returns true on success, false otherwise. 867762fbffSTetsuo Handa */ 877762fbffSTetsuo Handa static bool tomoyo_print_name_union(struct tomoyo_io_buffer *head, 887762fbffSTetsuo Handa const struct tomoyo_name_union *ptr) 897762fbffSTetsuo Handa { 907762fbffSTetsuo Handa int pos = head->read_avail; 917762fbffSTetsuo Handa if (pos && head->read_buf[pos - 1] == ' ') 927762fbffSTetsuo Handa head->read_avail--; 937762fbffSTetsuo Handa if (ptr->is_group) 947762fbffSTetsuo Handa return tomoyo_io_printf(head, " @%s", 957762fbffSTetsuo Handa ptr->group->group_name->name); 967762fbffSTetsuo Handa return tomoyo_io_printf(head, " %s", ptr->filename->name); 977762fbffSTetsuo Handa } 987762fbffSTetsuo Handa 997762fbffSTetsuo Handa /** 1004c3e9e2dSTetsuo Handa * tomoyo_print_number_union - Print a tomoyo_number_union. 1014c3e9e2dSTetsuo Handa * 1024c3e9e2dSTetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 1034c3e9e2dSTetsuo Handa * @ptr: Pointer to "struct tomoyo_number_union". 1044c3e9e2dSTetsuo Handa * 1054c3e9e2dSTetsuo Handa * Returns true on success, false otherwise. 1064c3e9e2dSTetsuo Handa */ 1074c3e9e2dSTetsuo Handa bool tomoyo_print_number_union(struct tomoyo_io_buffer *head, 1084c3e9e2dSTetsuo Handa const struct tomoyo_number_union *ptr) 1094c3e9e2dSTetsuo Handa { 1104c3e9e2dSTetsuo Handa unsigned long min; 1114c3e9e2dSTetsuo Handa unsigned long max; 1124c3e9e2dSTetsuo Handa u8 min_type; 1134c3e9e2dSTetsuo Handa u8 max_type; 1144c3e9e2dSTetsuo Handa if (!tomoyo_io_printf(head, " ")) 1154c3e9e2dSTetsuo Handa return false; 1164c3e9e2dSTetsuo Handa if (ptr->is_group) 1174c3e9e2dSTetsuo Handa return tomoyo_io_printf(head, "@%s", 1184c3e9e2dSTetsuo Handa ptr->group->group_name->name); 1194c3e9e2dSTetsuo Handa min_type = ptr->min_type; 1204c3e9e2dSTetsuo Handa max_type = ptr->max_type; 1214c3e9e2dSTetsuo Handa min = ptr->values[0]; 1224c3e9e2dSTetsuo Handa max = ptr->values[1]; 1234c3e9e2dSTetsuo Handa switch (min_type) { 1244c3e9e2dSTetsuo Handa case TOMOYO_VALUE_TYPE_HEXADECIMAL: 1254c3e9e2dSTetsuo Handa if (!tomoyo_io_printf(head, "0x%lX", min)) 1264c3e9e2dSTetsuo Handa return false; 1274c3e9e2dSTetsuo Handa break; 1284c3e9e2dSTetsuo Handa case TOMOYO_VALUE_TYPE_OCTAL: 1294c3e9e2dSTetsuo Handa if (!tomoyo_io_printf(head, "0%lo", min)) 1304c3e9e2dSTetsuo Handa return false; 1314c3e9e2dSTetsuo Handa break; 1324c3e9e2dSTetsuo Handa default: 1334c3e9e2dSTetsuo Handa if (!tomoyo_io_printf(head, "%lu", min)) 1344c3e9e2dSTetsuo Handa return false; 1354c3e9e2dSTetsuo Handa break; 1364c3e9e2dSTetsuo Handa } 1374c3e9e2dSTetsuo Handa if (min == max && min_type == max_type) 1384c3e9e2dSTetsuo Handa return true; 1394c3e9e2dSTetsuo Handa switch (max_type) { 1404c3e9e2dSTetsuo Handa case TOMOYO_VALUE_TYPE_HEXADECIMAL: 1414c3e9e2dSTetsuo Handa return tomoyo_io_printf(head, "-0x%lX", max); 1424c3e9e2dSTetsuo Handa case TOMOYO_VALUE_TYPE_OCTAL: 1434c3e9e2dSTetsuo Handa return tomoyo_io_printf(head, "-0%lo", max); 1444c3e9e2dSTetsuo Handa default: 1454c3e9e2dSTetsuo Handa return tomoyo_io_printf(head, "-%lu", max); 1464c3e9e2dSTetsuo Handa } 1474c3e9e2dSTetsuo Handa } 1484c3e9e2dSTetsuo Handa 1494c3e9e2dSTetsuo Handa /** 1509590837bSKentaro Takeda * tomoyo_io_printf - Transactional printf() to "struct tomoyo_io_buffer" structure. 1519590837bSKentaro Takeda * 1529590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 1539590837bSKentaro Takeda * @fmt: The printf()'s format string, followed by parameters. 1549590837bSKentaro Takeda * 1559590837bSKentaro Takeda * Returns true if output was written, false otherwise. 1569590837bSKentaro Takeda * 1579590837bSKentaro Takeda * The snprintf() will truncate, but tomoyo_io_printf() won't. 1589590837bSKentaro Takeda */ 1599590837bSKentaro Takeda bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) 1609590837bSKentaro Takeda { 1619590837bSKentaro Takeda va_list args; 1629590837bSKentaro Takeda int len; 1639590837bSKentaro Takeda int pos = head->read_avail; 1649590837bSKentaro Takeda int size = head->readbuf_size - pos; 1659590837bSKentaro Takeda 1669590837bSKentaro Takeda if (size <= 0) 1679590837bSKentaro Takeda return false; 1689590837bSKentaro Takeda va_start(args, fmt); 1699590837bSKentaro Takeda len = vsnprintf(head->read_buf + pos, size, fmt, args); 1709590837bSKentaro Takeda va_end(args); 1719590837bSKentaro Takeda if (pos + len >= head->readbuf_size) 1729590837bSKentaro Takeda return false; 1739590837bSKentaro Takeda head->read_avail += len; 1749590837bSKentaro Takeda return true; 1759590837bSKentaro Takeda } 1769590837bSKentaro Takeda 1779590837bSKentaro Takeda /** 1789590837bSKentaro Takeda * tomoyo_find_or_assign_new_profile - Create a new profile. 1799590837bSKentaro Takeda * 1809590837bSKentaro Takeda * @profile: Profile number to create. 1819590837bSKentaro Takeda * 1829590837bSKentaro Takeda * Returns pointer to "struct tomoyo_profile" on success, NULL otherwise. 1839590837bSKentaro Takeda */ 18457c2590fSTetsuo Handa static struct tomoyo_profile *tomoyo_find_or_assign_new_profile 18557c2590fSTetsuo Handa (const unsigned int profile) 1869590837bSKentaro Takeda { 18757c2590fSTetsuo Handa struct tomoyo_profile *ptr; 18857c2590fSTetsuo Handa struct tomoyo_profile *entry; 1899590837bSKentaro Takeda if (profile >= TOMOYO_MAX_PROFILES) 1909590837bSKentaro Takeda return NULL; 1919590837bSKentaro Takeda ptr = tomoyo_profile_ptr[profile]; 1929590837bSKentaro Takeda if (ptr) 19357c2590fSTetsuo Handa return ptr; 19457c2590fSTetsuo Handa entry = kzalloc(sizeof(*entry), GFP_NOFS); 19557c2590fSTetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 19657c2590fSTetsuo Handa goto out; 19757c2590fSTetsuo Handa ptr = tomoyo_profile_ptr[profile]; 19857c2590fSTetsuo Handa if (!ptr && tomoyo_memory_ok(entry)) { 19957c2590fSTetsuo Handa ptr = entry; 20057c2590fSTetsuo Handa ptr->learning = &tomoyo_default_profile.preference; 20157c2590fSTetsuo Handa ptr->permissive = &tomoyo_default_profile.preference; 20257c2590fSTetsuo Handa ptr->enforcing = &tomoyo_default_profile.preference; 20357c2590fSTetsuo Handa ptr->default_config = TOMOYO_CONFIG_DISABLED; 20457c2590fSTetsuo Handa memset(ptr->config, TOMOYO_CONFIG_USE_DEFAULT, 20557c2590fSTetsuo Handa sizeof(ptr->config)); 2069590837bSKentaro Takeda mb(); /* Avoid out-of-order execution. */ 2079590837bSKentaro Takeda tomoyo_profile_ptr[profile] = ptr; 20857c2590fSTetsuo Handa entry = NULL; 20957c2590fSTetsuo Handa } 21029282381STetsuo Handa mutex_unlock(&tomoyo_policy_lock); 21157c2590fSTetsuo Handa out: 21257c2590fSTetsuo Handa kfree(entry); 2139590837bSKentaro Takeda return ptr; 2149590837bSKentaro Takeda } 2159590837bSKentaro Takeda 2169590837bSKentaro Takeda /** 21757c2590fSTetsuo Handa * tomoyo_profile - Find a profile. 21857c2590fSTetsuo Handa * 21957c2590fSTetsuo Handa * @profile: Profile number to find. 22057c2590fSTetsuo Handa * 22157c2590fSTetsuo Handa * Returns pointer to "struct tomoyo_profile". 22257c2590fSTetsuo Handa */ 22357c2590fSTetsuo Handa struct tomoyo_profile *tomoyo_profile(const u8 profile) 22457c2590fSTetsuo Handa { 22557c2590fSTetsuo Handa struct tomoyo_profile *ptr = tomoyo_profile_ptr[profile]; 22657c2590fSTetsuo Handa if (!tomoyo_policy_loaded) 22757c2590fSTetsuo Handa return &tomoyo_default_profile; 22857c2590fSTetsuo Handa BUG_ON(!ptr); 22957c2590fSTetsuo Handa return ptr; 23057c2590fSTetsuo Handa } 23157c2590fSTetsuo Handa 23257c2590fSTetsuo Handa /** 23357c2590fSTetsuo Handa * tomoyo_write_profile - Write profile table. 2349590837bSKentaro Takeda * 2359590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 2369590837bSKentaro Takeda * 2379590837bSKentaro Takeda * Returns 0 on success, negative value otherwise. 2389590837bSKentaro Takeda */ 2399590837bSKentaro Takeda static int tomoyo_write_profile(struct tomoyo_io_buffer *head) 2409590837bSKentaro Takeda { 2419590837bSKentaro Takeda char *data = head->write_buf; 2429590837bSKentaro Takeda unsigned int i; 24357c2590fSTetsuo Handa int value; 24457c2590fSTetsuo Handa int mode; 24557c2590fSTetsuo Handa u8 config; 24657c2590fSTetsuo Handa bool use_default = false; 2479590837bSKentaro Takeda char *cp; 2489590837bSKentaro Takeda struct tomoyo_profile *profile; 24957c2590fSTetsuo Handa if (sscanf(data, "PROFILE_VERSION=%u", &tomoyo_profile_version) == 1) 25057c2590fSTetsuo Handa return 0; 25157c2590fSTetsuo Handa i = simple_strtoul(data, &cp, 10); 25257c2590fSTetsuo Handa if (data == cp) { 25357c2590fSTetsuo Handa profile = &tomoyo_default_profile; 25457c2590fSTetsuo Handa } else { 25557c2590fSTetsuo Handa if (*cp != '-') 2569590837bSKentaro Takeda return -EINVAL; 2579590837bSKentaro Takeda data = cp + 1; 25857c2590fSTetsuo Handa profile = tomoyo_find_or_assign_new_profile(i); 2599590837bSKentaro Takeda if (!profile) 2609590837bSKentaro Takeda return -EINVAL; 26157c2590fSTetsuo Handa } 2629590837bSKentaro Takeda cp = strchr(data, '='); 2639590837bSKentaro Takeda if (!cp) 2649590837bSKentaro Takeda return -EINVAL; 26557c2590fSTetsuo Handa *cp++ = '\0'; 26657c2590fSTetsuo Handa if (profile != &tomoyo_default_profile) 26757c2590fSTetsuo Handa use_default = strstr(cp, "use_default") != NULL; 26857c2590fSTetsuo Handa if (strstr(cp, "verbose=yes")) 26957c2590fSTetsuo Handa value = 1; 27057c2590fSTetsuo Handa else if (strstr(cp, "verbose=no")) 27157c2590fSTetsuo Handa value = 0; 27257c2590fSTetsuo Handa else 27357c2590fSTetsuo Handa value = -1; 27457c2590fSTetsuo Handa if (!strcmp(data, "PREFERENCE::enforcing")) { 27557c2590fSTetsuo Handa if (use_default) { 27657c2590fSTetsuo Handa profile->enforcing = &tomoyo_default_profile.preference; 27757c2590fSTetsuo Handa return 0; 27857c2590fSTetsuo Handa } 27957c2590fSTetsuo Handa profile->enforcing = &profile->preference; 28057c2590fSTetsuo Handa if (value >= 0) 28157c2590fSTetsuo Handa profile->preference.enforcing_verbose = value; 28257c2590fSTetsuo Handa return 0; 28357c2590fSTetsuo Handa } 28457c2590fSTetsuo Handa if (!strcmp(data, "PREFERENCE::permissive")) { 28557c2590fSTetsuo Handa if (use_default) { 28657c2590fSTetsuo Handa profile->permissive = &tomoyo_default_profile.preference; 28757c2590fSTetsuo Handa return 0; 28857c2590fSTetsuo Handa } 28957c2590fSTetsuo Handa profile->permissive = &profile->preference; 29057c2590fSTetsuo Handa if (value >= 0) 29157c2590fSTetsuo Handa profile->preference.permissive_verbose = value; 29257c2590fSTetsuo Handa return 0; 29357c2590fSTetsuo Handa } 29457c2590fSTetsuo Handa if (!strcmp(data, "PREFERENCE::learning")) { 29557c2590fSTetsuo Handa char *cp2; 29657c2590fSTetsuo Handa if (use_default) { 29757c2590fSTetsuo Handa profile->learning = &tomoyo_default_profile.preference; 29857c2590fSTetsuo Handa return 0; 29957c2590fSTetsuo Handa } 30057c2590fSTetsuo Handa profile->learning = &profile->preference; 30157c2590fSTetsuo Handa if (value >= 0) 30257c2590fSTetsuo Handa profile->preference.learning_verbose = value; 30357c2590fSTetsuo Handa cp2 = strstr(cp, "max_entry="); 30457c2590fSTetsuo Handa if (cp2) 30557c2590fSTetsuo Handa sscanf(cp2 + 10, "%u", 30657c2590fSTetsuo Handa &profile->preference.learning_max_entry); 30757c2590fSTetsuo Handa return 0; 30857c2590fSTetsuo Handa } 30957c2590fSTetsuo Handa if (profile == &tomoyo_default_profile) 31057c2590fSTetsuo Handa return -EINVAL; 3119590837bSKentaro Takeda if (!strcmp(data, "COMMENT")) { 312bf24fb01STetsuo Handa const struct tomoyo_path_info *old_comment = profile->comment; 31357c2590fSTetsuo Handa profile->comment = tomoyo_get_name(cp); 314bf24fb01STetsuo Handa tomoyo_put_name(old_comment); 3159590837bSKentaro Takeda return 0; 3169590837bSKentaro Takeda } 31757c2590fSTetsuo Handa if (!strcmp(data, "CONFIG")) { 31857c2590fSTetsuo Handa i = TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX; 31957c2590fSTetsuo Handa config = profile->default_config; 32057c2590fSTetsuo Handa } else if (tomoyo_str_starts(&data, "CONFIG::")) { 32157c2590fSTetsuo Handa config = 0; 32257c2590fSTetsuo Handa for (i = 0; i < TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX; i++) { 32357c2590fSTetsuo Handa if (strcmp(data, tomoyo_mac_keywords[i])) 3249590837bSKentaro Takeda continue; 32557c2590fSTetsuo Handa config = profile->config[i]; 3269590837bSKentaro Takeda break; 3279590837bSKentaro Takeda } 32857c2590fSTetsuo Handa if (i == TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX) 3299590837bSKentaro Takeda return -EINVAL; 33057c2590fSTetsuo Handa } else { 33157c2590fSTetsuo Handa return -EINVAL; 3329590837bSKentaro Takeda } 33357c2590fSTetsuo Handa if (use_default) { 33457c2590fSTetsuo Handa config = TOMOYO_CONFIG_USE_DEFAULT; 33557c2590fSTetsuo Handa } else { 33657c2590fSTetsuo Handa for (mode = 3; mode >= 0; mode--) 33757c2590fSTetsuo Handa if (strstr(cp, tomoyo_mode_4[mode])) 33857c2590fSTetsuo Handa /* 33957c2590fSTetsuo Handa * Update lower 3 bits in order to distinguish 34057c2590fSTetsuo Handa * 'config' from 'TOMOYO_CONFIG_USE_DEAFULT'. 34157c2590fSTetsuo Handa */ 34257c2590fSTetsuo Handa config = (config & ~7) | mode; 34357c2590fSTetsuo Handa } 34457c2590fSTetsuo Handa if (i < TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX) 34557c2590fSTetsuo Handa profile->config[i] = config; 34657c2590fSTetsuo Handa else if (config != TOMOYO_CONFIG_USE_DEFAULT) 34757c2590fSTetsuo Handa profile->default_config = config; 3489590837bSKentaro Takeda return 0; 3499590837bSKentaro Takeda } 3509590837bSKentaro Takeda 3519590837bSKentaro Takeda /** 35257c2590fSTetsuo Handa * tomoyo_read_profile - Read profile table. 3539590837bSKentaro Takeda * 3549590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 3559590837bSKentaro Takeda */ 3568fbe71f0STetsuo Handa static void tomoyo_read_profile(struct tomoyo_io_buffer *head) 3579590837bSKentaro Takeda { 35857c2590fSTetsuo Handa int index; 3599590837bSKentaro Takeda if (head->read_eof) 3608fbe71f0STetsuo Handa return; 36157c2590fSTetsuo Handa if (head->read_bit) 36257c2590fSTetsuo Handa goto body; 36357c2590fSTetsuo Handa tomoyo_io_printf(head, "PROFILE_VERSION=%s\n", "20090903"); 36457c2590fSTetsuo Handa tomoyo_io_printf(head, "PREFERENCE::learning={ verbose=%s " 36557c2590fSTetsuo Handa "max_entry=%u }\n", 36657c2590fSTetsuo Handa tomoyo_yesno(tomoyo_default_profile.preference. 36757c2590fSTetsuo Handa learning_verbose), 36857c2590fSTetsuo Handa tomoyo_default_profile.preference.learning_max_entry); 36957c2590fSTetsuo Handa tomoyo_io_printf(head, "PREFERENCE::permissive={ verbose=%s }\n", 37057c2590fSTetsuo Handa tomoyo_yesno(tomoyo_default_profile.preference. 37157c2590fSTetsuo Handa permissive_verbose)); 37257c2590fSTetsuo Handa tomoyo_io_printf(head, "PREFERENCE::enforcing={ verbose=%s }\n", 37357c2590fSTetsuo Handa tomoyo_yesno(tomoyo_default_profile.preference. 37457c2590fSTetsuo Handa enforcing_verbose)); 37557c2590fSTetsuo Handa head->read_bit = 1; 37657c2590fSTetsuo Handa body: 37757c2590fSTetsuo Handa for (index = head->read_step; index < TOMOYO_MAX_PROFILES; index++) { 37857c2590fSTetsuo Handa bool done; 37957c2590fSTetsuo Handa u8 config; 38057c2590fSTetsuo Handa int i; 38157c2590fSTetsuo Handa int pos; 3829590837bSKentaro Takeda const struct tomoyo_profile *profile 3839590837bSKentaro Takeda = tomoyo_profile_ptr[index]; 38457c2590fSTetsuo Handa const struct tomoyo_path_info *comment; 38557c2590fSTetsuo Handa head->read_step = index; 3869590837bSKentaro Takeda if (!profile) 3879590837bSKentaro Takeda continue; 38857c2590fSTetsuo Handa pos = head->read_avail; 38957c2590fSTetsuo Handa comment = profile->comment; 39057c2590fSTetsuo Handa done = tomoyo_io_printf(head, "%u-COMMENT=%s\n", index, 39157c2590fSTetsuo Handa comment ? comment->name : ""); 39257c2590fSTetsuo Handa if (!done) 39357c2590fSTetsuo Handa goto out; 39457c2590fSTetsuo Handa config = profile->default_config; 39557c2590fSTetsuo Handa if (!tomoyo_io_printf(head, "%u-CONFIG={ mode=%s }\n", index, 39657c2590fSTetsuo Handa tomoyo_mode_4[config & 3])) 39757c2590fSTetsuo Handa goto out; 39857c2590fSTetsuo Handa for (i = 0; i < TOMOYO_MAX_MAC_INDEX + 39957c2590fSTetsuo Handa TOMOYO_MAX_MAC_CATEGORY_INDEX; i++) { 40057c2590fSTetsuo Handa config = profile->config[i]; 40157c2590fSTetsuo Handa if (config == TOMOYO_CONFIG_USE_DEFAULT) 4029590837bSKentaro Takeda continue; 40357c2590fSTetsuo Handa if (!tomoyo_io_printf(head, 40457c2590fSTetsuo Handa "%u-CONFIG::%s={ mode=%s }\n", 40557c2590fSTetsuo Handa index, tomoyo_mac_keywords[i], 40657c2590fSTetsuo Handa tomoyo_mode_4[config & 3])) 40757c2590fSTetsuo Handa goto out; 4089590837bSKentaro Takeda } 40957c2590fSTetsuo Handa if (profile->learning != &tomoyo_default_profile.preference && 41057c2590fSTetsuo Handa !tomoyo_io_printf(head, "%u-PREFERENCE::learning={ " 41157c2590fSTetsuo Handa "verbose=%s max_entry=%u }\n", index, 41257c2590fSTetsuo Handa tomoyo_yesno(profile->preference. 41357c2590fSTetsuo Handa learning_verbose), 41457c2590fSTetsuo Handa profile->preference.learning_max_entry)) 41557c2590fSTetsuo Handa goto out; 41657c2590fSTetsuo Handa if (profile->permissive != &tomoyo_default_profile.preference 41757c2590fSTetsuo Handa && !tomoyo_io_printf(head, "%u-PREFERENCE::permissive={ " 41857c2590fSTetsuo Handa "verbose=%s }\n", index, 41957c2590fSTetsuo Handa tomoyo_yesno(profile->preference. 42057c2590fSTetsuo Handa permissive_verbose))) 42157c2590fSTetsuo Handa goto out; 42257c2590fSTetsuo Handa if (profile->enforcing != &tomoyo_default_profile.preference && 42357c2590fSTetsuo Handa !tomoyo_io_printf(head, "%u-PREFERENCE::enforcing={ " 42457c2590fSTetsuo Handa "verbose=%s }\n", index, 42557c2590fSTetsuo Handa tomoyo_yesno(profile->preference. 42657c2590fSTetsuo Handa enforcing_verbose))) 42757c2590fSTetsuo Handa goto out; 42857c2590fSTetsuo Handa continue; 42957c2590fSTetsuo Handa out: 43057c2590fSTetsuo Handa head->read_avail = pos; 4319590837bSKentaro Takeda break; 4329590837bSKentaro Takeda } 43357c2590fSTetsuo Handa if (index == TOMOYO_MAX_PROFILES) 4349590837bSKentaro Takeda head->read_eof = true; 4359590837bSKentaro Takeda } 4369590837bSKentaro Takeda 43736f5e1ffSTetsuo Handa static bool tomoyo_same_manager_entry(const struct tomoyo_acl_head *a, 43836f5e1ffSTetsuo Handa const struct tomoyo_acl_head *b) 43936f5e1ffSTetsuo Handa { 44036f5e1ffSTetsuo Handa return container_of(a, struct tomoyo_policy_manager_entry, head) 44136f5e1ffSTetsuo Handa ->manager == 44236f5e1ffSTetsuo Handa container_of(b, struct tomoyo_policy_manager_entry, head) 44336f5e1ffSTetsuo Handa ->manager; 44436f5e1ffSTetsuo Handa } 44536f5e1ffSTetsuo Handa 4469590837bSKentaro Takeda /** 4479590837bSKentaro Takeda * tomoyo_update_manager_entry - Add a manager entry. 4489590837bSKentaro Takeda * 4499590837bSKentaro Takeda * @manager: The path to manager or the domainnamme. 4509590837bSKentaro Takeda * @is_delete: True if it is a delete request. 4519590837bSKentaro Takeda * 4529590837bSKentaro Takeda * Returns 0 on success, negative value otherwise. 453fdb8ebb7STetsuo Handa * 454fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 4559590837bSKentaro Takeda */ 4569590837bSKentaro Takeda static int tomoyo_update_manager_entry(const char *manager, 4579590837bSKentaro Takeda const bool is_delete) 4589590837bSKentaro Takeda { 4599e4b50e9STetsuo Handa struct tomoyo_policy_manager_entry e = { }; 46036f5e1ffSTetsuo Handa int error; 4619590837bSKentaro Takeda 46275093152STetsuo Handa if (tomoyo_domain_def(manager)) { 46375093152STetsuo Handa if (!tomoyo_correct_domain(manager)) 4649590837bSKentaro Takeda return -EINVAL; 4659e4b50e9STetsuo Handa e.is_domain = true; 4669590837bSKentaro Takeda } else { 46775093152STetsuo Handa if (!tomoyo_correct_path(manager)) 4689590837bSKentaro Takeda return -EINVAL; 4699590837bSKentaro Takeda } 4709e4b50e9STetsuo Handa e.manager = tomoyo_get_name(manager); 4719e4b50e9STetsuo Handa if (!e.manager) 4729590837bSKentaro Takeda return -ENOMEM; 47336f5e1ffSTetsuo Handa error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, 474a230f9e7STetsuo Handa &tomoyo_policy_list[TOMOYO_ID_MANAGER], 47536f5e1ffSTetsuo Handa tomoyo_same_manager_entry); 4769e4b50e9STetsuo Handa tomoyo_put_name(e.manager); 4779590837bSKentaro Takeda return error; 4789590837bSKentaro Takeda } 4799590837bSKentaro Takeda 4809590837bSKentaro Takeda /** 4819590837bSKentaro Takeda * tomoyo_write_manager_policy - Write manager policy. 4829590837bSKentaro Takeda * 4839590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 4849590837bSKentaro Takeda * 4859590837bSKentaro Takeda * Returns 0 on success, negative value otherwise. 486fdb8ebb7STetsuo Handa * 487fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 4889590837bSKentaro Takeda */ 4899590837bSKentaro Takeda static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head) 4909590837bSKentaro Takeda { 4919590837bSKentaro Takeda char *data = head->write_buf; 4929590837bSKentaro Takeda bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE); 4939590837bSKentaro Takeda 4949590837bSKentaro Takeda if (!strcmp(data, "manage_by_non_root")) { 4959590837bSKentaro Takeda tomoyo_manage_by_non_root = !is_delete; 4969590837bSKentaro Takeda return 0; 4979590837bSKentaro Takeda } 4989590837bSKentaro Takeda return tomoyo_update_manager_entry(data, is_delete); 4999590837bSKentaro Takeda } 5009590837bSKentaro Takeda 5019590837bSKentaro Takeda /** 5029590837bSKentaro Takeda * tomoyo_read_manager_policy - Read manager policy. 5039590837bSKentaro Takeda * 5049590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 5059590837bSKentaro Takeda * 506fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 5079590837bSKentaro Takeda */ 5088fbe71f0STetsuo Handa static void tomoyo_read_manager_policy(struct tomoyo_io_buffer *head) 5099590837bSKentaro Takeda { 5109590837bSKentaro Takeda struct list_head *pos; 5119590837bSKentaro Takeda bool done = true; 5129590837bSKentaro Takeda 5139590837bSKentaro Takeda if (head->read_eof) 5148fbe71f0STetsuo Handa return; 5159590837bSKentaro Takeda list_for_each_cookie(pos, head->read_var2, 516a230f9e7STetsuo Handa &tomoyo_policy_list[TOMOYO_ID_MANAGER]) { 5179590837bSKentaro Takeda struct tomoyo_policy_manager_entry *ptr; 5189590837bSKentaro Takeda ptr = list_entry(pos, struct tomoyo_policy_manager_entry, 51982e0f001STetsuo Handa head.list); 52082e0f001STetsuo Handa if (ptr->head.is_deleted) 5219590837bSKentaro Takeda continue; 5227d2948b1STetsuo Handa done = tomoyo_io_printf(head, "%s\n", ptr->manager->name); 5237d2948b1STetsuo Handa if (!done) 5249590837bSKentaro Takeda break; 5259590837bSKentaro Takeda } 5269590837bSKentaro Takeda head->read_eof = done; 5279590837bSKentaro Takeda } 5289590837bSKentaro Takeda 5299590837bSKentaro Takeda /** 53075093152STetsuo Handa * tomoyo_policy_manager - Check whether the current process is a policy manager. 5319590837bSKentaro Takeda * 5329590837bSKentaro Takeda * Returns true if the current process is permitted to modify policy 5339590837bSKentaro Takeda * via /sys/kernel/security/tomoyo/ interface. 534fdb8ebb7STetsuo Handa * 535fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 5369590837bSKentaro Takeda */ 53775093152STetsuo Handa static bool tomoyo_policy_manager(void) 5389590837bSKentaro Takeda { 5399590837bSKentaro Takeda struct tomoyo_policy_manager_entry *ptr; 5409590837bSKentaro Takeda const char *exe; 5419590837bSKentaro Takeda const struct task_struct *task = current; 5429590837bSKentaro Takeda const struct tomoyo_path_info *domainname = tomoyo_domain()->domainname; 5439590837bSKentaro Takeda bool found = false; 5449590837bSKentaro Takeda 5459590837bSKentaro Takeda if (!tomoyo_policy_loaded) 5469590837bSKentaro Takeda return true; 5479590837bSKentaro Takeda if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid)) 5489590837bSKentaro Takeda return false; 549a230f9e7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_MANAGER], 550a230f9e7STetsuo Handa head.list) { 55182e0f001STetsuo Handa if (!ptr->head.is_deleted && ptr->is_domain 5529590837bSKentaro Takeda && !tomoyo_pathcmp(domainname, ptr->manager)) { 5539590837bSKentaro Takeda found = true; 5549590837bSKentaro Takeda break; 5559590837bSKentaro Takeda } 5569590837bSKentaro Takeda } 5579590837bSKentaro Takeda if (found) 5589590837bSKentaro Takeda return true; 5599590837bSKentaro Takeda exe = tomoyo_get_exe(); 5609590837bSKentaro Takeda if (!exe) 5619590837bSKentaro Takeda return false; 562a230f9e7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_MANAGER], 563a230f9e7STetsuo Handa head.list) { 56482e0f001STetsuo Handa if (!ptr->head.is_deleted && !ptr->is_domain 5659590837bSKentaro Takeda && !strcmp(exe, ptr->manager->name)) { 5669590837bSKentaro Takeda found = true; 5679590837bSKentaro Takeda break; 5689590837bSKentaro Takeda } 5699590837bSKentaro Takeda } 5709590837bSKentaro Takeda if (!found) { /* Reduce error messages. */ 5719590837bSKentaro Takeda static pid_t last_pid; 5729590837bSKentaro Takeda const pid_t pid = current->pid; 5739590837bSKentaro Takeda if (last_pid != pid) { 5749590837bSKentaro Takeda printk(KERN_WARNING "%s ( %s ) is not permitted to " 5759590837bSKentaro Takeda "update policies.\n", domainname->name, exe); 5769590837bSKentaro Takeda last_pid = pid; 5779590837bSKentaro Takeda } 5789590837bSKentaro Takeda } 5798e2d39a1STetsuo Handa kfree(exe); 5809590837bSKentaro Takeda return found; 5819590837bSKentaro Takeda } 5829590837bSKentaro Takeda 5839590837bSKentaro Takeda /** 58475093152STetsuo Handa * tomoyo_select_one - Parse select command. 5859590837bSKentaro Takeda * 5869590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 5879590837bSKentaro Takeda * @data: String to parse. 5889590837bSKentaro Takeda * 5899590837bSKentaro Takeda * Returns true on success, false otherwise. 590fdb8ebb7STetsuo Handa * 591fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 5929590837bSKentaro Takeda */ 59375093152STetsuo Handa static bool tomoyo_select_one(struct tomoyo_io_buffer *head, 5949590837bSKentaro Takeda const char *data) 5959590837bSKentaro Takeda { 5969590837bSKentaro Takeda unsigned int pid; 5979590837bSKentaro Takeda struct tomoyo_domain_info *domain = NULL; 5989b244373STetsuo Handa bool global_pid = false; 5999590837bSKentaro Takeda 6009b244373STetsuo Handa if (sscanf(data, "pid=%u", &pid) == 1 || 6019b244373STetsuo Handa (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) { 6029590837bSKentaro Takeda struct task_struct *p; 6031fcdc7c5STetsuo Handa rcu_read_lock(); 6049590837bSKentaro Takeda read_lock(&tasklist_lock); 6059b244373STetsuo Handa if (global_pid) 6069b244373STetsuo Handa p = find_task_by_pid_ns(pid, &init_pid_ns); 6079b244373STetsuo Handa else 6089590837bSKentaro Takeda p = find_task_by_vpid(pid); 6099590837bSKentaro Takeda if (p) 6109590837bSKentaro Takeda domain = tomoyo_real_domain(p); 6119590837bSKentaro Takeda read_unlock(&tasklist_lock); 6121fcdc7c5STetsuo Handa rcu_read_unlock(); 6139590837bSKentaro Takeda } else if (!strncmp(data, "domain=", 7)) { 61475093152STetsuo Handa if (tomoyo_domain_def(data + 7)) 6159590837bSKentaro Takeda domain = tomoyo_find_domain(data + 7); 6169590837bSKentaro Takeda } else 6179590837bSKentaro Takeda return false; 6189590837bSKentaro Takeda head->write_var1 = domain; 6199590837bSKentaro Takeda /* Accessing read_buf is safe because head->io_sem is held. */ 6209590837bSKentaro Takeda if (!head->read_buf) 6219590837bSKentaro Takeda return true; /* Do nothing if open(O_WRONLY). */ 6229590837bSKentaro Takeda head->read_avail = 0; 6239590837bSKentaro Takeda tomoyo_io_printf(head, "# select %s\n", data); 6249590837bSKentaro Takeda head->read_single_domain = true; 6259590837bSKentaro Takeda head->read_eof = !domain; 6269590837bSKentaro Takeda if (domain) { 6279590837bSKentaro Takeda struct tomoyo_domain_info *d; 6289590837bSKentaro Takeda head->read_var1 = NULL; 629fdb8ebb7STetsuo Handa list_for_each_entry_rcu(d, &tomoyo_domain_list, list) { 6309590837bSKentaro Takeda if (d == domain) 6319590837bSKentaro Takeda break; 6329590837bSKentaro Takeda head->read_var1 = &d->list; 6339590837bSKentaro Takeda } 6349590837bSKentaro Takeda head->read_var2 = NULL; 6359590837bSKentaro Takeda head->read_bit = 0; 6369590837bSKentaro Takeda head->read_step = 0; 6379590837bSKentaro Takeda if (domain->is_deleted) 6389590837bSKentaro Takeda tomoyo_io_printf(head, "# This is a deleted domain.\n"); 6399590837bSKentaro Takeda } 6409590837bSKentaro Takeda return true; 6419590837bSKentaro Takeda } 6429590837bSKentaro Takeda 6439590837bSKentaro Takeda /** 644ccf135f5STetsuo Handa * tomoyo_delete_domain - Delete a domain. 645ccf135f5STetsuo Handa * 646ccf135f5STetsuo Handa * @domainname: The name of domain. 647ccf135f5STetsuo Handa * 648ccf135f5STetsuo Handa * Returns 0. 649fdb8ebb7STetsuo Handa * 650fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 651ccf135f5STetsuo Handa */ 652ccf135f5STetsuo Handa static int tomoyo_delete_domain(char *domainname) 653ccf135f5STetsuo Handa { 654ccf135f5STetsuo Handa struct tomoyo_domain_info *domain; 655ccf135f5STetsuo Handa struct tomoyo_path_info name; 656ccf135f5STetsuo Handa 657ccf135f5STetsuo Handa name.name = domainname; 658ccf135f5STetsuo Handa tomoyo_fill_path_info(&name); 65929282381STetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 66029282381STetsuo Handa return 0; 661ccf135f5STetsuo Handa /* Is there an active domain? */ 662fdb8ebb7STetsuo Handa list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { 663ccf135f5STetsuo Handa /* Never delete tomoyo_kernel_domain */ 664ccf135f5STetsuo Handa if (domain == &tomoyo_kernel_domain) 665ccf135f5STetsuo Handa continue; 666ccf135f5STetsuo Handa if (domain->is_deleted || 667ccf135f5STetsuo Handa tomoyo_pathcmp(domain->domainname, &name)) 668ccf135f5STetsuo Handa continue; 669ccf135f5STetsuo Handa domain->is_deleted = true; 670ccf135f5STetsuo Handa break; 671ccf135f5STetsuo Handa } 672f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 673ccf135f5STetsuo Handa return 0; 674ccf135f5STetsuo Handa } 675ccf135f5STetsuo Handa 676ccf135f5STetsuo Handa /** 67717fcfbd9STetsuo Handa * tomoyo_write_domain_policy2 - Write domain policy. 67817fcfbd9STetsuo Handa * 67917fcfbd9STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 68017fcfbd9STetsuo Handa * 68117fcfbd9STetsuo Handa * Returns 0 on success, negative value otherwise. 68217fcfbd9STetsuo Handa * 68317fcfbd9STetsuo Handa * Caller holds tomoyo_read_lock(). 68417fcfbd9STetsuo Handa */ 68517fcfbd9STetsuo Handa static int tomoyo_write_domain_policy2(char *data, 68617fcfbd9STetsuo Handa struct tomoyo_domain_info *domain, 68717fcfbd9STetsuo Handa const bool is_delete) 68817fcfbd9STetsuo Handa { 68917fcfbd9STetsuo Handa if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_MOUNT)) 69017fcfbd9STetsuo Handa return tomoyo_write_mount_policy(data, domain, is_delete); 69117fcfbd9STetsuo Handa return tomoyo_write_file_policy(data, domain, is_delete); 69217fcfbd9STetsuo Handa } 69317fcfbd9STetsuo Handa 69417fcfbd9STetsuo Handa /** 6959590837bSKentaro Takeda * tomoyo_write_domain_policy - Write domain policy. 6969590837bSKentaro Takeda * 6979590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 6989590837bSKentaro Takeda * 6999590837bSKentaro Takeda * Returns 0 on success, negative value otherwise. 700fdb8ebb7STetsuo Handa * 701fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 7029590837bSKentaro Takeda */ 7039590837bSKentaro Takeda static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head) 7049590837bSKentaro Takeda { 7059590837bSKentaro Takeda char *data = head->write_buf; 7069590837bSKentaro Takeda struct tomoyo_domain_info *domain = head->write_var1; 7079590837bSKentaro Takeda bool is_delete = false; 7089590837bSKentaro Takeda bool is_select = false; 7099590837bSKentaro Takeda unsigned int profile; 7109590837bSKentaro Takeda 7119590837bSKentaro Takeda if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE)) 7129590837bSKentaro Takeda is_delete = true; 7139590837bSKentaro Takeda else if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_SELECT)) 7149590837bSKentaro Takeda is_select = true; 71575093152STetsuo Handa if (is_select && tomoyo_select_one(head, data)) 7169590837bSKentaro Takeda return 0; 7179590837bSKentaro Takeda /* Don't allow updating policies by non manager programs. */ 71875093152STetsuo Handa if (!tomoyo_policy_manager()) 7199590837bSKentaro Takeda return -EPERM; 72075093152STetsuo Handa if (tomoyo_domain_def(data)) { 7219590837bSKentaro Takeda domain = NULL; 7229590837bSKentaro Takeda if (is_delete) 7239590837bSKentaro Takeda tomoyo_delete_domain(data); 724fdb8ebb7STetsuo Handa else if (is_select) 7259590837bSKentaro Takeda domain = tomoyo_find_domain(data); 726fdb8ebb7STetsuo Handa else 7279590837bSKentaro Takeda domain = tomoyo_find_or_assign_new_domain(data, 0); 7289590837bSKentaro Takeda head->write_var1 = domain; 7299590837bSKentaro Takeda return 0; 7309590837bSKentaro Takeda } 7319590837bSKentaro Takeda if (!domain) 7329590837bSKentaro Takeda return -EINVAL; 7339590837bSKentaro Takeda 7349590837bSKentaro Takeda if (sscanf(data, TOMOYO_KEYWORD_USE_PROFILE "%u", &profile) == 1 7359590837bSKentaro Takeda && profile < TOMOYO_MAX_PROFILES) { 7369590837bSKentaro Takeda if (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded) 7379590837bSKentaro Takeda domain->profile = (u8) profile; 7389590837bSKentaro Takeda return 0; 7399590837bSKentaro Takeda } 7409590837bSKentaro Takeda if (!strcmp(data, TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ)) { 741ea13ddbaSTetsuo Handa domain->ignore_global_allow_read = !is_delete; 7429590837bSKentaro Takeda return 0; 7439590837bSKentaro Takeda } 7449b244373STetsuo Handa if (!strcmp(data, TOMOYO_KEYWORD_QUOTA_EXCEEDED)) { 7459b244373STetsuo Handa domain->quota_warned = !is_delete; 7469b244373STetsuo Handa return 0; 7479b244373STetsuo Handa } 7489b244373STetsuo Handa if (!strcmp(data, TOMOYO_KEYWORD_TRANSITION_FAILED)) { 7499b244373STetsuo Handa domain->transition_failed = !is_delete; 7509b244373STetsuo Handa return 0; 7519b244373STetsuo Handa } 75217fcfbd9STetsuo Handa return tomoyo_write_domain_policy2(data, domain, is_delete); 7539590837bSKentaro Takeda } 7549590837bSKentaro Takeda 7559590837bSKentaro Takeda /** 7567ef61233STetsuo Handa * tomoyo_print_path_acl - Print a single path ACL entry. 7579590837bSKentaro Takeda * 7589590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 7597ef61233STetsuo Handa * @ptr: Pointer to "struct tomoyo_path_acl". 7609590837bSKentaro Takeda * 7619590837bSKentaro Takeda * Returns true on success, false otherwise. 7629590837bSKentaro Takeda */ 7637ef61233STetsuo Handa static bool tomoyo_print_path_acl(struct tomoyo_io_buffer *head, 7647ef61233STetsuo Handa struct tomoyo_path_acl *ptr) 7659590837bSKentaro Takeda { 7669590837bSKentaro Takeda int pos; 7679590837bSKentaro Takeda u8 bit; 768a1f9bb6aSTetsuo Handa const u16 perm = ptr->perm; 7699590837bSKentaro Takeda 7707ef61233STetsuo Handa for (bit = head->read_bit; bit < TOMOYO_MAX_PATH_OPERATION; bit++) { 7719590837bSKentaro Takeda if (!(perm & (1 << bit))) 7729590837bSKentaro Takeda continue; 7739590837bSKentaro Takeda /* Print "read/write" instead of "read" and "write". */ 7747ef61233STetsuo Handa if ((bit == TOMOYO_TYPE_READ || bit == TOMOYO_TYPE_WRITE) 7757ef61233STetsuo Handa && (perm & (1 << TOMOYO_TYPE_READ_WRITE))) 7769590837bSKentaro Takeda continue; 7779590837bSKentaro Takeda pos = head->read_avail; 7787762fbffSTetsuo Handa if (!tomoyo_io_printf(head, "allow_%s ", 77971c28236STetsuo Handa tomoyo_path_keyword[bit]) || 7807762fbffSTetsuo Handa !tomoyo_print_name_union(head, &ptr->name) || 7817762fbffSTetsuo Handa !tomoyo_io_printf(head, "\n")) 7829590837bSKentaro Takeda goto out; 7839590837bSKentaro Takeda } 7849590837bSKentaro Takeda head->read_bit = 0; 7859590837bSKentaro Takeda return true; 7869590837bSKentaro Takeda out: 7879590837bSKentaro Takeda head->read_bit = bit; 7889590837bSKentaro Takeda head->read_avail = pos; 7899590837bSKentaro Takeda return false; 7909590837bSKentaro Takeda } 7919590837bSKentaro Takeda 7929590837bSKentaro Takeda /** 7937ef61233STetsuo Handa * tomoyo_print_path2_acl - Print a double path ACL entry. 7949590837bSKentaro Takeda * 7959590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 7967ef61233STetsuo Handa * @ptr: Pointer to "struct tomoyo_path2_acl". 7979590837bSKentaro Takeda * 7989590837bSKentaro Takeda * Returns true on success, false otherwise. 7999590837bSKentaro Takeda */ 8007ef61233STetsuo Handa static bool tomoyo_print_path2_acl(struct tomoyo_io_buffer *head, 8017ef61233STetsuo Handa struct tomoyo_path2_acl *ptr) 8029590837bSKentaro Takeda { 8039590837bSKentaro Takeda int pos; 8049590837bSKentaro Takeda const u8 perm = ptr->perm; 8059590837bSKentaro Takeda u8 bit; 8069590837bSKentaro Takeda 8077ef61233STetsuo Handa for (bit = head->read_bit; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) { 8089590837bSKentaro Takeda if (!(perm & (1 << bit))) 8099590837bSKentaro Takeda continue; 8109590837bSKentaro Takeda pos = head->read_avail; 8117762fbffSTetsuo Handa if (!tomoyo_io_printf(head, "allow_%s ", 81271c28236STetsuo Handa tomoyo_path2_keyword[bit]) || 8137762fbffSTetsuo Handa !tomoyo_print_name_union(head, &ptr->name1) || 8147762fbffSTetsuo Handa !tomoyo_print_name_union(head, &ptr->name2) || 8157762fbffSTetsuo Handa !tomoyo_io_printf(head, "\n")) 8169590837bSKentaro Takeda goto out; 8179590837bSKentaro Takeda } 8189590837bSKentaro Takeda head->read_bit = 0; 8199590837bSKentaro Takeda return true; 8209590837bSKentaro Takeda out: 8219590837bSKentaro Takeda head->read_bit = bit; 8229590837bSKentaro Takeda head->read_avail = pos; 8239590837bSKentaro Takeda return false; 8249590837bSKentaro Takeda } 8259590837bSKentaro Takeda 8269590837bSKentaro Takeda /** 827a1f9bb6aSTetsuo Handa * tomoyo_print_path_number_acl - Print a path_number ACL entry. 828a1f9bb6aSTetsuo Handa * 829a1f9bb6aSTetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 830a1f9bb6aSTetsuo Handa * @ptr: Pointer to "struct tomoyo_path_number_acl". 831a1f9bb6aSTetsuo Handa * 832a1f9bb6aSTetsuo Handa * Returns true on success, false otherwise. 833a1f9bb6aSTetsuo Handa */ 834a1f9bb6aSTetsuo Handa static bool tomoyo_print_path_number_acl(struct tomoyo_io_buffer *head, 835a1f9bb6aSTetsuo Handa struct tomoyo_path_number_acl *ptr) 836a1f9bb6aSTetsuo Handa { 837a1f9bb6aSTetsuo Handa int pos; 838a1f9bb6aSTetsuo Handa u8 bit; 839a1f9bb6aSTetsuo Handa const u8 perm = ptr->perm; 840a1f9bb6aSTetsuo Handa for (bit = head->read_bit; bit < TOMOYO_MAX_PATH_NUMBER_OPERATION; 841a1f9bb6aSTetsuo Handa bit++) { 842a1f9bb6aSTetsuo Handa if (!(perm & (1 << bit))) 843a1f9bb6aSTetsuo Handa continue; 844a1f9bb6aSTetsuo Handa pos = head->read_avail; 845a1f9bb6aSTetsuo Handa if (!tomoyo_io_printf(head, "allow_%s", 84671c28236STetsuo Handa tomoyo_path_number_keyword[bit]) || 847a1f9bb6aSTetsuo Handa !tomoyo_print_name_union(head, &ptr->name) || 848a1f9bb6aSTetsuo Handa !tomoyo_print_number_union(head, &ptr->number) || 849a1f9bb6aSTetsuo Handa !tomoyo_io_printf(head, "\n")) 850a1f9bb6aSTetsuo Handa goto out; 851a1f9bb6aSTetsuo Handa } 852a1f9bb6aSTetsuo Handa head->read_bit = 0; 853a1f9bb6aSTetsuo Handa return true; 854a1f9bb6aSTetsuo Handa out: 855a1f9bb6aSTetsuo Handa head->read_bit = bit; 856a1f9bb6aSTetsuo Handa head->read_avail = pos; 857a1f9bb6aSTetsuo Handa return false; 858a1f9bb6aSTetsuo Handa } 859a1f9bb6aSTetsuo Handa 860a1f9bb6aSTetsuo Handa /** 86175093152STetsuo Handa * tomoyo_print_mkdev_acl - Print a mkdev ACL entry. 862a1f9bb6aSTetsuo Handa * 863a1f9bb6aSTetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 86475093152STetsuo Handa * @ptr: Pointer to "struct tomoyo_mkdev_acl". 865a1f9bb6aSTetsuo Handa * 866a1f9bb6aSTetsuo Handa * Returns true on success, false otherwise. 867a1f9bb6aSTetsuo Handa */ 86875093152STetsuo Handa static bool tomoyo_print_mkdev_acl(struct tomoyo_io_buffer *head, 86975093152STetsuo Handa struct tomoyo_mkdev_acl *ptr) 870a1f9bb6aSTetsuo Handa { 871a1f9bb6aSTetsuo Handa int pos; 872a1f9bb6aSTetsuo Handa u8 bit; 873a1f9bb6aSTetsuo Handa const u16 perm = ptr->perm; 87475093152STetsuo Handa for (bit = head->read_bit; bit < TOMOYO_MAX_MKDEV_OPERATION; 875a1f9bb6aSTetsuo Handa bit++) { 876a1f9bb6aSTetsuo Handa if (!(perm & (1 << bit))) 877a1f9bb6aSTetsuo Handa continue; 878a1f9bb6aSTetsuo Handa pos = head->read_avail; 879a1f9bb6aSTetsuo Handa if (!tomoyo_io_printf(head, "allow_%s", 88071c28236STetsuo Handa tomoyo_mkdev_keyword[bit]) || 881a1f9bb6aSTetsuo Handa !tomoyo_print_name_union(head, &ptr->name) || 882a1f9bb6aSTetsuo Handa !tomoyo_print_number_union(head, &ptr->mode) || 883a1f9bb6aSTetsuo Handa !tomoyo_print_number_union(head, &ptr->major) || 884a1f9bb6aSTetsuo Handa !tomoyo_print_number_union(head, &ptr->minor) || 885a1f9bb6aSTetsuo Handa !tomoyo_io_printf(head, "\n")) 886a1f9bb6aSTetsuo Handa goto out; 887a1f9bb6aSTetsuo Handa } 888a1f9bb6aSTetsuo Handa head->read_bit = 0; 889a1f9bb6aSTetsuo Handa return true; 890a1f9bb6aSTetsuo Handa out: 891a1f9bb6aSTetsuo Handa head->read_bit = bit; 892a1f9bb6aSTetsuo Handa head->read_avail = pos; 893a1f9bb6aSTetsuo Handa return false; 894a1f9bb6aSTetsuo Handa } 895a1f9bb6aSTetsuo Handa 896a1f9bb6aSTetsuo Handa /** 8972106ccd9STetsuo Handa * tomoyo_print_mount_acl - Print a mount ACL entry. 8982106ccd9STetsuo Handa * 8992106ccd9STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 9002106ccd9STetsuo Handa * @ptr: Pointer to "struct tomoyo_mount_acl". 9012106ccd9STetsuo Handa * 9022106ccd9STetsuo Handa * Returns true on success, false otherwise. 9032106ccd9STetsuo Handa */ 9042106ccd9STetsuo Handa static bool tomoyo_print_mount_acl(struct tomoyo_io_buffer *head, 9052106ccd9STetsuo Handa struct tomoyo_mount_acl *ptr) 9062106ccd9STetsuo Handa { 9072106ccd9STetsuo Handa const int pos = head->read_avail; 9082106ccd9STetsuo Handa if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_MOUNT) || 9092106ccd9STetsuo Handa !tomoyo_print_name_union(head, &ptr->dev_name) || 9102106ccd9STetsuo Handa !tomoyo_print_name_union(head, &ptr->dir_name) || 9112106ccd9STetsuo Handa !tomoyo_print_name_union(head, &ptr->fs_type) || 9122106ccd9STetsuo Handa !tomoyo_print_number_union(head, &ptr->flags) || 9132106ccd9STetsuo Handa !tomoyo_io_printf(head, "\n")) { 9142106ccd9STetsuo Handa head->read_avail = pos; 9152106ccd9STetsuo Handa return false; 9162106ccd9STetsuo Handa } 9172106ccd9STetsuo Handa return true; 9182106ccd9STetsuo Handa } 9192106ccd9STetsuo Handa 9202106ccd9STetsuo Handa /** 9219590837bSKentaro Takeda * tomoyo_print_entry - Print an ACL entry. 9229590837bSKentaro Takeda * 9239590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 9249590837bSKentaro Takeda * @ptr: Pointer to an ACL entry. 9259590837bSKentaro Takeda * 9269590837bSKentaro Takeda * Returns true on success, false otherwise. 9279590837bSKentaro Takeda */ 9289590837bSKentaro Takeda static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, 9299590837bSKentaro Takeda struct tomoyo_acl_info *ptr) 9309590837bSKentaro Takeda { 931ea13ddbaSTetsuo Handa const u8 acl_type = ptr->type; 9329590837bSKentaro Takeda 933237ab459STetsuo Handa if (ptr->is_deleted) 934237ab459STetsuo Handa return true; 9357ef61233STetsuo Handa if (acl_type == TOMOYO_TYPE_PATH_ACL) { 9367ef61233STetsuo Handa struct tomoyo_path_acl *acl 9377ef61233STetsuo Handa = container_of(ptr, struct tomoyo_path_acl, head); 9387ef61233STetsuo Handa return tomoyo_print_path_acl(head, acl); 9399590837bSKentaro Takeda } 9407ef61233STetsuo Handa if (acl_type == TOMOYO_TYPE_PATH2_ACL) { 9417ef61233STetsuo Handa struct tomoyo_path2_acl *acl 9427ef61233STetsuo Handa = container_of(ptr, struct tomoyo_path2_acl, head); 9437ef61233STetsuo Handa return tomoyo_print_path2_acl(head, acl); 9449590837bSKentaro Takeda } 945a1f9bb6aSTetsuo Handa if (acl_type == TOMOYO_TYPE_PATH_NUMBER_ACL) { 946a1f9bb6aSTetsuo Handa struct tomoyo_path_number_acl *acl 947a1f9bb6aSTetsuo Handa = container_of(ptr, struct tomoyo_path_number_acl, 948a1f9bb6aSTetsuo Handa head); 949a1f9bb6aSTetsuo Handa return tomoyo_print_path_number_acl(head, acl); 950a1f9bb6aSTetsuo Handa } 95175093152STetsuo Handa if (acl_type == TOMOYO_TYPE_MKDEV_ACL) { 95275093152STetsuo Handa struct tomoyo_mkdev_acl *acl 95375093152STetsuo Handa = container_of(ptr, struct tomoyo_mkdev_acl, 954a1f9bb6aSTetsuo Handa head); 95575093152STetsuo Handa return tomoyo_print_mkdev_acl(head, acl); 956a1f9bb6aSTetsuo Handa } 9572106ccd9STetsuo Handa if (acl_type == TOMOYO_TYPE_MOUNT_ACL) { 9582106ccd9STetsuo Handa struct tomoyo_mount_acl *acl 9592106ccd9STetsuo Handa = container_of(ptr, struct tomoyo_mount_acl, head); 9602106ccd9STetsuo Handa return tomoyo_print_mount_acl(head, acl); 9612106ccd9STetsuo Handa } 9629590837bSKentaro Takeda BUG(); /* This must not happen. */ 9639590837bSKentaro Takeda return false; 9649590837bSKentaro Takeda } 9659590837bSKentaro Takeda 9669590837bSKentaro Takeda /** 9679590837bSKentaro Takeda * tomoyo_read_domain_policy - Read domain policy. 9689590837bSKentaro Takeda * 9699590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 9709590837bSKentaro Takeda * 971fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 9729590837bSKentaro Takeda */ 9738fbe71f0STetsuo Handa static void tomoyo_read_domain_policy(struct tomoyo_io_buffer *head) 9749590837bSKentaro Takeda { 9759590837bSKentaro Takeda struct list_head *dpos; 9769590837bSKentaro Takeda struct list_head *apos; 9779590837bSKentaro Takeda bool done = true; 9789590837bSKentaro Takeda 9799590837bSKentaro Takeda if (head->read_eof) 9808fbe71f0STetsuo Handa return; 9819590837bSKentaro Takeda if (head->read_step == 0) 9829590837bSKentaro Takeda head->read_step = 1; 9839590837bSKentaro Takeda list_for_each_cookie(dpos, head->read_var1, &tomoyo_domain_list) { 9849590837bSKentaro Takeda struct tomoyo_domain_info *domain; 9859590837bSKentaro Takeda const char *quota_exceeded = ""; 9869590837bSKentaro Takeda const char *transition_failed = ""; 9879590837bSKentaro Takeda const char *ignore_global_allow_read = ""; 9889590837bSKentaro Takeda domain = list_entry(dpos, struct tomoyo_domain_info, list); 9899590837bSKentaro Takeda if (head->read_step != 1) 9909590837bSKentaro Takeda goto acl_loop; 9919590837bSKentaro Takeda if (domain->is_deleted && !head->read_single_domain) 9929590837bSKentaro Takeda continue; 9939590837bSKentaro Takeda /* Print domainname and flags. */ 9949590837bSKentaro Takeda if (domain->quota_warned) 9959590837bSKentaro Takeda quota_exceeded = "quota_exceeded\n"; 996ea13ddbaSTetsuo Handa if (domain->transition_failed) 9979590837bSKentaro Takeda transition_failed = "transition_failed\n"; 998ea13ddbaSTetsuo Handa if (domain->ignore_global_allow_read) 9999590837bSKentaro Takeda ignore_global_allow_read 10009590837bSKentaro Takeda = TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n"; 10017d2948b1STetsuo Handa done = tomoyo_io_printf(head, "%s\n" TOMOYO_KEYWORD_USE_PROFILE 10027d2948b1STetsuo Handa "%u\n%s%s%s\n", 10037d2948b1STetsuo Handa domain->domainname->name, 10049590837bSKentaro Takeda domain->profile, quota_exceeded, 10059590837bSKentaro Takeda transition_failed, 10067d2948b1STetsuo Handa ignore_global_allow_read); 10077d2948b1STetsuo Handa if (!done) 10089590837bSKentaro Takeda break; 10099590837bSKentaro Takeda head->read_step = 2; 10109590837bSKentaro Takeda acl_loop: 10119590837bSKentaro Takeda if (head->read_step == 3) 10129590837bSKentaro Takeda goto tail_mark; 10139590837bSKentaro Takeda /* Print ACL entries in the domain. */ 10149590837bSKentaro Takeda list_for_each_cookie(apos, head->read_var2, 10159590837bSKentaro Takeda &domain->acl_info_list) { 10169590837bSKentaro Takeda struct tomoyo_acl_info *ptr 10179590837bSKentaro Takeda = list_entry(apos, struct tomoyo_acl_info, 10189590837bSKentaro Takeda list); 10197d2948b1STetsuo Handa done = tomoyo_print_entry(head, ptr); 10207d2948b1STetsuo Handa if (!done) 10219590837bSKentaro Takeda break; 10229590837bSKentaro Takeda } 10239590837bSKentaro Takeda if (!done) 10249590837bSKentaro Takeda break; 10259590837bSKentaro Takeda head->read_step = 3; 10269590837bSKentaro Takeda tail_mark: 10277d2948b1STetsuo Handa done = tomoyo_io_printf(head, "\n"); 10287d2948b1STetsuo Handa if (!done) 10299590837bSKentaro Takeda break; 10309590837bSKentaro Takeda head->read_step = 1; 10319590837bSKentaro Takeda if (head->read_single_domain) 10329590837bSKentaro Takeda break; 10339590837bSKentaro Takeda } 10349590837bSKentaro Takeda head->read_eof = done; 10359590837bSKentaro Takeda } 10369590837bSKentaro Takeda 10379590837bSKentaro Takeda /** 10389590837bSKentaro Takeda * tomoyo_write_domain_profile - Assign profile for specified domain. 10399590837bSKentaro Takeda * 10409590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 10419590837bSKentaro Takeda * 10429590837bSKentaro Takeda * Returns 0 on success, -EINVAL otherwise. 10439590837bSKentaro Takeda * 10449590837bSKentaro Takeda * This is equivalent to doing 10459590837bSKentaro Takeda * 10469590837bSKentaro Takeda * ( echo "select " $domainname; echo "use_profile " $profile ) | 10479b244373STetsuo Handa * /usr/sbin/tomoyo-loadpolicy -d 1048fdb8ebb7STetsuo Handa * 1049fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 10509590837bSKentaro Takeda */ 10519590837bSKentaro Takeda static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head) 10529590837bSKentaro Takeda { 10539590837bSKentaro Takeda char *data = head->write_buf; 10549590837bSKentaro Takeda char *cp = strchr(data, ' '); 10559590837bSKentaro Takeda struct tomoyo_domain_info *domain; 10569590837bSKentaro Takeda unsigned long profile; 10579590837bSKentaro Takeda 10589590837bSKentaro Takeda if (!cp) 10599590837bSKentaro Takeda return -EINVAL; 10609590837bSKentaro Takeda *cp = '\0'; 10619590837bSKentaro Takeda domain = tomoyo_find_domain(cp + 1); 10629590837bSKentaro Takeda if (strict_strtoul(data, 10, &profile)) 10639590837bSKentaro Takeda return -EINVAL; 10649590837bSKentaro Takeda if (domain && profile < TOMOYO_MAX_PROFILES 10659590837bSKentaro Takeda && (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded)) 10669590837bSKentaro Takeda domain->profile = (u8) profile; 10679590837bSKentaro Takeda return 0; 10689590837bSKentaro Takeda } 10699590837bSKentaro Takeda 10709590837bSKentaro Takeda /** 10719590837bSKentaro Takeda * tomoyo_read_domain_profile - Read only domainname and profile. 10729590837bSKentaro Takeda * 10739590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 10749590837bSKentaro Takeda * 10759590837bSKentaro Takeda * Returns list of profile number and domainname pairs. 10769590837bSKentaro Takeda * 10779590837bSKentaro Takeda * This is equivalent to doing 10789590837bSKentaro Takeda * 10799590837bSKentaro Takeda * grep -A 1 '^<kernel>' /sys/kernel/security/tomoyo/domain_policy | 10809590837bSKentaro Takeda * awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" ) 10819590837bSKentaro Takeda * domainname = $0; } else if ( $1 == "use_profile" ) { 10829590837bSKentaro Takeda * print $2 " " domainname; domainname = ""; } } ; ' 1083fdb8ebb7STetsuo Handa * 1084fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 10859590837bSKentaro Takeda */ 10868fbe71f0STetsuo Handa static void tomoyo_read_domain_profile(struct tomoyo_io_buffer *head) 10879590837bSKentaro Takeda { 10889590837bSKentaro Takeda struct list_head *pos; 10899590837bSKentaro Takeda bool done = true; 10909590837bSKentaro Takeda 10919590837bSKentaro Takeda if (head->read_eof) 10928fbe71f0STetsuo Handa return; 10939590837bSKentaro Takeda list_for_each_cookie(pos, head->read_var1, &tomoyo_domain_list) { 10949590837bSKentaro Takeda struct tomoyo_domain_info *domain; 10959590837bSKentaro Takeda domain = list_entry(pos, struct tomoyo_domain_info, list); 10969590837bSKentaro Takeda if (domain->is_deleted) 10979590837bSKentaro Takeda continue; 10987d2948b1STetsuo Handa done = tomoyo_io_printf(head, "%u %s\n", domain->profile, 10997d2948b1STetsuo Handa domain->domainname->name); 11007d2948b1STetsuo Handa if (!done) 11019590837bSKentaro Takeda break; 11029590837bSKentaro Takeda } 11039590837bSKentaro Takeda head->read_eof = done; 11049590837bSKentaro Takeda } 11059590837bSKentaro Takeda 11069590837bSKentaro Takeda /** 11079590837bSKentaro Takeda * tomoyo_write_pid: Specify PID to obtain domainname. 11089590837bSKentaro Takeda * 11099590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 11109590837bSKentaro Takeda * 11119590837bSKentaro Takeda * Returns 0. 11129590837bSKentaro Takeda */ 11139590837bSKentaro Takeda static int tomoyo_write_pid(struct tomoyo_io_buffer *head) 11149590837bSKentaro Takeda { 11159590837bSKentaro Takeda unsigned long pid; 11169590837bSKentaro Takeda /* No error check. */ 11179590837bSKentaro Takeda strict_strtoul(head->write_buf, 10, &pid); 11189590837bSKentaro Takeda head->read_step = (int) pid; 11199590837bSKentaro Takeda head->read_eof = false; 11209590837bSKentaro Takeda return 0; 11219590837bSKentaro Takeda } 11229590837bSKentaro Takeda 11239590837bSKentaro Takeda /** 11249590837bSKentaro Takeda * tomoyo_read_pid - Get domainname of the specified PID. 11259590837bSKentaro Takeda * 11269590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 11279590837bSKentaro Takeda * 11289590837bSKentaro Takeda * Returns the domainname which the specified PID is in on success, 11299590837bSKentaro Takeda * empty string otherwise. 11309590837bSKentaro Takeda * The PID is specified by tomoyo_write_pid() so that the user can obtain 11319590837bSKentaro Takeda * using read()/write() interface rather than sysctl() interface. 11329590837bSKentaro Takeda */ 11338fbe71f0STetsuo Handa static void tomoyo_read_pid(struct tomoyo_io_buffer *head) 11349590837bSKentaro Takeda { 11359590837bSKentaro Takeda if (head->read_avail == 0 && !head->read_eof) { 11369590837bSKentaro Takeda const int pid = head->read_step; 11379590837bSKentaro Takeda struct task_struct *p; 11389590837bSKentaro Takeda struct tomoyo_domain_info *domain = NULL; 11391fcdc7c5STetsuo Handa rcu_read_lock(); 11409590837bSKentaro Takeda read_lock(&tasklist_lock); 11419590837bSKentaro Takeda p = find_task_by_vpid(pid); 11429590837bSKentaro Takeda if (p) 11439590837bSKentaro Takeda domain = tomoyo_real_domain(p); 11449590837bSKentaro Takeda read_unlock(&tasklist_lock); 11451fcdc7c5STetsuo Handa rcu_read_unlock(); 11469590837bSKentaro Takeda if (domain) 11479590837bSKentaro Takeda tomoyo_io_printf(head, "%d %u %s", pid, domain->profile, 11489590837bSKentaro Takeda domain->domainname->name); 11499590837bSKentaro Takeda head->read_eof = true; 11509590837bSKentaro Takeda } 11519590837bSKentaro Takeda } 11529590837bSKentaro Takeda 1153*5448ec4fSTetsuo Handa static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = { 1154*5448ec4fSTetsuo Handa [TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE] 1155*5448ec4fSTetsuo Handa = TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN, 1156*5448ec4fSTetsuo Handa [TOMOYO_TRANSITION_CONTROL_INITIALIZE] 1157*5448ec4fSTetsuo Handa = TOMOYO_KEYWORD_INITIALIZE_DOMAIN, 1158*5448ec4fSTetsuo Handa [TOMOYO_TRANSITION_CONTROL_NO_KEEP] = TOMOYO_KEYWORD_NO_KEEP_DOMAIN, 1159*5448ec4fSTetsuo Handa [TOMOYO_TRANSITION_CONTROL_KEEP] = TOMOYO_KEYWORD_KEEP_DOMAIN 1160*5448ec4fSTetsuo Handa }; 1161*5448ec4fSTetsuo Handa 11629590837bSKentaro Takeda /** 11639590837bSKentaro Takeda * tomoyo_write_exception_policy - Write exception policy. 11649590837bSKentaro Takeda * 11659590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 11669590837bSKentaro Takeda * 11679590837bSKentaro Takeda * Returns 0 on success, negative value otherwise. 1168fdb8ebb7STetsuo Handa * 1169fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 11709590837bSKentaro Takeda */ 11719590837bSKentaro Takeda static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head) 11729590837bSKentaro Takeda { 11739590837bSKentaro Takeda char *data = head->write_buf; 11749590837bSKentaro Takeda bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE); 1175*5448ec4fSTetsuo Handa u8 i; 11769590837bSKentaro Takeda 1177*5448ec4fSTetsuo Handa for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++) { 1178*5448ec4fSTetsuo Handa if (tomoyo_str_starts(&data, tomoyo_transition_type[i])) 1179*5448ec4fSTetsuo Handa return tomoyo_write_transition_control(data, is_delete, 1180*5448ec4fSTetsuo Handa i); 1181*5448ec4fSTetsuo Handa } 11821084307cSTetsuo Handa if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_AGGREGATOR)) 11831084307cSTetsuo Handa return tomoyo_write_aggregator_policy(data, is_delete); 11849590837bSKentaro Takeda if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_READ)) 11859590837bSKentaro Takeda return tomoyo_write_globally_readable_policy(data, is_delete); 11869590837bSKentaro Takeda if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_FILE_PATTERN)) 11879590837bSKentaro Takeda return tomoyo_write_pattern_policy(data, is_delete); 11889590837bSKentaro Takeda if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DENY_REWRITE)) 11899590837bSKentaro Takeda return tomoyo_write_no_rewrite_policy(data, is_delete); 11907762fbffSTetsuo Handa if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_PATH_GROUP)) 11917c2ea22eSTetsuo Handa return tomoyo_write_group(data, is_delete, TOMOYO_PATH_GROUP); 11924c3e9e2dSTetsuo Handa if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NUMBER_GROUP)) 11937c2ea22eSTetsuo Handa return tomoyo_write_group(data, is_delete, TOMOYO_NUMBER_GROUP); 11949590837bSKentaro Takeda return -EINVAL; 11959590837bSKentaro Takeda } 11969590837bSKentaro Takeda 119731845e8cSTetsuo Handa static void tomoyo_print_number(char *buffer, int buffer_len, 119831845e8cSTetsuo Handa const struct tomoyo_number_union *ptr) 119931845e8cSTetsuo Handa { 120031845e8cSTetsuo Handa int i; 120131845e8cSTetsuo Handa unsigned long min = ptr->values[0]; 120231845e8cSTetsuo Handa const unsigned long max = ptr->values[1]; 120331845e8cSTetsuo Handa u8 min_type = ptr->min_type; 120431845e8cSTetsuo Handa const u8 max_type = ptr->max_type; 120531845e8cSTetsuo Handa memset(buffer, 0, buffer_len); 120631845e8cSTetsuo Handa buffer_len -= 2; 120731845e8cSTetsuo Handa for (i = 0; i < 2; i++) { 120831845e8cSTetsuo Handa int len; 120931845e8cSTetsuo Handa switch (min_type) { 121031845e8cSTetsuo Handa case TOMOYO_VALUE_TYPE_HEXADECIMAL: 121131845e8cSTetsuo Handa snprintf(buffer, buffer_len, "0x%lX", min); 121231845e8cSTetsuo Handa break; 121331845e8cSTetsuo Handa case TOMOYO_VALUE_TYPE_OCTAL: 121431845e8cSTetsuo Handa snprintf(buffer, buffer_len, "0%lo", min); 121531845e8cSTetsuo Handa break; 121631845e8cSTetsuo Handa default: 121731845e8cSTetsuo Handa snprintf(buffer, buffer_len, "%lu", min); 121831845e8cSTetsuo Handa break; 121931845e8cSTetsuo Handa } 122031845e8cSTetsuo Handa if (min == max && min_type == max_type) 122131845e8cSTetsuo Handa break; 122231845e8cSTetsuo Handa len = strlen(buffer); 122331845e8cSTetsuo Handa buffer[len++] = '-'; 122431845e8cSTetsuo Handa buffer += len; 122531845e8cSTetsuo Handa buffer_len -= len; 122631845e8cSTetsuo Handa min_type = max_type; 122731845e8cSTetsuo Handa min = max; 122831845e8cSTetsuo Handa } 122931845e8cSTetsuo Handa } 123031845e8cSTetsuo Handa 123131845e8cSTetsuo Handa static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = { 123231845e8cSTetsuo Handa [TOMOYO_PATH_GROUP] = TOMOYO_KEYWORD_PATH_GROUP, 123331845e8cSTetsuo Handa [TOMOYO_NUMBER_GROUP] = TOMOYO_KEYWORD_NUMBER_GROUP 123431845e8cSTetsuo Handa }; 123531845e8cSTetsuo Handa 123631845e8cSTetsuo Handa /** 123731845e8cSTetsuo Handa * tomoyo_read_group - Read "struct tomoyo_path_group"/"struct tomoyo_number_group" list. 123831845e8cSTetsuo Handa * 123931845e8cSTetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 124031845e8cSTetsuo Handa * @idx: Index number. 124131845e8cSTetsuo Handa * 124231845e8cSTetsuo Handa * Returns true on success, false otherwise. 124331845e8cSTetsuo Handa * 124431845e8cSTetsuo Handa * Caller holds tomoyo_read_lock(). 124531845e8cSTetsuo Handa */ 124631845e8cSTetsuo Handa static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) 124731845e8cSTetsuo Handa { 124831845e8cSTetsuo Handa struct list_head *gpos; 124931845e8cSTetsuo Handa struct list_head *mpos; 125031845e8cSTetsuo Handa const char *w[3] = { "", "", "" }; 125131845e8cSTetsuo Handa w[0] = tomoyo_group_name[idx]; 125231845e8cSTetsuo Handa list_for_each_cookie(gpos, head->read_var1, &tomoyo_group_list[idx]) { 125331845e8cSTetsuo Handa struct tomoyo_group *group = 125431845e8cSTetsuo Handa list_entry(gpos, struct tomoyo_group, list); 125531845e8cSTetsuo Handa w[1] = group->group_name->name; 125631845e8cSTetsuo Handa list_for_each_cookie(mpos, head->read_var2, 125731845e8cSTetsuo Handa &group->member_list) { 125831845e8cSTetsuo Handa char buffer[128]; 125931845e8cSTetsuo Handa struct tomoyo_acl_head *ptr = 126031845e8cSTetsuo Handa list_entry(mpos, struct tomoyo_acl_head, list); 126131845e8cSTetsuo Handa if (ptr->is_deleted) 126231845e8cSTetsuo Handa continue; 126331845e8cSTetsuo Handa if (idx == TOMOYO_PATH_GROUP) { 126431845e8cSTetsuo Handa w[2] = container_of(ptr, 126531845e8cSTetsuo Handa struct tomoyo_path_group, 126631845e8cSTetsuo Handa head)->member_name->name; 126731845e8cSTetsuo Handa } else if (idx == TOMOYO_NUMBER_GROUP) { 126831845e8cSTetsuo Handa tomoyo_print_number(buffer, sizeof(buffer), 126931845e8cSTetsuo Handa &container_of 127031845e8cSTetsuo Handa (ptr, struct 127131845e8cSTetsuo Handa tomoyo_number_group, 127231845e8cSTetsuo Handa head)->number); 127331845e8cSTetsuo Handa w[2] = buffer; 127431845e8cSTetsuo Handa } 127531845e8cSTetsuo Handa if (!tomoyo_io_printf(head, "%s%s %s\n", w[0], w[1], 127631845e8cSTetsuo Handa w[2])) 127731845e8cSTetsuo Handa return false; 127831845e8cSTetsuo Handa } 127931845e8cSTetsuo Handa } 128031845e8cSTetsuo Handa return true; 128131845e8cSTetsuo Handa } 128231845e8cSTetsuo Handa 128331845e8cSTetsuo Handa /** 128431845e8cSTetsuo Handa * tomoyo_read_policy - Read "struct tomoyo_..._entry" list. 128531845e8cSTetsuo Handa * 128631845e8cSTetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 128731845e8cSTetsuo Handa * @idx: Index number. 128831845e8cSTetsuo Handa * 128931845e8cSTetsuo Handa * Returns true on success, false otherwise. 129031845e8cSTetsuo Handa * 129131845e8cSTetsuo Handa * Caller holds tomoyo_read_lock(). 129231845e8cSTetsuo Handa */ 129331845e8cSTetsuo Handa static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) 129431845e8cSTetsuo Handa { 129531845e8cSTetsuo Handa struct list_head *pos; 129631845e8cSTetsuo Handa list_for_each_cookie(pos, head->read_var2, &tomoyo_policy_list[idx]) { 129731845e8cSTetsuo Handa const char *w[4] = { "", "", "", "" }; 129831845e8cSTetsuo Handa struct tomoyo_acl_head *acl = container_of(pos, typeof(*acl), 129931845e8cSTetsuo Handa list); 130031845e8cSTetsuo Handa if (acl->is_deleted) 130131845e8cSTetsuo Handa continue; 130231845e8cSTetsuo Handa switch (idx) { 1303*5448ec4fSTetsuo Handa case TOMOYO_ID_TRANSITION_CONTROL: 130431845e8cSTetsuo Handa { 1305*5448ec4fSTetsuo Handa struct tomoyo_transition_control *ptr = 130631845e8cSTetsuo Handa container_of(acl, typeof(*ptr), head); 1307*5448ec4fSTetsuo Handa w[0] = tomoyo_transition_type[ptr->type]; 1308*5448ec4fSTetsuo Handa if (ptr->program) 130931845e8cSTetsuo Handa w[1] = ptr->program->name; 1310*5448ec4fSTetsuo Handa if (ptr->domainname) 131131845e8cSTetsuo Handa w[3] = ptr->domainname->name; 1312*5448ec4fSTetsuo Handa if (w[1][0] && w[3][0]) 131331845e8cSTetsuo Handa w[2] = " from "; 131431845e8cSTetsuo Handa } 131531845e8cSTetsuo Handa break; 131631845e8cSTetsuo Handa case TOMOYO_ID_GLOBALLY_READABLE: 131731845e8cSTetsuo Handa { 131831845e8cSTetsuo Handa struct tomoyo_globally_readable_file_entry *ptr 131931845e8cSTetsuo Handa = container_of(acl, typeof(*ptr), head); 132031845e8cSTetsuo Handa w[0] = TOMOYO_KEYWORD_ALLOW_READ; 132131845e8cSTetsuo Handa w[1] = ptr->filename->name; 132231845e8cSTetsuo Handa } 132331845e8cSTetsuo Handa break; 132431845e8cSTetsuo Handa case TOMOYO_ID_AGGREGATOR: 132531845e8cSTetsuo Handa { 132631845e8cSTetsuo Handa struct tomoyo_aggregator_entry *ptr = 132731845e8cSTetsuo Handa container_of(acl, typeof(*ptr), head); 132831845e8cSTetsuo Handa w[0] = TOMOYO_KEYWORD_AGGREGATOR; 132931845e8cSTetsuo Handa w[1] = ptr->original_name->name; 133031845e8cSTetsuo Handa w[2] = " "; 133131845e8cSTetsuo Handa w[3] = ptr->aggregated_name->name; 133231845e8cSTetsuo Handa } 133331845e8cSTetsuo Handa break; 133431845e8cSTetsuo Handa case TOMOYO_ID_PATTERN: 133531845e8cSTetsuo Handa { 133631845e8cSTetsuo Handa struct tomoyo_pattern_entry *ptr = 133731845e8cSTetsuo Handa container_of(acl, typeof(*ptr), head); 133831845e8cSTetsuo Handa w[0] = TOMOYO_KEYWORD_FILE_PATTERN; 133931845e8cSTetsuo Handa w[1] = ptr->pattern->name; 134031845e8cSTetsuo Handa } 134131845e8cSTetsuo Handa break; 134231845e8cSTetsuo Handa case TOMOYO_ID_NO_REWRITE: 134331845e8cSTetsuo Handa { 134431845e8cSTetsuo Handa struct tomoyo_no_rewrite_entry *ptr = 134531845e8cSTetsuo Handa container_of(acl, typeof(*ptr), head); 134631845e8cSTetsuo Handa w[0] = TOMOYO_KEYWORD_DENY_REWRITE; 134731845e8cSTetsuo Handa w[1] = ptr->pattern->name; 134831845e8cSTetsuo Handa } 134931845e8cSTetsuo Handa break; 135031845e8cSTetsuo Handa default: 135131845e8cSTetsuo Handa continue; 135231845e8cSTetsuo Handa } 135331845e8cSTetsuo Handa if (!tomoyo_io_printf(head, "%s%s%s%s\n", w[0], w[1], w[2], 135431845e8cSTetsuo Handa w[3])) 135531845e8cSTetsuo Handa return false; 135631845e8cSTetsuo Handa } 135731845e8cSTetsuo Handa return true; 135831845e8cSTetsuo Handa } 135931845e8cSTetsuo Handa 13609590837bSKentaro Takeda /** 13619590837bSKentaro Takeda * tomoyo_read_exception_policy - Read exception policy. 13629590837bSKentaro Takeda * 13639590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 13649590837bSKentaro Takeda * 1365fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 13669590837bSKentaro Takeda */ 13678fbe71f0STetsuo Handa static void tomoyo_read_exception_policy(struct tomoyo_io_buffer *head) 13689590837bSKentaro Takeda { 136931845e8cSTetsuo Handa if (head->read_eof) 137031845e8cSTetsuo Handa return; 137131845e8cSTetsuo Handa while (head->read_step < TOMOYO_MAX_POLICY && 137231845e8cSTetsuo Handa tomoyo_read_policy(head, head->read_step)) 137331845e8cSTetsuo Handa head->read_step++; 137431845e8cSTetsuo Handa if (head->read_step < TOMOYO_MAX_POLICY) 137531845e8cSTetsuo Handa return; 137631845e8cSTetsuo Handa while (head->read_step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP && 137731845e8cSTetsuo Handa tomoyo_read_group(head, head->read_step - TOMOYO_MAX_POLICY)) 137831845e8cSTetsuo Handa head->read_step++; 137931845e8cSTetsuo Handa if (head->read_step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP) 138031845e8cSTetsuo Handa return; 13819590837bSKentaro Takeda head->read_eof = true; 13829590837bSKentaro Takeda } 13839590837bSKentaro Takeda 13849590837bSKentaro Takeda /** 138517fcfbd9STetsuo Handa * tomoyo_print_header - Get header line of audit log. 138617fcfbd9STetsuo Handa * 138717fcfbd9STetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 138817fcfbd9STetsuo Handa * 138917fcfbd9STetsuo Handa * Returns string representation. 139017fcfbd9STetsuo Handa * 139117fcfbd9STetsuo Handa * This function uses kmalloc(), so caller must kfree() if this function 139217fcfbd9STetsuo Handa * didn't return NULL. 139317fcfbd9STetsuo Handa */ 139417fcfbd9STetsuo Handa static char *tomoyo_print_header(struct tomoyo_request_info *r) 139517fcfbd9STetsuo Handa { 139617fcfbd9STetsuo Handa static const char *tomoyo_mode_4[4] = { 139717fcfbd9STetsuo Handa "disabled", "learning", "permissive", "enforcing" 139817fcfbd9STetsuo Handa }; 139917fcfbd9STetsuo Handa struct timeval tv; 140017fcfbd9STetsuo Handa const pid_t gpid = task_pid_nr(current); 140117fcfbd9STetsuo Handa static const int tomoyo_buffer_len = 4096; 140217fcfbd9STetsuo Handa char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS); 140317fcfbd9STetsuo Handa if (!buffer) 140417fcfbd9STetsuo Handa return NULL; 140517fcfbd9STetsuo Handa do_gettimeofday(&tv); 140617fcfbd9STetsuo Handa snprintf(buffer, tomoyo_buffer_len - 1, 140717fcfbd9STetsuo Handa "#timestamp=%lu profile=%u mode=%s (global-pid=%u)" 140817fcfbd9STetsuo Handa " task={ pid=%u ppid=%u uid=%u gid=%u euid=%u" 140917fcfbd9STetsuo Handa " egid=%u suid=%u sgid=%u fsuid=%u fsgid=%u }", 141017fcfbd9STetsuo Handa tv.tv_sec, r->profile, tomoyo_mode_4[r->mode], gpid, 141117fcfbd9STetsuo Handa (pid_t) sys_getpid(), (pid_t) sys_getppid(), 141217fcfbd9STetsuo Handa current_uid(), current_gid(), current_euid(), 141317fcfbd9STetsuo Handa current_egid(), current_suid(), current_sgid(), 141417fcfbd9STetsuo Handa current_fsuid(), current_fsgid()); 141517fcfbd9STetsuo Handa return buffer; 141617fcfbd9STetsuo Handa } 141717fcfbd9STetsuo Handa 141817fcfbd9STetsuo Handa /** 141917fcfbd9STetsuo Handa * tomoyo_init_audit_log - Allocate buffer for audit logs. 142017fcfbd9STetsuo Handa * 142117fcfbd9STetsuo Handa * @len: Required size. 142217fcfbd9STetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 142317fcfbd9STetsuo Handa * 142417fcfbd9STetsuo Handa * Returns pointer to allocated memory. 142517fcfbd9STetsuo Handa * 142617fcfbd9STetsuo Handa * The @len is updated to add the header lines' size on success. 142717fcfbd9STetsuo Handa * 142817fcfbd9STetsuo Handa * This function uses kzalloc(), so caller must kfree() if this function 142917fcfbd9STetsuo Handa * didn't return NULL. 143017fcfbd9STetsuo Handa */ 143117fcfbd9STetsuo Handa static char *tomoyo_init_audit_log(int *len, struct tomoyo_request_info *r) 143217fcfbd9STetsuo Handa { 143317fcfbd9STetsuo Handa char *buf = NULL; 143417fcfbd9STetsuo Handa const char *header; 143517fcfbd9STetsuo Handa const char *domainname; 143617fcfbd9STetsuo Handa if (!r->domain) 143717fcfbd9STetsuo Handa r->domain = tomoyo_domain(); 143817fcfbd9STetsuo Handa domainname = r->domain->domainname->name; 143917fcfbd9STetsuo Handa header = tomoyo_print_header(r); 144017fcfbd9STetsuo Handa if (!header) 144117fcfbd9STetsuo Handa return NULL; 144217fcfbd9STetsuo Handa *len += strlen(domainname) + strlen(header) + 10; 144317fcfbd9STetsuo Handa buf = kzalloc(*len, GFP_NOFS); 144417fcfbd9STetsuo Handa if (buf) 144517fcfbd9STetsuo Handa snprintf(buf, (*len) - 1, "%s\n%s\n", header, domainname); 144617fcfbd9STetsuo Handa kfree(header); 144717fcfbd9STetsuo Handa return buf; 144817fcfbd9STetsuo Handa } 144917fcfbd9STetsuo Handa 145017fcfbd9STetsuo Handa /* Wait queue for tomoyo_query_list. */ 145117fcfbd9STetsuo Handa static DECLARE_WAIT_QUEUE_HEAD(tomoyo_query_wait); 145217fcfbd9STetsuo Handa 145317fcfbd9STetsuo Handa /* Lock for manipulating tomoyo_query_list. */ 145417fcfbd9STetsuo Handa static DEFINE_SPINLOCK(tomoyo_query_list_lock); 145517fcfbd9STetsuo Handa 145617fcfbd9STetsuo Handa /* Structure for query. */ 145717fcfbd9STetsuo Handa struct tomoyo_query_entry { 145817fcfbd9STetsuo Handa struct list_head list; 145917fcfbd9STetsuo Handa char *query; 146017fcfbd9STetsuo Handa int query_len; 146117fcfbd9STetsuo Handa unsigned int serial; 146217fcfbd9STetsuo Handa int timer; 146317fcfbd9STetsuo Handa int answer; 146417fcfbd9STetsuo Handa }; 146517fcfbd9STetsuo Handa 146617fcfbd9STetsuo Handa /* The list for "struct tomoyo_query_entry". */ 146717fcfbd9STetsuo Handa static LIST_HEAD(tomoyo_query_list); 146817fcfbd9STetsuo Handa 146917fcfbd9STetsuo Handa /* 147017fcfbd9STetsuo Handa * Number of "struct file" referring /sys/kernel/security/tomoyo/query 147117fcfbd9STetsuo Handa * interface. 147217fcfbd9STetsuo Handa */ 147317fcfbd9STetsuo Handa static atomic_t tomoyo_query_observers = ATOMIC_INIT(0); 147417fcfbd9STetsuo Handa 147517fcfbd9STetsuo Handa /** 147617fcfbd9STetsuo Handa * tomoyo_supervisor - Ask for the supervisor's decision. 147717fcfbd9STetsuo Handa * 147817fcfbd9STetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 147917fcfbd9STetsuo Handa * @fmt: The printf()'s format string, followed by parameters. 148017fcfbd9STetsuo Handa * 148117fcfbd9STetsuo Handa * Returns 0 if the supervisor decided to permit the access request which 148217fcfbd9STetsuo Handa * violated the policy in enforcing mode, TOMOYO_RETRY_REQUEST if the 148317fcfbd9STetsuo Handa * supervisor decided to retry the access request which violated the policy in 148417fcfbd9STetsuo Handa * enforcing mode, 0 if it is not in enforcing mode, -EPERM otherwise. 148517fcfbd9STetsuo Handa */ 148617fcfbd9STetsuo Handa int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) 148717fcfbd9STetsuo Handa { 148817fcfbd9STetsuo Handa va_list args; 148917fcfbd9STetsuo Handa int error = -EPERM; 149017fcfbd9STetsuo Handa int pos; 149117fcfbd9STetsuo Handa int len; 149217fcfbd9STetsuo Handa static unsigned int tomoyo_serial; 149317fcfbd9STetsuo Handa struct tomoyo_query_entry *tomoyo_query_entry = NULL; 149417fcfbd9STetsuo Handa bool quota_exceeded = false; 149517fcfbd9STetsuo Handa char *header; 149617fcfbd9STetsuo Handa switch (r->mode) { 149717fcfbd9STetsuo Handa char *buffer; 149817fcfbd9STetsuo Handa case TOMOYO_CONFIG_LEARNING: 149917fcfbd9STetsuo Handa if (!tomoyo_domain_quota_is_ok(r)) 150017fcfbd9STetsuo Handa return 0; 150117fcfbd9STetsuo Handa va_start(args, fmt); 150217fcfbd9STetsuo Handa len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 4; 150317fcfbd9STetsuo Handa va_end(args); 150417fcfbd9STetsuo Handa buffer = kmalloc(len, GFP_NOFS); 150517fcfbd9STetsuo Handa if (!buffer) 150617fcfbd9STetsuo Handa return 0; 150717fcfbd9STetsuo Handa va_start(args, fmt); 150817fcfbd9STetsuo Handa vsnprintf(buffer, len - 1, fmt, args); 150917fcfbd9STetsuo Handa va_end(args); 151017fcfbd9STetsuo Handa tomoyo_normalize_line(buffer); 151117fcfbd9STetsuo Handa tomoyo_write_domain_policy2(buffer, r->domain, false); 151217fcfbd9STetsuo Handa kfree(buffer); 151317fcfbd9STetsuo Handa /* fall through */ 151417fcfbd9STetsuo Handa case TOMOYO_CONFIG_PERMISSIVE: 151517fcfbd9STetsuo Handa return 0; 151617fcfbd9STetsuo Handa } 151717fcfbd9STetsuo Handa if (!r->domain) 151817fcfbd9STetsuo Handa r->domain = tomoyo_domain(); 151917fcfbd9STetsuo Handa if (!atomic_read(&tomoyo_query_observers)) 152017fcfbd9STetsuo Handa return -EPERM; 152117fcfbd9STetsuo Handa va_start(args, fmt); 152217fcfbd9STetsuo Handa len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 32; 152317fcfbd9STetsuo Handa va_end(args); 152417fcfbd9STetsuo Handa header = tomoyo_init_audit_log(&len, r); 152517fcfbd9STetsuo Handa if (!header) 152617fcfbd9STetsuo Handa goto out; 152717fcfbd9STetsuo Handa tomoyo_query_entry = kzalloc(sizeof(*tomoyo_query_entry), GFP_NOFS); 152817fcfbd9STetsuo Handa if (!tomoyo_query_entry) 152917fcfbd9STetsuo Handa goto out; 153017fcfbd9STetsuo Handa tomoyo_query_entry->query = kzalloc(len, GFP_NOFS); 153117fcfbd9STetsuo Handa if (!tomoyo_query_entry->query) 153217fcfbd9STetsuo Handa goto out; 153317fcfbd9STetsuo Handa len = ksize(tomoyo_query_entry->query); 153417fcfbd9STetsuo Handa INIT_LIST_HEAD(&tomoyo_query_entry->list); 153517fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 153617fcfbd9STetsuo Handa if (tomoyo_quota_for_query && tomoyo_query_memory_size + len + 153717fcfbd9STetsuo Handa sizeof(*tomoyo_query_entry) >= tomoyo_quota_for_query) { 153817fcfbd9STetsuo Handa quota_exceeded = true; 153917fcfbd9STetsuo Handa } else { 154017fcfbd9STetsuo Handa tomoyo_query_memory_size += len + sizeof(*tomoyo_query_entry); 154117fcfbd9STetsuo Handa tomoyo_query_entry->serial = tomoyo_serial++; 154217fcfbd9STetsuo Handa } 154317fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 154417fcfbd9STetsuo Handa if (quota_exceeded) 154517fcfbd9STetsuo Handa goto out; 154617fcfbd9STetsuo Handa pos = snprintf(tomoyo_query_entry->query, len - 1, "Q%u-%hu\n%s", 154717fcfbd9STetsuo Handa tomoyo_query_entry->serial, r->retry, header); 154817fcfbd9STetsuo Handa kfree(header); 154917fcfbd9STetsuo Handa header = NULL; 155017fcfbd9STetsuo Handa va_start(args, fmt); 155117fcfbd9STetsuo Handa vsnprintf(tomoyo_query_entry->query + pos, len - 1 - pos, fmt, args); 155217fcfbd9STetsuo Handa tomoyo_query_entry->query_len = strlen(tomoyo_query_entry->query) + 1; 155317fcfbd9STetsuo Handa va_end(args); 155417fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 155517fcfbd9STetsuo Handa list_add_tail(&tomoyo_query_entry->list, &tomoyo_query_list); 155617fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 155717fcfbd9STetsuo Handa /* Give 10 seconds for supervisor's opinion. */ 155817fcfbd9STetsuo Handa for (tomoyo_query_entry->timer = 0; 155917fcfbd9STetsuo Handa atomic_read(&tomoyo_query_observers) && tomoyo_query_entry->timer < 100; 156017fcfbd9STetsuo Handa tomoyo_query_entry->timer++) { 156117fcfbd9STetsuo Handa wake_up(&tomoyo_query_wait); 156217fcfbd9STetsuo Handa set_current_state(TASK_INTERRUPTIBLE); 156317fcfbd9STetsuo Handa schedule_timeout(HZ / 10); 156417fcfbd9STetsuo Handa if (tomoyo_query_entry->answer) 156517fcfbd9STetsuo Handa break; 156617fcfbd9STetsuo Handa } 156717fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 156817fcfbd9STetsuo Handa list_del(&tomoyo_query_entry->list); 156917fcfbd9STetsuo Handa tomoyo_query_memory_size -= len + sizeof(*tomoyo_query_entry); 157017fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 157117fcfbd9STetsuo Handa switch (tomoyo_query_entry->answer) { 157217fcfbd9STetsuo Handa case 3: /* Asked to retry by administrator. */ 157317fcfbd9STetsuo Handa error = TOMOYO_RETRY_REQUEST; 157417fcfbd9STetsuo Handa r->retry++; 157517fcfbd9STetsuo Handa break; 157617fcfbd9STetsuo Handa case 1: 157717fcfbd9STetsuo Handa /* Granted by administrator. */ 157817fcfbd9STetsuo Handa error = 0; 157917fcfbd9STetsuo Handa break; 158017fcfbd9STetsuo Handa case 0: 158117fcfbd9STetsuo Handa /* Timed out. */ 158217fcfbd9STetsuo Handa break; 158317fcfbd9STetsuo Handa default: 158417fcfbd9STetsuo Handa /* Rejected by administrator. */ 158517fcfbd9STetsuo Handa break; 158617fcfbd9STetsuo Handa } 158717fcfbd9STetsuo Handa out: 158817fcfbd9STetsuo Handa if (tomoyo_query_entry) 158917fcfbd9STetsuo Handa kfree(tomoyo_query_entry->query); 159017fcfbd9STetsuo Handa kfree(tomoyo_query_entry); 159117fcfbd9STetsuo Handa kfree(header); 159217fcfbd9STetsuo Handa return error; 159317fcfbd9STetsuo Handa } 159417fcfbd9STetsuo Handa 159517fcfbd9STetsuo Handa /** 159617fcfbd9STetsuo Handa * tomoyo_poll_query - poll() for /sys/kernel/security/tomoyo/query. 159717fcfbd9STetsuo Handa * 159817fcfbd9STetsuo Handa * @file: Pointer to "struct file". 159917fcfbd9STetsuo Handa * @wait: Pointer to "poll_table". 160017fcfbd9STetsuo Handa * 160117fcfbd9STetsuo Handa * Returns POLLIN | POLLRDNORM when ready to read, 0 otherwise. 160217fcfbd9STetsuo Handa * 160317fcfbd9STetsuo Handa * Waits for access requests which violated policy in enforcing mode. 160417fcfbd9STetsuo Handa */ 160517fcfbd9STetsuo Handa static int tomoyo_poll_query(struct file *file, poll_table *wait) 160617fcfbd9STetsuo Handa { 160717fcfbd9STetsuo Handa struct list_head *tmp; 160817fcfbd9STetsuo Handa bool found = false; 160917fcfbd9STetsuo Handa u8 i; 161017fcfbd9STetsuo Handa for (i = 0; i < 2; i++) { 161117fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 161217fcfbd9STetsuo Handa list_for_each(tmp, &tomoyo_query_list) { 161317fcfbd9STetsuo Handa struct tomoyo_query_entry *ptr 161417fcfbd9STetsuo Handa = list_entry(tmp, struct tomoyo_query_entry, 161517fcfbd9STetsuo Handa list); 161617fcfbd9STetsuo Handa if (ptr->answer) 161717fcfbd9STetsuo Handa continue; 161817fcfbd9STetsuo Handa found = true; 161917fcfbd9STetsuo Handa break; 162017fcfbd9STetsuo Handa } 162117fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 162217fcfbd9STetsuo Handa if (found) 162317fcfbd9STetsuo Handa return POLLIN | POLLRDNORM; 162417fcfbd9STetsuo Handa if (i) 162517fcfbd9STetsuo Handa break; 162617fcfbd9STetsuo Handa poll_wait(file, &tomoyo_query_wait, wait); 162717fcfbd9STetsuo Handa } 162817fcfbd9STetsuo Handa return 0; 162917fcfbd9STetsuo Handa } 163017fcfbd9STetsuo Handa 163117fcfbd9STetsuo Handa /** 163217fcfbd9STetsuo Handa * tomoyo_read_query - Read access requests which violated policy in enforcing mode. 163317fcfbd9STetsuo Handa * 163417fcfbd9STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 163517fcfbd9STetsuo Handa */ 16368fbe71f0STetsuo Handa static void tomoyo_read_query(struct tomoyo_io_buffer *head) 163717fcfbd9STetsuo Handa { 163817fcfbd9STetsuo Handa struct list_head *tmp; 163917fcfbd9STetsuo Handa int pos = 0; 164017fcfbd9STetsuo Handa int len = 0; 164117fcfbd9STetsuo Handa char *buf; 164217fcfbd9STetsuo Handa if (head->read_avail) 16438fbe71f0STetsuo Handa return; 164417fcfbd9STetsuo Handa if (head->read_buf) { 164517fcfbd9STetsuo Handa kfree(head->read_buf); 164617fcfbd9STetsuo Handa head->read_buf = NULL; 164717fcfbd9STetsuo Handa head->readbuf_size = 0; 164817fcfbd9STetsuo Handa } 164917fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 165017fcfbd9STetsuo Handa list_for_each(tmp, &tomoyo_query_list) { 165117fcfbd9STetsuo Handa struct tomoyo_query_entry *ptr 165217fcfbd9STetsuo Handa = list_entry(tmp, struct tomoyo_query_entry, list); 165317fcfbd9STetsuo Handa if (ptr->answer) 165417fcfbd9STetsuo Handa continue; 165517fcfbd9STetsuo Handa if (pos++ != head->read_step) 165617fcfbd9STetsuo Handa continue; 165717fcfbd9STetsuo Handa len = ptr->query_len; 165817fcfbd9STetsuo Handa break; 165917fcfbd9STetsuo Handa } 166017fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 166117fcfbd9STetsuo Handa if (!len) { 166217fcfbd9STetsuo Handa head->read_step = 0; 16638fbe71f0STetsuo Handa return; 166417fcfbd9STetsuo Handa } 166517fcfbd9STetsuo Handa buf = kzalloc(len, GFP_NOFS); 166617fcfbd9STetsuo Handa if (!buf) 16678fbe71f0STetsuo Handa return; 166817fcfbd9STetsuo Handa pos = 0; 166917fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 167017fcfbd9STetsuo Handa list_for_each(tmp, &tomoyo_query_list) { 167117fcfbd9STetsuo Handa struct tomoyo_query_entry *ptr 167217fcfbd9STetsuo Handa = list_entry(tmp, struct tomoyo_query_entry, list); 167317fcfbd9STetsuo Handa if (ptr->answer) 167417fcfbd9STetsuo Handa continue; 167517fcfbd9STetsuo Handa if (pos++ != head->read_step) 167617fcfbd9STetsuo Handa continue; 167717fcfbd9STetsuo Handa /* 167817fcfbd9STetsuo Handa * Some query can be skipped because tomoyo_query_list 167917fcfbd9STetsuo Handa * can change, but I don't care. 168017fcfbd9STetsuo Handa */ 168117fcfbd9STetsuo Handa if (len == ptr->query_len) 168217fcfbd9STetsuo Handa memmove(buf, ptr->query, len); 168317fcfbd9STetsuo Handa break; 168417fcfbd9STetsuo Handa } 168517fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 168617fcfbd9STetsuo Handa if (buf[0]) { 168717fcfbd9STetsuo Handa head->read_avail = len; 168817fcfbd9STetsuo Handa head->readbuf_size = head->read_avail; 168917fcfbd9STetsuo Handa head->read_buf = buf; 169017fcfbd9STetsuo Handa head->read_step++; 169117fcfbd9STetsuo Handa } else { 169217fcfbd9STetsuo Handa kfree(buf); 169317fcfbd9STetsuo Handa } 169417fcfbd9STetsuo Handa } 169517fcfbd9STetsuo Handa 169617fcfbd9STetsuo Handa /** 169717fcfbd9STetsuo Handa * tomoyo_write_answer - Write the supervisor's decision. 169817fcfbd9STetsuo Handa * 169917fcfbd9STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 170017fcfbd9STetsuo Handa * 170117fcfbd9STetsuo Handa * Returns 0 on success, -EINVAL otherwise. 170217fcfbd9STetsuo Handa */ 170317fcfbd9STetsuo Handa static int tomoyo_write_answer(struct tomoyo_io_buffer *head) 170417fcfbd9STetsuo Handa { 170517fcfbd9STetsuo Handa char *data = head->write_buf; 170617fcfbd9STetsuo Handa struct list_head *tmp; 170717fcfbd9STetsuo Handa unsigned int serial; 170817fcfbd9STetsuo Handa unsigned int answer; 170917fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 171017fcfbd9STetsuo Handa list_for_each(tmp, &tomoyo_query_list) { 171117fcfbd9STetsuo Handa struct tomoyo_query_entry *ptr 171217fcfbd9STetsuo Handa = list_entry(tmp, struct tomoyo_query_entry, list); 171317fcfbd9STetsuo Handa ptr->timer = 0; 171417fcfbd9STetsuo Handa } 171517fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 171617fcfbd9STetsuo Handa if (sscanf(data, "A%u=%u", &serial, &answer) != 2) 171717fcfbd9STetsuo Handa return -EINVAL; 171817fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 171917fcfbd9STetsuo Handa list_for_each(tmp, &tomoyo_query_list) { 172017fcfbd9STetsuo Handa struct tomoyo_query_entry *ptr 172117fcfbd9STetsuo Handa = list_entry(tmp, struct tomoyo_query_entry, list); 172217fcfbd9STetsuo Handa if (ptr->serial != serial) 172317fcfbd9STetsuo Handa continue; 172417fcfbd9STetsuo Handa if (!ptr->answer) 172517fcfbd9STetsuo Handa ptr->answer = answer; 172617fcfbd9STetsuo Handa break; 172717fcfbd9STetsuo Handa } 172817fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 172917fcfbd9STetsuo Handa return 0; 173017fcfbd9STetsuo Handa } 173117fcfbd9STetsuo Handa 173217fcfbd9STetsuo Handa /** 17339590837bSKentaro Takeda * tomoyo_read_version: Get version. 17349590837bSKentaro Takeda * 17359590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 17369590837bSKentaro Takeda * 17379590837bSKentaro Takeda * Returns version information. 17389590837bSKentaro Takeda */ 17398fbe71f0STetsuo Handa static void tomoyo_read_version(struct tomoyo_io_buffer *head) 17409590837bSKentaro Takeda { 17419590837bSKentaro Takeda if (!head->read_eof) { 174257c2590fSTetsuo Handa tomoyo_io_printf(head, "2.3.0-pre"); 17439590837bSKentaro Takeda head->read_eof = true; 17449590837bSKentaro Takeda } 17459590837bSKentaro Takeda } 17469590837bSKentaro Takeda 17479590837bSKentaro Takeda /** 17489590837bSKentaro Takeda * tomoyo_read_self_domain - Get the current process's domainname. 17499590837bSKentaro Takeda * 17509590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 17519590837bSKentaro Takeda * 17529590837bSKentaro Takeda * Returns the current process's domainname. 17539590837bSKentaro Takeda */ 17548fbe71f0STetsuo Handa static void tomoyo_read_self_domain(struct tomoyo_io_buffer *head) 17559590837bSKentaro Takeda { 17569590837bSKentaro Takeda if (!head->read_eof) { 17579590837bSKentaro Takeda /* 17589590837bSKentaro Takeda * tomoyo_domain()->domainname != NULL 17599590837bSKentaro Takeda * because every process belongs to a domain and 17609590837bSKentaro Takeda * the domain's name cannot be NULL. 17619590837bSKentaro Takeda */ 17629590837bSKentaro Takeda tomoyo_io_printf(head, "%s", tomoyo_domain()->domainname->name); 17639590837bSKentaro Takeda head->read_eof = true; 17649590837bSKentaro Takeda } 17659590837bSKentaro Takeda } 17669590837bSKentaro Takeda 17679590837bSKentaro Takeda /** 17689590837bSKentaro Takeda * tomoyo_open_control - open() for /sys/kernel/security/tomoyo/ interface. 17699590837bSKentaro Takeda * 17709590837bSKentaro Takeda * @type: Type of interface. 17719590837bSKentaro Takeda * @file: Pointer to "struct file". 17729590837bSKentaro Takeda * 17739590837bSKentaro Takeda * Associates policy handler and returns 0 on success, -ENOMEM otherwise. 1774fdb8ebb7STetsuo Handa * 1775fdb8ebb7STetsuo Handa * Caller acquires tomoyo_read_lock(). 17769590837bSKentaro Takeda */ 1777c3ef1500STetsuo Handa int tomoyo_open_control(const u8 type, struct file *file) 17789590837bSKentaro Takeda { 17794e5d6f7eSTetsuo Handa struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_NOFS); 17809590837bSKentaro Takeda 17819590837bSKentaro Takeda if (!head) 17829590837bSKentaro Takeda return -ENOMEM; 17839590837bSKentaro Takeda mutex_init(&head->io_sem); 178417fcfbd9STetsuo Handa head->type = type; 17859590837bSKentaro Takeda switch (type) { 17869590837bSKentaro Takeda case TOMOYO_DOMAINPOLICY: 17879590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/domain_policy */ 17889590837bSKentaro Takeda head->write = tomoyo_write_domain_policy; 17899590837bSKentaro Takeda head->read = tomoyo_read_domain_policy; 17909590837bSKentaro Takeda break; 17919590837bSKentaro Takeda case TOMOYO_EXCEPTIONPOLICY: 17929590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/exception_policy */ 17939590837bSKentaro Takeda head->write = tomoyo_write_exception_policy; 17949590837bSKentaro Takeda head->read = tomoyo_read_exception_policy; 17959590837bSKentaro Takeda break; 17969590837bSKentaro Takeda case TOMOYO_SELFDOMAIN: 17979590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/self_domain */ 17989590837bSKentaro Takeda head->read = tomoyo_read_self_domain; 17999590837bSKentaro Takeda break; 18009590837bSKentaro Takeda case TOMOYO_DOMAIN_STATUS: 18019590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/.domain_status */ 18029590837bSKentaro Takeda head->write = tomoyo_write_domain_profile; 18039590837bSKentaro Takeda head->read = tomoyo_read_domain_profile; 18049590837bSKentaro Takeda break; 18059590837bSKentaro Takeda case TOMOYO_PROCESS_STATUS: 18069590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/.process_status */ 18079590837bSKentaro Takeda head->write = tomoyo_write_pid; 18089590837bSKentaro Takeda head->read = tomoyo_read_pid; 18099590837bSKentaro Takeda break; 18109590837bSKentaro Takeda case TOMOYO_VERSION: 18119590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/version */ 18129590837bSKentaro Takeda head->read = tomoyo_read_version; 18139590837bSKentaro Takeda head->readbuf_size = 128; 18149590837bSKentaro Takeda break; 18159590837bSKentaro Takeda case TOMOYO_MEMINFO: 18169590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/meminfo */ 18179590837bSKentaro Takeda head->write = tomoyo_write_memory_quota; 18189590837bSKentaro Takeda head->read = tomoyo_read_memory_counter; 18199590837bSKentaro Takeda head->readbuf_size = 512; 18209590837bSKentaro Takeda break; 18219590837bSKentaro Takeda case TOMOYO_PROFILE: 18229590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/profile */ 18239590837bSKentaro Takeda head->write = tomoyo_write_profile; 18249590837bSKentaro Takeda head->read = tomoyo_read_profile; 18259590837bSKentaro Takeda break; 182617fcfbd9STetsuo Handa case TOMOYO_QUERY: /* /sys/kernel/security/tomoyo/query */ 182717fcfbd9STetsuo Handa head->poll = tomoyo_poll_query; 182817fcfbd9STetsuo Handa head->write = tomoyo_write_answer; 182917fcfbd9STetsuo Handa head->read = tomoyo_read_query; 183017fcfbd9STetsuo Handa break; 18319590837bSKentaro Takeda case TOMOYO_MANAGER: 18329590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/manager */ 18339590837bSKentaro Takeda head->write = tomoyo_write_manager_policy; 18349590837bSKentaro Takeda head->read = tomoyo_read_manager_policy; 18359590837bSKentaro Takeda break; 18369590837bSKentaro Takeda } 18379590837bSKentaro Takeda if (!(file->f_mode & FMODE_READ)) { 18389590837bSKentaro Takeda /* 18399590837bSKentaro Takeda * No need to allocate read_buf since it is not opened 18409590837bSKentaro Takeda * for reading. 18419590837bSKentaro Takeda */ 18429590837bSKentaro Takeda head->read = NULL; 184317fcfbd9STetsuo Handa head->poll = NULL; 184417fcfbd9STetsuo Handa } else if (!head->poll) { 184517fcfbd9STetsuo Handa /* Don't allocate read_buf for poll() access. */ 18469590837bSKentaro Takeda if (!head->readbuf_size) 18479590837bSKentaro Takeda head->readbuf_size = 4096 * 2; 18484e5d6f7eSTetsuo Handa head->read_buf = kzalloc(head->readbuf_size, GFP_NOFS); 18499590837bSKentaro Takeda if (!head->read_buf) { 18508e2d39a1STetsuo Handa kfree(head); 18519590837bSKentaro Takeda return -ENOMEM; 18529590837bSKentaro Takeda } 18539590837bSKentaro Takeda } 18549590837bSKentaro Takeda if (!(file->f_mode & FMODE_WRITE)) { 18559590837bSKentaro Takeda /* 18569590837bSKentaro Takeda * No need to allocate write_buf since it is not opened 18579590837bSKentaro Takeda * for writing. 18589590837bSKentaro Takeda */ 18599590837bSKentaro Takeda head->write = NULL; 18609590837bSKentaro Takeda } else if (head->write) { 18619590837bSKentaro Takeda head->writebuf_size = 4096 * 2; 18624e5d6f7eSTetsuo Handa head->write_buf = kzalloc(head->writebuf_size, GFP_NOFS); 18639590837bSKentaro Takeda if (!head->write_buf) { 18648e2d39a1STetsuo Handa kfree(head->read_buf); 18658e2d39a1STetsuo Handa kfree(head); 18669590837bSKentaro Takeda return -ENOMEM; 18679590837bSKentaro Takeda } 18689590837bSKentaro Takeda } 186917fcfbd9STetsuo Handa if (type != TOMOYO_QUERY) 1870fdb8ebb7STetsuo Handa head->reader_idx = tomoyo_read_lock(); 18719590837bSKentaro Takeda file->private_data = head; 18729590837bSKentaro Takeda /* 18739590837bSKentaro Takeda * Call the handler now if the file is 18749590837bSKentaro Takeda * /sys/kernel/security/tomoyo/self_domain 18759590837bSKentaro Takeda * so that the user can use 18769590837bSKentaro Takeda * cat < /sys/kernel/security/tomoyo/self_domain" 18779590837bSKentaro Takeda * to know the current process's domainname. 18789590837bSKentaro Takeda */ 18799590837bSKentaro Takeda if (type == TOMOYO_SELFDOMAIN) 18809590837bSKentaro Takeda tomoyo_read_control(file, NULL, 0); 188117fcfbd9STetsuo Handa /* 188217fcfbd9STetsuo Handa * If the file is /sys/kernel/security/tomoyo/query , increment the 188317fcfbd9STetsuo Handa * observer counter. 188417fcfbd9STetsuo Handa * The obserber counter is used by tomoyo_supervisor() to see if 188517fcfbd9STetsuo Handa * there is some process monitoring /sys/kernel/security/tomoyo/query. 188617fcfbd9STetsuo Handa */ 188717fcfbd9STetsuo Handa else if (type == TOMOYO_QUERY) 188817fcfbd9STetsuo Handa atomic_inc(&tomoyo_query_observers); 18899590837bSKentaro Takeda return 0; 18909590837bSKentaro Takeda } 18919590837bSKentaro Takeda 18929590837bSKentaro Takeda /** 189317fcfbd9STetsuo Handa * tomoyo_poll_control - poll() for /sys/kernel/security/tomoyo/ interface. 189417fcfbd9STetsuo Handa * 189517fcfbd9STetsuo Handa * @file: Pointer to "struct file". 189617fcfbd9STetsuo Handa * @wait: Pointer to "poll_table". 189717fcfbd9STetsuo Handa * 189817fcfbd9STetsuo Handa * Waits for read readiness. 189917fcfbd9STetsuo Handa * /sys/kernel/security/tomoyo/query is handled by /usr/sbin/tomoyo-queryd . 190017fcfbd9STetsuo Handa */ 190117fcfbd9STetsuo Handa int tomoyo_poll_control(struct file *file, poll_table *wait) 190217fcfbd9STetsuo Handa { 190317fcfbd9STetsuo Handa struct tomoyo_io_buffer *head = file->private_data; 190417fcfbd9STetsuo Handa if (!head->poll) 190517fcfbd9STetsuo Handa return -ENOSYS; 190617fcfbd9STetsuo Handa return head->poll(file, wait); 190717fcfbd9STetsuo Handa } 190817fcfbd9STetsuo Handa 190917fcfbd9STetsuo Handa /** 19109590837bSKentaro Takeda * tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface. 19119590837bSKentaro Takeda * 19129590837bSKentaro Takeda * @file: Pointer to "struct file". 19139590837bSKentaro Takeda * @buffer: Poiner to buffer to write to. 19149590837bSKentaro Takeda * @buffer_len: Size of @buffer. 19159590837bSKentaro Takeda * 19169590837bSKentaro Takeda * Returns bytes read on success, negative value otherwise. 1917fdb8ebb7STetsuo Handa * 1918fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 19199590837bSKentaro Takeda */ 1920c3ef1500STetsuo Handa int tomoyo_read_control(struct file *file, char __user *buffer, 19219590837bSKentaro Takeda const int buffer_len) 19229590837bSKentaro Takeda { 19239590837bSKentaro Takeda int len = 0; 19249590837bSKentaro Takeda struct tomoyo_io_buffer *head = file->private_data; 19259590837bSKentaro Takeda char *cp; 19269590837bSKentaro Takeda 19279590837bSKentaro Takeda if (!head->read) 19289590837bSKentaro Takeda return -ENOSYS; 19299590837bSKentaro Takeda if (mutex_lock_interruptible(&head->io_sem)) 19309590837bSKentaro Takeda return -EINTR; 19319590837bSKentaro Takeda /* Call the policy handler. */ 19328fbe71f0STetsuo Handa head->read(head); 19339590837bSKentaro Takeda if (len < 0) 19349590837bSKentaro Takeda goto out; 19359590837bSKentaro Takeda /* Write to buffer. */ 19369590837bSKentaro Takeda len = head->read_avail; 19379590837bSKentaro Takeda if (len > buffer_len) 19389590837bSKentaro Takeda len = buffer_len; 19399590837bSKentaro Takeda if (!len) 19409590837bSKentaro Takeda goto out; 19419590837bSKentaro Takeda /* head->read_buf changes by some functions. */ 19429590837bSKentaro Takeda cp = head->read_buf; 19439590837bSKentaro Takeda if (copy_to_user(buffer, cp, len)) { 19449590837bSKentaro Takeda len = -EFAULT; 19459590837bSKentaro Takeda goto out; 19469590837bSKentaro Takeda } 19479590837bSKentaro Takeda head->read_avail -= len; 19489590837bSKentaro Takeda memmove(cp, cp + len, head->read_avail); 19499590837bSKentaro Takeda out: 19509590837bSKentaro Takeda mutex_unlock(&head->io_sem); 19519590837bSKentaro Takeda return len; 19529590837bSKentaro Takeda } 19539590837bSKentaro Takeda 19549590837bSKentaro Takeda /** 19559590837bSKentaro Takeda * tomoyo_write_control - write() for /sys/kernel/security/tomoyo/ interface. 19569590837bSKentaro Takeda * 19579590837bSKentaro Takeda * @file: Pointer to "struct file". 19589590837bSKentaro Takeda * @buffer: Pointer to buffer to read from. 19599590837bSKentaro Takeda * @buffer_len: Size of @buffer. 19609590837bSKentaro Takeda * 19619590837bSKentaro Takeda * Returns @buffer_len on success, negative value otherwise. 1962fdb8ebb7STetsuo Handa * 1963fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 19649590837bSKentaro Takeda */ 1965c3ef1500STetsuo Handa int tomoyo_write_control(struct file *file, const char __user *buffer, 19669590837bSKentaro Takeda const int buffer_len) 19679590837bSKentaro Takeda { 19689590837bSKentaro Takeda struct tomoyo_io_buffer *head = file->private_data; 19699590837bSKentaro Takeda int error = buffer_len; 19709590837bSKentaro Takeda int avail_len = buffer_len; 19719590837bSKentaro Takeda char *cp0 = head->write_buf; 19729590837bSKentaro Takeda 19739590837bSKentaro Takeda if (!head->write) 19749590837bSKentaro Takeda return -ENOSYS; 19759590837bSKentaro Takeda if (!access_ok(VERIFY_READ, buffer, buffer_len)) 19769590837bSKentaro Takeda return -EFAULT; 19779590837bSKentaro Takeda /* Don't allow updating policies by non manager programs. */ 19789590837bSKentaro Takeda if (head->write != tomoyo_write_pid && 19799590837bSKentaro Takeda head->write != tomoyo_write_domain_policy && 198075093152STetsuo Handa !tomoyo_policy_manager()) 19819590837bSKentaro Takeda return -EPERM; 19829590837bSKentaro Takeda if (mutex_lock_interruptible(&head->io_sem)) 19839590837bSKentaro Takeda return -EINTR; 19849590837bSKentaro Takeda /* Read a line and dispatch it to the policy handler. */ 19859590837bSKentaro Takeda while (avail_len > 0) { 19869590837bSKentaro Takeda char c; 19879590837bSKentaro Takeda if (head->write_avail >= head->writebuf_size - 1) { 19889590837bSKentaro Takeda error = -ENOMEM; 19899590837bSKentaro Takeda break; 19909590837bSKentaro Takeda } else if (get_user(c, buffer)) { 19919590837bSKentaro Takeda error = -EFAULT; 19929590837bSKentaro Takeda break; 19939590837bSKentaro Takeda } 19949590837bSKentaro Takeda buffer++; 19959590837bSKentaro Takeda avail_len--; 19969590837bSKentaro Takeda cp0[head->write_avail++] = c; 19979590837bSKentaro Takeda if (c != '\n') 19989590837bSKentaro Takeda continue; 19999590837bSKentaro Takeda cp0[head->write_avail - 1] = '\0'; 20009590837bSKentaro Takeda head->write_avail = 0; 20019590837bSKentaro Takeda tomoyo_normalize_line(cp0); 20029590837bSKentaro Takeda head->write(head); 20039590837bSKentaro Takeda } 20049590837bSKentaro Takeda mutex_unlock(&head->io_sem); 20059590837bSKentaro Takeda return error; 20069590837bSKentaro Takeda } 20079590837bSKentaro Takeda 20089590837bSKentaro Takeda /** 20099590837bSKentaro Takeda * tomoyo_close_control - close() for /sys/kernel/security/tomoyo/ interface. 20109590837bSKentaro Takeda * 20119590837bSKentaro Takeda * @file: Pointer to "struct file". 20129590837bSKentaro Takeda * 20139590837bSKentaro Takeda * Releases memory and returns 0. 2014fdb8ebb7STetsuo Handa * 2015fdb8ebb7STetsuo Handa * Caller looses tomoyo_read_lock(). 20169590837bSKentaro Takeda */ 2017c3ef1500STetsuo Handa int tomoyo_close_control(struct file *file) 20189590837bSKentaro Takeda { 20199590837bSKentaro Takeda struct tomoyo_io_buffer *head = file->private_data; 2020847b173eSTetsuo Handa const bool is_write = !!head->write_buf; 20219590837bSKentaro Takeda 202217fcfbd9STetsuo Handa /* 202317fcfbd9STetsuo Handa * If the file is /sys/kernel/security/tomoyo/query , decrement the 202417fcfbd9STetsuo Handa * observer counter. 202517fcfbd9STetsuo Handa */ 202617fcfbd9STetsuo Handa if (head->type == TOMOYO_QUERY) 202717fcfbd9STetsuo Handa atomic_dec(&tomoyo_query_observers); 202817fcfbd9STetsuo Handa else 2029fdb8ebb7STetsuo Handa tomoyo_read_unlock(head->reader_idx); 20309590837bSKentaro Takeda /* Release memory used for policy I/O. */ 20318e2d39a1STetsuo Handa kfree(head->read_buf); 20329590837bSKentaro Takeda head->read_buf = NULL; 20338e2d39a1STetsuo Handa kfree(head->write_buf); 20349590837bSKentaro Takeda head->write_buf = NULL; 20358e2d39a1STetsuo Handa kfree(head); 20369590837bSKentaro Takeda head = NULL; 20379590837bSKentaro Takeda file->private_data = NULL; 2038847b173eSTetsuo Handa if (is_write) 2039847b173eSTetsuo Handa tomoyo_run_gc(); 20409590837bSKentaro Takeda return 0; 20419590837bSKentaro Takeda } 20429590837bSKentaro Takeda 20439590837bSKentaro Takeda /** 2044c3ef1500STetsuo Handa * tomoyo_check_profile - Check all profiles currently assigned to domains are defined. 20459590837bSKentaro Takeda */ 2046c3ef1500STetsuo Handa void tomoyo_check_profile(void) 20479590837bSKentaro Takeda { 2048c3ef1500STetsuo Handa struct tomoyo_domain_info *domain; 2049c3ef1500STetsuo Handa const int idx = tomoyo_read_lock(); 2050c3ef1500STetsuo Handa tomoyo_policy_loaded = true; 2051c3ef1500STetsuo Handa /* Check all profiles currently assigned to domains are defined. */ 2052c3ef1500STetsuo Handa list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { 2053c3ef1500STetsuo Handa const u8 profile = domain->profile; 2054c3ef1500STetsuo Handa if (tomoyo_profile_ptr[profile]) 2055c3ef1500STetsuo Handa continue; 2056c3ef1500STetsuo Handa panic("Profile %u (used by '%s') not defined.\n", 2057c3ef1500STetsuo Handa profile, domain->domainname->name); 20589590837bSKentaro Takeda } 2059c3ef1500STetsuo Handa tomoyo_read_unlock(idx); 206057c2590fSTetsuo Handa if (tomoyo_profile_version != 20090903) 206157c2590fSTetsuo Handa panic("Profile version %u is not supported.\n", 206257c2590fSTetsuo Handa tomoyo_profile_version); 206357c2590fSTetsuo Handa printk(KERN_INFO "TOMOYO: 2.3.0-pre 2010/06/03\n"); 2064c3ef1500STetsuo Handa printk(KERN_INFO "Mandatory Access Control activated.\n"); 20659590837bSKentaro Takeda } 2066