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 11539590837bSKentaro Takeda /** 11549590837bSKentaro Takeda * tomoyo_write_exception_policy - Write exception policy. 11559590837bSKentaro Takeda * 11569590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 11579590837bSKentaro Takeda * 11589590837bSKentaro Takeda * Returns 0 on success, negative value otherwise. 1159fdb8ebb7STetsuo Handa * 1160fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 11619590837bSKentaro Takeda */ 11629590837bSKentaro Takeda static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head) 11639590837bSKentaro Takeda { 11649590837bSKentaro Takeda char *data = head->write_buf; 11659590837bSKentaro Takeda bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE); 11669590837bSKentaro Takeda 11679590837bSKentaro Takeda if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_KEEP_DOMAIN)) 11689590837bSKentaro Takeda return tomoyo_write_domain_keeper_policy(data, false, 11699590837bSKentaro Takeda is_delete); 11709590837bSKentaro Takeda if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_KEEP_DOMAIN)) 11719590837bSKentaro Takeda return tomoyo_write_domain_keeper_policy(data, true, is_delete); 11729590837bSKentaro Takeda if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_INITIALIZE_DOMAIN)) 11739590837bSKentaro Takeda return tomoyo_write_domain_initializer_policy(data, false, 11749590837bSKentaro Takeda is_delete); 11759590837bSKentaro Takeda if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN)) 11769590837bSKentaro Takeda return tomoyo_write_domain_initializer_policy(data, true, 11779590837bSKentaro Takeda is_delete); 11781084307cSTetsuo Handa if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_AGGREGATOR)) 11791084307cSTetsuo Handa return tomoyo_write_aggregator_policy(data, is_delete); 11809590837bSKentaro Takeda if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALIAS)) 11819590837bSKentaro Takeda return tomoyo_write_alias_policy(data, is_delete); 11829590837bSKentaro Takeda if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_READ)) 11839590837bSKentaro Takeda return tomoyo_write_globally_readable_policy(data, is_delete); 11849590837bSKentaro Takeda if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_FILE_PATTERN)) 11859590837bSKentaro Takeda return tomoyo_write_pattern_policy(data, is_delete); 11869590837bSKentaro Takeda if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DENY_REWRITE)) 11879590837bSKentaro Takeda return tomoyo_write_no_rewrite_policy(data, is_delete); 11887762fbffSTetsuo Handa if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_PATH_GROUP)) 11897762fbffSTetsuo Handa return tomoyo_write_path_group_policy(data, is_delete); 11904c3e9e2dSTetsuo Handa if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NUMBER_GROUP)) 11914c3e9e2dSTetsuo Handa return tomoyo_write_number_group_policy(data, is_delete); 11929590837bSKentaro Takeda return -EINVAL; 11939590837bSKentaro Takeda } 11949590837bSKentaro Takeda 1195*31845e8cSTetsuo Handa static void tomoyo_print_number(char *buffer, int buffer_len, 1196*31845e8cSTetsuo Handa const struct tomoyo_number_union *ptr) 1197*31845e8cSTetsuo Handa { 1198*31845e8cSTetsuo Handa int i; 1199*31845e8cSTetsuo Handa unsigned long min = ptr->values[0]; 1200*31845e8cSTetsuo Handa const unsigned long max = ptr->values[1]; 1201*31845e8cSTetsuo Handa u8 min_type = ptr->min_type; 1202*31845e8cSTetsuo Handa const u8 max_type = ptr->max_type; 1203*31845e8cSTetsuo Handa memset(buffer, 0, buffer_len); 1204*31845e8cSTetsuo Handa buffer_len -= 2; 1205*31845e8cSTetsuo Handa for (i = 0; i < 2; i++) { 1206*31845e8cSTetsuo Handa int len; 1207*31845e8cSTetsuo Handa switch (min_type) { 1208*31845e8cSTetsuo Handa case TOMOYO_VALUE_TYPE_HEXADECIMAL: 1209*31845e8cSTetsuo Handa snprintf(buffer, buffer_len, "0x%lX", min); 1210*31845e8cSTetsuo Handa break; 1211*31845e8cSTetsuo Handa case TOMOYO_VALUE_TYPE_OCTAL: 1212*31845e8cSTetsuo Handa snprintf(buffer, buffer_len, "0%lo", min); 1213*31845e8cSTetsuo Handa break; 1214*31845e8cSTetsuo Handa default: 1215*31845e8cSTetsuo Handa snprintf(buffer, buffer_len, "%lu", min); 1216*31845e8cSTetsuo Handa break; 1217*31845e8cSTetsuo Handa } 1218*31845e8cSTetsuo Handa if (min == max && min_type == max_type) 1219*31845e8cSTetsuo Handa break; 1220*31845e8cSTetsuo Handa len = strlen(buffer); 1221*31845e8cSTetsuo Handa buffer[len++] = '-'; 1222*31845e8cSTetsuo Handa buffer += len; 1223*31845e8cSTetsuo Handa buffer_len -= len; 1224*31845e8cSTetsuo Handa min_type = max_type; 1225*31845e8cSTetsuo Handa min = max; 1226*31845e8cSTetsuo Handa } 1227*31845e8cSTetsuo Handa } 1228*31845e8cSTetsuo Handa 1229*31845e8cSTetsuo Handa static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = { 1230*31845e8cSTetsuo Handa [TOMOYO_PATH_GROUP] = TOMOYO_KEYWORD_PATH_GROUP, 1231*31845e8cSTetsuo Handa [TOMOYO_NUMBER_GROUP] = TOMOYO_KEYWORD_NUMBER_GROUP 1232*31845e8cSTetsuo Handa }; 1233*31845e8cSTetsuo Handa 1234*31845e8cSTetsuo Handa /** 1235*31845e8cSTetsuo Handa * tomoyo_read_group - Read "struct tomoyo_path_group"/"struct tomoyo_number_group" list. 1236*31845e8cSTetsuo Handa * 1237*31845e8cSTetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 1238*31845e8cSTetsuo Handa * @idx: Index number. 1239*31845e8cSTetsuo Handa * 1240*31845e8cSTetsuo Handa * Returns true on success, false otherwise. 1241*31845e8cSTetsuo Handa * 1242*31845e8cSTetsuo Handa * Caller holds tomoyo_read_lock(). 1243*31845e8cSTetsuo Handa */ 1244*31845e8cSTetsuo Handa static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) 1245*31845e8cSTetsuo Handa { 1246*31845e8cSTetsuo Handa struct list_head *gpos; 1247*31845e8cSTetsuo Handa struct list_head *mpos; 1248*31845e8cSTetsuo Handa const char *w[3] = { "", "", "" }; 1249*31845e8cSTetsuo Handa w[0] = tomoyo_group_name[idx]; 1250*31845e8cSTetsuo Handa list_for_each_cookie(gpos, head->read_var1, &tomoyo_group_list[idx]) { 1251*31845e8cSTetsuo Handa struct tomoyo_group *group = 1252*31845e8cSTetsuo Handa list_entry(gpos, struct tomoyo_group, list); 1253*31845e8cSTetsuo Handa w[1] = group->group_name->name; 1254*31845e8cSTetsuo Handa list_for_each_cookie(mpos, head->read_var2, 1255*31845e8cSTetsuo Handa &group->member_list) { 1256*31845e8cSTetsuo Handa char buffer[128]; 1257*31845e8cSTetsuo Handa struct tomoyo_acl_head *ptr = 1258*31845e8cSTetsuo Handa list_entry(mpos, struct tomoyo_acl_head, list); 1259*31845e8cSTetsuo Handa if (ptr->is_deleted) 1260*31845e8cSTetsuo Handa continue; 1261*31845e8cSTetsuo Handa if (idx == TOMOYO_PATH_GROUP) { 1262*31845e8cSTetsuo Handa w[2] = container_of(ptr, 1263*31845e8cSTetsuo Handa struct tomoyo_path_group, 1264*31845e8cSTetsuo Handa head)->member_name->name; 1265*31845e8cSTetsuo Handa } else if (idx == TOMOYO_NUMBER_GROUP) { 1266*31845e8cSTetsuo Handa tomoyo_print_number(buffer, sizeof(buffer), 1267*31845e8cSTetsuo Handa &container_of 1268*31845e8cSTetsuo Handa (ptr, struct 1269*31845e8cSTetsuo Handa tomoyo_number_group, 1270*31845e8cSTetsuo Handa head)->number); 1271*31845e8cSTetsuo Handa w[2] = buffer; 1272*31845e8cSTetsuo Handa } 1273*31845e8cSTetsuo Handa if (!tomoyo_io_printf(head, "%s%s %s\n", w[0], w[1], 1274*31845e8cSTetsuo Handa w[2])) 1275*31845e8cSTetsuo Handa return false; 1276*31845e8cSTetsuo Handa } 1277*31845e8cSTetsuo Handa } 1278*31845e8cSTetsuo Handa return true; 1279*31845e8cSTetsuo Handa } 1280*31845e8cSTetsuo Handa 1281*31845e8cSTetsuo Handa /** 1282*31845e8cSTetsuo Handa * tomoyo_read_policy - Read "struct tomoyo_..._entry" list. 1283*31845e8cSTetsuo Handa * 1284*31845e8cSTetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 1285*31845e8cSTetsuo Handa * @idx: Index number. 1286*31845e8cSTetsuo Handa * 1287*31845e8cSTetsuo Handa * Returns true on success, false otherwise. 1288*31845e8cSTetsuo Handa * 1289*31845e8cSTetsuo Handa * Caller holds tomoyo_read_lock(). 1290*31845e8cSTetsuo Handa */ 1291*31845e8cSTetsuo Handa static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) 1292*31845e8cSTetsuo Handa { 1293*31845e8cSTetsuo Handa struct list_head *pos; 1294*31845e8cSTetsuo Handa list_for_each_cookie(pos, head->read_var2, &tomoyo_policy_list[idx]) { 1295*31845e8cSTetsuo Handa const char *w[4] = { "", "", "", "" }; 1296*31845e8cSTetsuo Handa struct tomoyo_acl_head *acl = container_of(pos, typeof(*acl), 1297*31845e8cSTetsuo Handa list); 1298*31845e8cSTetsuo Handa if (acl->is_deleted) 1299*31845e8cSTetsuo Handa continue; 1300*31845e8cSTetsuo Handa switch (idx) { 1301*31845e8cSTetsuo Handa case TOMOYO_ID_DOMAIN_KEEPER: 1302*31845e8cSTetsuo Handa { 1303*31845e8cSTetsuo Handa struct tomoyo_domain_keeper_entry *ptr = 1304*31845e8cSTetsuo Handa container_of(acl, typeof(*ptr), head); 1305*31845e8cSTetsuo Handa w[0] = ptr->is_not ? 1306*31845e8cSTetsuo Handa TOMOYO_KEYWORD_NO_KEEP_DOMAIN : 1307*31845e8cSTetsuo Handa TOMOYO_KEYWORD_KEEP_DOMAIN; 1308*31845e8cSTetsuo Handa if (ptr->program) { 1309*31845e8cSTetsuo Handa w[1] = ptr->program->name; 1310*31845e8cSTetsuo Handa w[2] = " from "; 1311*31845e8cSTetsuo Handa } 1312*31845e8cSTetsuo Handa w[3] = ptr->domainname->name; 1313*31845e8cSTetsuo Handa } 1314*31845e8cSTetsuo Handa break; 1315*31845e8cSTetsuo Handa case TOMOYO_ID_DOMAIN_INITIALIZER: 1316*31845e8cSTetsuo Handa { 1317*31845e8cSTetsuo Handa struct tomoyo_domain_initializer_entry *ptr = 1318*31845e8cSTetsuo Handa container_of(acl, typeof(*ptr), head); 1319*31845e8cSTetsuo Handa w[0] = ptr->is_not ? 1320*31845e8cSTetsuo Handa TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN : 1321*31845e8cSTetsuo Handa TOMOYO_KEYWORD_INITIALIZE_DOMAIN; 1322*31845e8cSTetsuo Handa w[1] = ptr->program->name; 1323*31845e8cSTetsuo Handa if (ptr->domainname) { 1324*31845e8cSTetsuo Handa w[2] = " from "; 1325*31845e8cSTetsuo Handa w[3] = ptr->domainname->name; 1326*31845e8cSTetsuo Handa } 1327*31845e8cSTetsuo Handa } 1328*31845e8cSTetsuo Handa break; 1329*31845e8cSTetsuo Handa case TOMOYO_ID_GLOBALLY_READABLE: 1330*31845e8cSTetsuo Handa { 1331*31845e8cSTetsuo Handa struct tomoyo_globally_readable_file_entry *ptr 1332*31845e8cSTetsuo Handa = container_of(acl, typeof(*ptr), head); 1333*31845e8cSTetsuo Handa w[0] = TOMOYO_KEYWORD_ALLOW_READ; 1334*31845e8cSTetsuo Handa w[1] = ptr->filename->name; 1335*31845e8cSTetsuo Handa } 1336*31845e8cSTetsuo Handa break; 1337*31845e8cSTetsuo Handa case TOMOYO_ID_ALIAS: 1338*31845e8cSTetsuo Handa { 1339*31845e8cSTetsuo Handa struct tomoyo_alias_entry *ptr = 1340*31845e8cSTetsuo Handa container_of(acl, typeof(*ptr), head); 1341*31845e8cSTetsuo Handa w[0] = TOMOYO_KEYWORD_ALIAS; 1342*31845e8cSTetsuo Handa w[1] = ptr->original_name->name; 1343*31845e8cSTetsuo Handa w[2] = " "; 1344*31845e8cSTetsuo Handa w[3] = ptr->aliased_name->name; 1345*31845e8cSTetsuo Handa } 1346*31845e8cSTetsuo Handa break; 1347*31845e8cSTetsuo Handa case TOMOYO_ID_AGGREGATOR: 1348*31845e8cSTetsuo Handa { 1349*31845e8cSTetsuo Handa struct tomoyo_aggregator_entry *ptr = 1350*31845e8cSTetsuo Handa container_of(acl, typeof(*ptr), head); 1351*31845e8cSTetsuo Handa w[0] = TOMOYO_KEYWORD_AGGREGATOR; 1352*31845e8cSTetsuo Handa w[1] = ptr->original_name->name; 1353*31845e8cSTetsuo Handa w[2] = " "; 1354*31845e8cSTetsuo Handa w[3] = ptr->aggregated_name->name; 1355*31845e8cSTetsuo Handa } 1356*31845e8cSTetsuo Handa break; 1357*31845e8cSTetsuo Handa case TOMOYO_ID_PATTERN: 1358*31845e8cSTetsuo Handa { 1359*31845e8cSTetsuo Handa struct tomoyo_pattern_entry *ptr = 1360*31845e8cSTetsuo Handa container_of(acl, typeof(*ptr), head); 1361*31845e8cSTetsuo Handa w[0] = TOMOYO_KEYWORD_FILE_PATTERN; 1362*31845e8cSTetsuo Handa w[1] = ptr->pattern->name; 1363*31845e8cSTetsuo Handa } 1364*31845e8cSTetsuo Handa break; 1365*31845e8cSTetsuo Handa case TOMOYO_ID_NO_REWRITE: 1366*31845e8cSTetsuo Handa { 1367*31845e8cSTetsuo Handa struct tomoyo_no_rewrite_entry *ptr = 1368*31845e8cSTetsuo Handa container_of(acl, typeof(*ptr), head); 1369*31845e8cSTetsuo Handa w[0] = TOMOYO_KEYWORD_DENY_REWRITE; 1370*31845e8cSTetsuo Handa w[1] = ptr->pattern->name; 1371*31845e8cSTetsuo Handa } 1372*31845e8cSTetsuo Handa break; 1373*31845e8cSTetsuo Handa default: 1374*31845e8cSTetsuo Handa continue; 1375*31845e8cSTetsuo Handa } 1376*31845e8cSTetsuo Handa if (!tomoyo_io_printf(head, "%s%s%s%s\n", w[0], w[1], w[2], 1377*31845e8cSTetsuo Handa w[3])) 1378*31845e8cSTetsuo Handa return false; 1379*31845e8cSTetsuo Handa } 1380*31845e8cSTetsuo Handa return true; 1381*31845e8cSTetsuo Handa } 1382*31845e8cSTetsuo Handa 13839590837bSKentaro Takeda /** 13849590837bSKentaro Takeda * tomoyo_read_exception_policy - Read exception policy. 13859590837bSKentaro Takeda * 13869590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 13879590837bSKentaro Takeda * 1388fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 13899590837bSKentaro Takeda */ 13908fbe71f0STetsuo Handa static void tomoyo_read_exception_policy(struct tomoyo_io_buffer *head) 13919590837bSKentaro Takeda { 1392*31845e8cSTetsuo Handa if (head->read_eof) 1393*31845e8cSTetsuo Handa return; 1394*31845e8cSTetsuo Handa while (head->read_step < TOMOYO_MAX_POLICY && 1395*31845e8cSTetsuo Handa tomoyo_read_policy(head, head->read_step)) 1396*31845e8cSTetsuo Handa head->read_step++; 1397*31845e8cSTetsuo Handa if (head->read_step < TOMOYO_MAX_POLICY) 1398*31845e8cSTetsuo Handa return; 1399*31845e8cSTetsuo Handa while (head->read_step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP && 1400*31845e8cSTetsuo Handa tomoyo_read_group(head, head->read_step - TOMOYO_MAX_POLICY)) 1401*31845e8cSTetsuo Handa head->read_step++; 1402*31845e8cSTetsuo Handa if (head->read_step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP) 1403*31845e8cSTetsuo Handa return; 14049590837bSKentaro Takeda head->read_eof = true; 14059590837bSKentaro Takeda } 14069590837bSKentaro Takeda 14079590837bSKentaro Takeda /** 140817fcfbd9STetsuo Handa * tomoyo_print_header - Get header line of audit log. 140917fcfbd9STetsuo Handa * 141017fcfbd9STetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 141117fcfbd9STetsuo Handa * 141217fcfbd9STetsuo Handa * Returns string representation. 141317fcfbd9STetsuo Handa * 141417fcfbd9STetsuo Handa * This function uses kmalloc(), so caller must kfree() if this function 141517fcfbd9STetsuo Handa * didn't return NULL. 141617fcfbd9STetsuo Handa */ 141717fcfbd9STetsuo Handa static char *tomoyo_print_header(struct tomoyo_request_info *r) 141817fcfbd9STetsuo Handa { 141917fcfbd9STetsuo Handa static const char *tomoyo_mode_4[4] = { 142017fcfbd9STetsuo Handa "disabled", "learning", "permissive", "enforcing" 142117fcfbd9STetsuo Handa }; 142217fcfbd9STetsuo Handa struct timeval tv; 142317fcfbd9STetsuo Handa const pid_t gpid = task_pid_nr(current); 142417fcfbd9STetsuo Handa static const int tomoyo_buffer_len = 4096; 142517fcfbd9STetsuo Handa char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS); 142617fcfbd9STetsuo Handa if (!buffer) 142717fcfbd9STetsuo Handa return NULL; 142817fcfbd9STetsuo Handa do_gettimeofday(&tv); 142917fcfbd9STetsuo Handa snprintf(buffer, tomoyo_buffer_len - 1, 143017fcfbd9STetsuo Handa "#timestamp=%lu profile=%u mode=%s (global-pid=%u)" 143117fcfbd9STetsuo Handa " task={ pid=%u ppid=%u uid=%u gid=%u euid=%u" 143217fcfbd9STetsuo Handa " egid=%u suid=%u sgid=%u fsuid=%u fsgid=%u }", 143317fcfbd9STetsuo Handa tv.tv_sec, r->profile, tomoyo_mode_4[r->mode], gpid, 143417fcfbd9STetsuo Handa (pid_t) sys_getpid(), (pid_t) sys_getppid(), 143517fcfbd9STetsuo Handa current_uid(), current_gid(), current_euid(), 143617fcfbd9STetsuo Handa current_egid(), current_suid(), current_sgid(), 143717fcfbd9STetsuo Handa current_fsuid(), current_fsgid()); 143817fcfbd9STetsuo Handa return buffer; 143917fcfbd9STetsuo Handa } 144017fcfbd9STetsuo Handa 144117fcfbd9STetsuo Handa /** 144217fcfbd9STetsuo Handa * tomoyo_init_audit_log - Allocate buffer for audit logs. 144317fcfbd9STetsuo Handa * 144417fcfbd9STetsuo Handa * @len: Required size. 144517fcfbd9STetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 144617fcfbd9STetsuo Handa * 144717fcfbd9STetsuo Handa * Returns pointer to allocated memory. 144817fcfbd9STetsuo Handa * 144917fcfbd9STetsuo Handa * The @len is updated to add the header lines' size on success. 145017fcfbd9STetsuo Handa * 145117fcfbd9STetsuo Handa * This function uses kzalloc(), so caller must kfree() if this function 145217fcfbd9STetsuo Handa * didn't return NULL. 145317fcfbd9STetsuo Handa */ 145417fcfbd9STetsuo Handa static char *tomoyo_init_audit_log(int *len, struct tomoyo_request_info *r) 145517fcfbd9STetsuo Handa { 145617fcfbd9STetsuo Handa char *buf = NULL; 145717fcfbd9STetsuo Handa const char *header; 145817fcfbd9STetsuo Handa const char *domainname; 145917fcfbd9STetsuo Handa if (!r->domain) 146017fcfbd9STetsuo Handa r->domain = tomoyo_domain(); 146117fcfbd9STetsuo Handa domainname = r->domain->domainname->name; 146217fcfbd9STetsuo Handa header = tomoyo_print_header(r); 146317fcfbd9STetsuo Handa if (!header) 146417fcfbd9STetsuo Handa return NULL; 146517fcfbd9STetsuo Handa *len += strlen(domainname) + strlen(header) + 10; 146617fcfbd9STetsuo Handa buf = kzalloc(*len, GFP_NOFS); 146717fcfbd9STetsuo Handa if (buf) 146817fcfbd9STetsuo Handa snprintf(buf, (*len) - 1, "%s\n%s\n", header, domainname); 146917fcfbd9STetsuo Handa kfree(header); 147017fcfbd9STetsuo Handa return buf; 147117fcfbd9STetsuo Handa } 147217fcfbd9STetsuo Handa 147317fcfbd9STetsuo Handa /* Wait queue for tomoyo_query_list. */ 147417fcfbd9STetsuo Handa static DECLARE_WAIT_QUEUE_HEAD(tomoyo_query_wait); 147517fcfbd9STetsuo Handa 147617fcfbd9STetsuo Handa /* Lock for manipulating tomoyo_query_list. */ 147717fcfbd9STetsuo Handa static DEFINE_SPINLOCK(tomoyo_query_list_lock); 147817fcfbd9STetsuo Handa 147917fcfbd9STetsuo Handa /* Structure for query. */ 148017fcfbd9STetsuo Handa struct tomoyo_query_entry { 148117fcfbd9STetsuo Handa struct list_head list; 148217fcfbd9STetsuo Handa char *query; 148317fcfbd9STetsuo Handa int query_len; 148417fcfbd9STetsuo Handa unsigned int serial; 148517fcfbd9STetsuo Handa int timer; 148617fcfbd9STetsuo Handa int answer; 148717fcfbd9STetsuo Handa }; 148817fcfbd9STetsuo Handa 148917fcfbd9STetsuo Handa /* The list for "struct tomoyo_query_entry". */ 149017fcfbd9STetsuo Handa static LIST_HEAD(tomoyo_query_list); 149117fcfbd9STetsuo Handa 149217fcfbd9STetsuo Handa /* 149317fcfbd9STetsuo Handa * Number of "struct file" referring /sys/kernel/security/tomoyo/query 149417fcfbd9STetsuo Handa * interface. 149517fcfbd9STetsuo Handa */ 149617fcfbd9STetsuo Handa static atomic_t tomoyo_query_observers = ATOMIC_INIT(0); 149717fcfbd9STetsuo Handa 149817fcfbd9STetsuo Handa /** 149917fcfbd9STetsuo Handa * tomoyo_supervisor - Ask for the supervisor's decision. 150017fcfbd9STetsuo Handa * 150117fcfbd9STetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 150217fcfbd9STetsuo Handa * @fmt: The printf()'s format string, followed by parameters. 150317fcfbd9STetsuo Handa * 150417fcfbd9STetsuo Handa * Returns 0 if the supervisor decided to permit the access request which 150517fcfbd9STetsuo Handa * violated the policy in enforcing mode, TOMOYO_RETRY_REQUEST if the 150617fcfbd9STetsuo Handa * supervisor decided to retry the access request which violated the policy in 150717fcfbd9STetsuo Handa * enforcing mode, 0 if it is not in enforcing mode, -EPERM otherwise. 150817fcfbd9STetsuo Handa */ 150917fcfbd9STetsuo Handa int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) 151017fcfbd9STetsuo Handa { 151117fcfbd9STetsuo Handa va_list args; 151217fcfbd9STetsuo Handa int error = -EPERM; 151317fcfbd9STetsuo Handa int pos; 151417fcfbd9STetsuo Handa int len; 151517fcfbd9STetsuo Handa static unsigned int tomoyo_serial; 151617fcfbd9STetsuo Handa struct tomoyo_query_entry *tomoyo_query_entry = NULL; 151717fcfbd9STetsuo Handa bool quota_exceeded = false; 151817fcfbd9STetsuo Handa char *header; 151917fcfbd9STetsuo Handa switch (r->mode) { 152017fcfbd9STetsuo Handa char *buffer; 152117fcfbd9STetsuo Handa case TOMOYO_CONFIG_LEARNING: 152217fcfbd9STetsuo Handa if (!tomoyo_domain_quota_is_ok(r)) 152317fcfbd9STetsuo Handa return 0; 152417fcfbd9STetsuo Handa va_start(args, fmt); 152517fcfbd9STetsuo Handa len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 4; 152617fcfbd9STetsuo Handa va_end(args); 152717fcfbd9STetsuo Handa buffer = kmalloc(len, GFP_NOFS); 152817fcfbd9STetsuo Handa if (!buffer) 152917fcfbd9STetsuo Handa return 0; 153017fcfbd9STetsuo Handa va_start(args, fmt); 153117fcfbd9STetsuo Handa vsnprintf(buffer, len - 1, fmt, args); 153217fcfbd9STetsuo Handa va_end(args); 153317fcfbd9STetsuo Handa tomoyo_normalize_line(buffer); 153417fcfbd9STetsuo Handa tomoyo_write_domain_policy2(buffer, r->domain, false); 153517fcfbd9STetsuo Handa kfree(buffer); 153617fcfbd9STetsuo Handa /* fall through */ 153717fcfbd9STetsuo Handa case TOMOYO_CONFIG_PERMISSIVE: 153817fcfbd9STetsuo Handa return 0; 153917fcfbd9STetsuo Handa } 154017fcfbd9STetsuo Handa if (!r->domain) 154117fcfbd9STetsuo Handa r->domain = tomoyo_domain(); 154217fcfbd9STetsuo Handa if (!atomic_read(&tomoyo_query_observers)) 154317fcfbd9STetsuo Handa return -EPERM; 154417fcfbd9STetsuo Handa va_start(args, fmt); 154517fcfbd9STetsuo Handa len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 32; 154617fcfbd9STetsuo Handa va_end(args); 154717fcfbd9STetsuo Handa header = tomoyo_init_audit_log(&len, r); 154817fcfbd9STetsuo Handa if (!header) 154917fcfbd9STetsuo Handa goto out; 155017fcfbd9STetsuo Handa tomoyo_query_entry = kzalloc(sizeof(*tomoyo_query_entry), GFP_NOFS); 155117fcfbd9STetsuo Handa if (!tomoyo_query_entry) 155217fcfbd9STetsuo Handa goto out; 155317fcfbd9STetsuo Handa tomoyo_query_entry->query = kzalloc(len, GFP_NOFS); 155417fcfbd9STetsuo Handa if (!tomoyo_query_entry->query) 155517fcfbd9STetsuo Handa goto out; 155617fcfbd9STetsuo Handa len = ksize(tomoyo_query_entry->query); 155717fcfbd9STetsuo Handa INIT_LIST_HEAD(&tomoyo_query_entry->list); 155817fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 155917fcfbd9STetsuo Handa if (tomoyo_quota_for_query && tomoyo_query_memory_size + len + 156017fcfbd9STetsuo Handa sizeof(*tomoyo_query_entry) >= tomoyo_quota_for_query) { 156117fcfbd9STetsuo Handa quota_exceeded = true; 156217fcfbd9STetsuo Handa } else { 156317fcfbd9STetsuo Handa tomoyo_query_memory_size += len + sizeof(*tomoyo_query_entry); 156417fcfbd9STetsuo Handa tomoyo_query_entry->serial = tomoyo_serial++; 156517fcfbd9STetsuo Handa } 156617fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 156717fcfbd9STetsuo Handa if (quota_exceeded) 156817fcfbd9STetsuo Handa goto out; 156917fcfbd9STetsuo Handa pos = snprintf(tomoyo_query_entry->query, len - 1, "Q%u-%hu\n%s", 157017fcfbd9STetsuo Handa tomoyo_query_entry->serial, r->retry, header); 157117fcfbd9STetsuo Handa kfree(header); 157217fcfbd9STetsuo Handa header = NULL; 157317fcfbd9STetsuo Handa va_start(args, fmt); 157417fcfbd9STetsuo Handa vsnprintf(tomoyo_query_entry->query + pos, len - 1 - pos, fmt, args); 157517fcfbd9STetsuo Handa tomoyo_query_entry->query_len = strlen(tomoyo_query_entry->query) + 1; 157617fcfbd9STetsuo Handa va_end(args); 157717fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 157817fcfbd9STetsuo Handa list_add_tail(&tomoyo_query_entry->list, &tomoyo_query_list); 157917fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 158017fcfbd9STetsuo Handa /* Give 10 seconds for supervisor's opinion. */ 158117fcfbd9STetsuo Handa for (tomoyo_query_entry->timer = 0; 158217fcfbd9STetsuo Handa atomic_read(&tomoyo_query_observers) && tomoyo_query_entry->timer < 100; 158317fcfbd9STetsuo Handa tomoyo_query_entry->timer++) { 158417fcfbd9STetsuo Handa wake_up(&tomoyo_query_wait); 158517fcfbd9STetsuo Handa set_current_state(TASK_INTERRUPTIBLE); 158617fcfbd9STetsuo Handa schedule_timeout(HZ / 10); 158717fcfbd9STetsuo Handa if (tomoyo_query_entry->answer) 158817fcfbd9STetsuo Handa break; 158917fcfbd9STetsuo Handa } 159017fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 159117fcfbd9STetsuo Handa list_del(&tomoyo_query_entry->list); 159217fcfbd9STetsuo Handa tomoyo_query_memory_size -= len + sizeof(*tomoyo_query_entry); 159317fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 159417fcfbd9STetsuo Handa switch (tomoyo_query_entry->answer) { 159517fcfbd9STetsuo Handa case 3: /* Asked to retry by administrator. */ 159617fcfbd9STetsuo Handa error = TOMOYO_RETRY_REQUEST; 159717fcfbd9STetsuo Handa r->retry++; 159817fcfbd9STetsuo Handa break; 159917fcfbd9STetsuo Handa case 1: 160017fcfbd9STetsuo Handa /* Granted by administrator. */ 160117fcfbd9STetsuo Handa error = 0; 160217fcfbd9STetsuo Handa break; 160317fcfbd9STetsuo Handa case 0: 160417fcfbd9STetsuo Handa /* Timed out. */ 160517fcfbd9STetsuo Handa break; 160617fcfbd9STetsuo Handa default: 160717fcfbd9STetsuo Handa /* Rejected by administrator. */ 160817fcfbd9STetsuo Handa break; 160917fcfbd9STetsuo Handa } 161017fcfbd9STetsuo Handa out: 161117fcfbd9STetsuo Handa if (tomoyo_query_entry) 161217fcfbd9STetsuo Handa kfree(tomoyo_query_entry->query); 161317fcfbd9STetsuo Handa kfree(tomoyo_query_entry); 161417fcfbd9STetsuo Handa kfree(header); 161517fcfbd9STetsuo Handa return error; 161617fcfbd9STetsuo Handa } 161717fcfbd9STetsuo Handa 161817fcfbd9STetsuo Handa /** 161917fcfbd9STetsuo Handa * tomoyo_poll_query - poll() for /sys/kernel/security/tomoyo/query. 162017fcfbd9STetsuo Handa * 162117fcfbd9STetsuo Handa * @file: Pointer to "struct file". 162217fcfbd9STetsuo Handa * @wait: Pointer to "poll_table". 162317fcfbd9STetsuo Handa * 162417fcfbd9STetsuo Handa * Returns POLLIN | POLLRDNORM when ready to read, 0 otherwise. 162517fcfbd9STetsuo Handa * 162617fcfbd9STetsuo Handa * Waits for access requests which violated policy in enforcing mode. 162717fcfbd9STetsuo Handa */ 162817fcfbd9STetsuo Handa static int tomoyo_poll_query(struct file *file, poll_table *wait) 162917fcfbd9STetsuo Handa { 163017fcfbd9STetsuo Handa struct list_head *tmp; 163117fcfbd9STetsuo Handa bool found = false; 163217fcfbd9STetsuo Handa u8 i; 163317fcfbd9STetsuo Handa for (i = 0; i < 2; i++) { 163417fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 163517fcfbd9STetsuo Handa list_for_each(tmp, &tomoyo_query_list) { 163617fcfbd9STetsuo Handa struct tomoyo_query_entry *ptr 163717fcfbd9STetsuo Handa = list_entry(tmp, struct tomoyo_query_entry, 163817fcfbd9STetsuo Handa list); 163917fcfbd9STetsuo Handa if (ptr->answer) 164017fcfbd9STetsuo Handa continue; 164117fcfbd9STetsuo Handa found = true; 164217fcfbd9STetsuo Handa break; 164317fcfbd9STetsuo Handa } 164417fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 164517fcfbd9STetsuo Handa if (found) 164617fcfbd9STetsuo Handa return POLLIN | POLLRDNORM; 164717fcfbd9STetsuo Handa if (i) 164817fcfbd9STetsuo Handa break; 164917fcfbd9STetsuo Handa poll_wait(file, &tomoyo_query_wait, wait); 165017fcfbd9STetsuo Handa } 165117fcfbd9STetsuo Handa return 0; 165217fcfbd9STetsuo Handa } 165317fcfbd9STetsuo Handa 165417fcfbd9STetsuo Handa /** 165517fcfbd9STetsuo Handa * tomoyo_read_query - Read access requests which violated policy in enforcing mode. 165617fcfbd9STetsuo Handa * 165717fcfbd9STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 165817fcfbd9STetsuo Handa */ 16598fbe71f0STetsuo Handa static void tomoyo_read_query(struct tomoyo_io_buffer *head) 166017fcfbd9STetsuo Handa { 166117fcfbd9STetsuo Handa struct list_head *tmp; 166217fcfbd9STetsuo Handa int pos = 0; 166317fcfbd9STetsuo Handa int len = 0; 166417fcfbd9STetsuo Handa char *buf; 166517fcfbd9STetsuo Handa if (head->read_avail) 16668fbe71f0STetsuo Handa return; 166717fcfbd9STetsuo Handa if (head->read_buf) { 166817fcfbd9STetsuo Handa kfree(head->read_buf); 166917fcfbd9STetsuo Handa head->read_buf = NULL; 167017fcfbd9STetsuo Handa head->readbuf_size = 0; 167117fcfbd9STetsuo Handa } 167217fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 167317fcfbd9STetsuo Handa list_for_each(tmp, &tomoyo_query_list) { 167417fcfbd9STetsuo Handa struct tomoyo_query_entry *ptr 167517fcfbd9STetsuo Handa = list_entry(tmp, struct tomoyo_query_entry, list); 167617fcfbd9STetsuo Handa if (ptr->answer) 167717fcfbd9STetsuo Handa continue; 167817fcfbd9STetsuo Handa if (pos++ != head->read_step) 167917fcfbd9STetsuo Handa continue; 168017fcfbd9STetsuo Handa len = ptr->query_len; 168117fcfbd9STetsuo Handa break; 168217fcfbd9STetsuo Handa } 168317fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 168417fcfbd9STetsuo Handa if (!len) { 168517fcfbd9STetsuo Handa head->read_step = 0; 16868fbe71f0STetsuo Handa return; 168717fcfbd9STetsuo Handa } 168817fcfbd9STetsuo Handa buf = kzalloc(len, GFP_NOFS); 168917fcfbd9STetsuo Handa if (!buf) 16908fbe71f0STetsuo Handa return; 169117fcfbd9STetsuo Handa pos = 0; 169217fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 169317fcfbd9STetsuo Handa list_for_each(tmp, &tomoyo_query_list) { 169417fcfbd9STetsuo Handa struct tomoyo_query_entry *ptr 169517fcfbd9STetsuo Handa = list_entry(tmp, struct tomoyo_query_entry, list); 169617fcfbd9STetsuo Handa if (ptr->answer) 169717fcfbd9STetsuo Handa continue; 169817fcfbd9STetsuo Handa if (pos++ != head->read_step) 169917fcfbd9STetsuo Handa continue; 170017fcfbd9STetsuo Handa /* 170117fcfbd9STetsuo Handa * Some query can be skipped because tomoyo_query_list 170217fcfbd9STetsuo Handa * can change, but I don't care. 170317fcfbd9STetsuo Handa */ 170417fcfbd9STetsuo Handa if (len == ptr->query_len) 170517fcfbd9STetsuo Handa memmove(buf, ptr->query, len); 170617fcfbd9STetsuo Handa break; 170717fcfbd9STetsuo Handa } 170817fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 170917fcfbd9STetsuo Handa if (buf[0]) { 171017fcfbd9STetsuo Handa head->read_avail = len; 171117fcfbd9STetsuo Handa head->readbuf_size = head->read_avail; 171217fcfbd9STetsuo Handa head->read_buf = buf; 171317fcfbd9STetsuo Handa head->read_step++; 171417fcfbd9STetsuo Handa } else { 171517fcfbd9STetsuo Handa kfree(buf); 171617fcfbd9STetsuo Handa } 171717fcfbd9STetsuo Handa } 171817fcfbd9STetsuo Handa 171917fcfbd9STetsuo Handa /** 172017fcfbd9STetsuo Handa * tomoyo_write_answer - Write the supervisor's decision. 172117fcfbd9STetsuo Handa * 172217fcfbd9STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 172317fcfbd9STetsuo Handa * 172417fcfbd9STetsuo Handa * Returns 0 on success, -EINVAL otherwise. 172517fcfbd9STetsuo Handa */ 172617fcfbd9STetsuo Handa static int tomoyo_write_answer(struct tomoyo_io_buffer *head) 172717fcfbd9STetsuo Handa { 172817fcfbd9STetsuo Handa char *data = head->write_buf; 172917fcfbd9STetsuo Handa struct list_head *tmp; 173017fcfbd9STetsuo Handa unsigned int serial; 173117fcfbd9STetsuo Handa unsigned int answer; 173217fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 173317fcfbd9STetsuo Handa list_for_each(tmp, &tomoyo_query_list) { 173417fcfbd9STetsuo Handa struct tomoyo_query_entry *ptr 173517fcfbd9STetsuo Handa = list_entry(tmp, struct tomoyo_query_entry, list); 173617fcfbd9STetsuo Handa ptr->timer = 0; 173717fcfbd9STetsuo Handa } 173817fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 173917fcfbd9STetsuo Handa if (sscanf(data, "A%u=%u", &serial, &answer) != 2) 174017fcfbd9STetsuo Handa return -EINVAL; 174117fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 174217fcfbd9STetsuo Handa list_for_each(tmp, &tomoyo_query_list) { 174317fcfbd9STetsuo Handa struct tomoyo_query_entry *ptr 174417fcfbd9STetsuo Handa = list_entry(tmp, struct tomoyo_query_entry, list); 174517fcfbd9STetsuo Handa if (ptr->serial != serial) 174617fcfbd9STetsuo Handa continue; 174717fcfbd9STetsuo Handa if (!ptr->answer) 174817fcfbd9STetsuo Handa ptr->answer = answer; 174917fcfbd9STetsuo Handa break; 175017fcfbd9STetsuo Handa } 175117fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 175217fcfbd9STetsuo Handa return 0; 175317fcfbd9STetsuo Handa } 175417fcfbd9STetsuo Handa 175517fcfbd9STetsuo Handa /** 17569590837bSKentaro Takeda * tomoyo_read_version: Get version. 17579590837bSKentaro Takeda * 17589590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 17599590837bSKentaro Takeda * 17609590837bSKentaro Takeda * Returns version information. 17619590837bSKentaro Takeda */ 17628fbe71f0STetsuo Handa static void tomoyo_read_version(struct tomoyo_io_buffer *head) 17639590837bSKentaro Takeda { 17649590837bSKentaro Takeda if (!head->read_eof) { 176557c2590fSTetsuo Handa tomoyo_io_printf(head, "2.3.0-pre"); 17669590837bSKentaro Takeda head->read_eof = true; 17679590837bSKentaro Takeda } 17689590837bSKentaro Takeda } 17699590837bSKentaro Takeda 17709590837bSKentaro Takeda /** 17719590837bSKentaro Takeda * tomoyo_read_self_domain - Get the current process's domainname. 17729590837bSKentaro Takeda * 17739590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 17749590837bSKentaro Takeda * 17759590837bSKentaro Takeda * Returns the current process's domainname. 17769590837bSKentaro Takeda */ 17778fbe71f0STetsuo Handa static void tomoyo_read_self_domain(struct tomoyo_io_buffer *head) 17789590837bSKentaro Takeda { 17799590837bSKentaro Takeda if (!head->read_eof) { 17809590837bSKentaro Takeda /* 17819590837bSKentaro Takeda * tomoyo_domain()->domainname != NULL 17829590837bSKentaro Takeda * because every process belongs to a domain and 17839590837bSKentaro Takeda * the domain's name cannot be NULL. 17849590837bSKentaro Takeda */ 17859590837bSKentaro Takeda tomoyo_io_printf(head, "%s", tomoyo_domain()->domainname->name); 17869590837bSKentaro Takeda head->read_eof = true; 17879590837bSKentaro Takeda } 17889590837bSKentaro Takeda } 17899590837bSKentaro Takeda 17909590837bSKentaro Takeda /** 17919590837bSKentaro Takeda * tomoyo_open_control - open() for /sys/kernel/security/tomoyo/ interface. 17929590837bSKentaro Takeda * 17939590837bSKentaro Takeda * @type: Type of interface. 17949590837bSKentaro Takeda * @file: Pointer to "struct file". 17959590837bSKentaro Takeda * 17969590837bSKentaro Takeda * Associates policy handler and returns 0 on success, -ENOMEM otherwise. 1797fdb8ebb7STetsuo Handa * 1798fdb8ebb7STetsuo Handa * Caller acquires tomoyo_read_lock(). 17999590837bSKentaro Takeda */ 1800c3ef1500STetsuo Handa int tomoyo_open_control(const u8 type, struct file *file) 18019590837bSKentaro Takeda { 18024e5d6f7eSTetsuo Handa struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_NOFS); 18039590837bSKentaro Takeda 18049590837bSKentaro Takeda if (!head) 18059590837bSKentaro Takeda return -ENOMEM; 18069590837bSKentaro Takeda mutex_init(&head->io_sem); 180717fcfbd9STetsuo Handa head->type = type; 18089590837bSKentaro Takeda switch (type) { 18099590837bSKentaro Takeda case TOMOYO_DOMAINPOLICY: 18109590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/domain_policy */ 18119590837bSKentaro Takeda head->write = tomoyo_write_domain_policy; 18129590837bSKentaro Takeda head->read = tomoyo_read_domain_policy; 18139590837bSKentaro Takeda break; 18149590837bSKentaro Takeda case TOMOYO_EXCEPTIONPOLICY: 18159590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/exception_policy */ 18169590837bSKentaro Takeda head->write = tomoyo_write_exception_policy; 18179590837bSKentaro Takeda head->read = tomoyo_read_exception_policy; 18189590837bSKentaro Takeda break; 18199590837bSKentaro Takeda case TOMOYO_SELFDOMAIN: 18209590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/self_domain */ 18219590837bSKentaro Takeda head->read = tomoyo_read_self_domain; 18229590837bSKentaro Takeda break; 18239590837bSKentaro Takeda case TOMOYO_DOMAIN_STATUS: 18249590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/.domain_status */ 18259590837bSKentaro Takeda head->write = tomoyo_write_domain_profile; 18269590837bSKentaro Takeda head->read = tomoyo_read_domain_profile; 18279590837bSKentaro Takeda break; 18289590837bSKentaro Takeda case TOMOYO_PROCESS_STATUS: 18299590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/.process_status */ 18309590837bSKentaro Takeda head->write = tomoyo_write_pid; 18319590837bSKentaro Takeda head->read = tomoyo_read_pid; 18329590837bSKentaro Takeda break; 18339590837bSKentaro Takeda case TOMOYO_VERSION: 18349590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/version */ 18359590837bSKentaro Takeda head->read = tomoyo_read_version; 18369590837bSKentaro Takeda head->readbuf_size = 128; 18379590837bSKentaro Takeda break; 18389590837bSKentaro Takeda case TOMOYO_MEMINFO: 18399590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/meminfo */ 18409590837bSKentaro Takeda head->write = tomoyo_write_memory_quota; 18419590837bSKentaro Takeda head->read = tomoyo_read_memory_counter; 18429590837bSKentaro Takeda head->readbuf_size = 512; 18439590837bSKentaro Takeda break; 18449590837bSKentaro Takeda case TOMOYO_PROFILE: 18459590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/profile */ 18469590837bSKentaro Takeda head->write = tomoyo_write_profile; 18479590837bSKentaro Takeda head->read = tomoyo_read_profile; 18489590837bSKentaro Takeda break; 184917fcfbd9STetsuo Handa case TOMOYO_QUERY: /* /sys/kernel/security/tomoyo/query */ 185017fcfbd9STetsuo Handa head->poll = tomoyo_poll_query; 185117fcfbd9STetsuo Handa head->write = tomoyo_write_answer; 185217fcfbd9STetsuo Handa head->read = tomoyo_read_query; 185317fcfbd9STetsuo Handa break; 18549590837bSKentaro Takeda case TOMOYO_MANAGER: 18559590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/manager */ 18569590837bSKentaro Takeda head->write = tomoyo_write_manager_policy; 18579590837bSKentaro Takeda head->read = tomoyo_read_manager_policy; 18589590837bSKentaro Takeda break; 18599590837bSKentaro Takeda } 18609590837bSKentaro Takeda if (!(file->f_mode & FMODE_READ)) { 18619590837bSKentaro Takeda /* 18629590837bSKentaro Takeda * No need to allocate read_buf since it is not opened 18639590837bSKentaro Takeda * for reading. 18649590837bSKentaro Takeda */ 18659590837bSKentaro Takeda head->read = NULL; 186617fcfbd9STetsuo Handa head->poll = NULL; 186717fcfbd9STetsuo Handa } else if (!head->poll) { 186817fcfbd9STetsuo Handa /* Don't allocate read_buf for poll() access. */ 18699590837bSKentaro Takeda if (!head->readbuf_size) 18709590837bSKentaro Takeda head->readbuf_size = 4096 * 2; 18714e5d6f7eSTetsuo Handa head->read_buf = kzalloc(head->readbuf_size, GFP_NOFS); 18729590837bSKentaro Takeda if (!head->read_buf) { 18738e2d39a1STetsuo Handa kfree(head); 18749590837bSKentaro Takeda return -ENOMEM; 18759590837bSKentaro Takeda } 18769590837bSKentaro Takeda } 18779590837bSKentaro Takeda if (!(file->f_mode & FMODE_WRITE)) { 18789590837bSKentaro Takeda /* 18799590837bSKentaro Takeda * No need to allocate write_buf since it is not opened 18809590837bSKentaro Takeda * for writing. 18819590837bSKentaro Takeda */ 18829590837bSKentaro Takeda head->write = NULL; 18839590837bSKentaro Takeda } else if (head->write) { 18849590837bSKentaro Takeda head->writebuf_size = 4096 * 2; 18854e5d6f7eSTetsuo Handa head->write_buf = kzalloc(head->writebuf_size, GFP_NOFS); 18869590837bSKentaro Takeda if (!head->write_buf) { 18878e2d39a1STetsuo Handa kfree(head->read_buf); 18888e2d39a1STetsuo Handa kfree(head); 18899590837bSKentaro Takeda return -ENOMEM; 18909590837bSKentaro Takeda } 18919590837bSKentaro Takeda } 189217fcfbd9STetsuo Handa if (type != TOMOYO_QUERY) 1893fdb8ebb7STetsuo Handa head->reader_idx = tomoyo_read_lock(); 18949590837bSKentaro Takeda file->private_data = head; 18959590837bSKentaro Takeda /* 18969590837bSKentaro Takeda * Call the handler now if the file is 18979590837bSKentaro Takeda * /sys/kernel/security/tomoyo/self_domain 18989590837bSKentaro Takeda * so that the user can use 18999590837bSKentaro Takeda * cat < /sys/kernel/security/tomoyo/self_domain" 19009590837bSKentaro Takeda * to know the current process's domainname. 19019590837bSKentaro Takeda */ 19029590837bSKentaro Takeda if (type == TOMOYO_SELFDOMAIN) 19039590837bSKentaro Takeda tomoyo_read_control(file, NULL, 0); 190417fcfbd9STetsuo Handa /* 190517fcfbd9STetsuo Handa * If the file is /sys/kernel/security/tomoyo/query , increment the 190617fcfbd9STetsuo Handa * observer counter. 190717fcfbd9STetsuo Handa * The obserber counter is used by tomoyo_supervisor() to see if 190817fcfbd9STetsuo Handa * there is some process monitoring /sys/kernel/security/tomoyo/query. 190917fcfbd9STetsuo Handa */ 191017fcfbd9STetsuo Handa else if (type == TOMOYO_QUERY) 191117fcfbd9STetsuo Handa atomic_inc(&tomoyo_query_observers); 19129590837bSKentaro Takeda return 0; 19139590837bSKentaro Takeda } 19149590837bSKentaro Takeda 19159590837bSKentaro Takeda /** 191617fcfbd9STetsuo Handa * tomoyo_poll_control - poll() for /sys/kernel/security/tomoyo/ interface. 191717fcfbd9STetsuo Handa * 191817fcfbd9STetsuo Handa * @file: Pointer to "struct file". 191917fcfbd9STetsuo Handa * @wait: Pointer to "poll_table". 192017fcfbd9STetsuo Handa * 192117fcfbd9STetsuo Handa * Waits for read readiness. 192217fcfbd9STetsuo Handa * /sys/kernel/security/tomoyo/query is handled by /usr/sbin/tomoyo-queryd . 192317fcfbd9STetsuo Handa */ 192417fcfbd9STetsuo Handa int tomoyo_poll_control(struct file *file, poll_table *wait) 192517fcfbd9STetsuo Handa { 192617fcfbd9STetsuo Handa struct tomoyo_io_buffer *head = file->private_data; 192717fcfbd9STetsuo Handa if (!head->poll) 192817fcfbd9STetsuo Handa return -ENOSYS; 192917fcfbd9STetsuo Handa return head->poll(file, wait); 193017fcfbd9STetsuo Handa } 193117fcfbd9STetsuo Handa 193217fcfbd9STetsuo Handa /** 19339590837bSKentaro Takeda * tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface. 19349590837bSKentaro Takeda * 19359590837bSKentaro Takeda * @file: Pointer to "struct file". 19369590837bSKentaro Takeda * @buffer: Poiner to buffer to write to. 19379590837bSKentaro Takeda * @buffer_len: Size of @buffer. 19389590837bSKentaro Takeda * 19399590837bSKentaro Takeda * Returns bytes read on success, negative value otherwise. 1940fdb8ebb7STetsuo Handa * 1941fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 19429590837bSKentaro Takeda */ 1943c3ef1500STetsuo Handa int tomoyo_read_control(struct file *file, char __user *buffer, 19449590837bSKentaro Takeda const int buffer_len) 19459590837bSKentaro Takeda { 19469590837bSKentaro Takeda int len = 0; 19479590837bSKentaro Takeda struct tomoyo_io_buffer *head = file->private_data; 19489590837bSKentaro Takeda char *cp; 19499590837bSKentaro Takeda 19509590837bSKentaro Takeda if (!head->read) 19519590837bSKentaro Takeda return -ENOSYS; 19529590837bSKentaro Takeda if (mutex_lock_interruptible(&head->io_sem)) 19539590837bSKentaro Takeda return -EINTR; 19549590837bSKentaro Takeda /* Call the policy handler. */ 19558fbe71f0STetsuo Handa head->read(head); 19569590837bSKentaro Takeda if (len < 0) 19579590837bSKentaro Takeda goto out; 19589590837bSKentaro Takeda /* Write to buffer. */ 19599590837bSKentaro Takeda len = head->read_avail; 19609590837bSKentaro Takeda if (len > buffer_len) 19619590837bSKentaro Takeda len = buffer_len; 19629590837bSKentaro Takeda if (!len) 19639590837bSKentaro Takeda goto out; 19649590837bSKentaro Takeda /* head->read_buf changes by some functions. */ 19659590837bSKentaro Takeda cp = head->read_buf; 19669590837bSKentaro Takeda if (copy_to_user(buffer, cp, len)) { 19679590837bSKentaro Takeda len = -EFAULT; 19689590837bSKentaro Takeda goto out; 19699590837bSKentaro Takeda } 19709590837bSKentaro Takeda head->read_avail -= len; 19719590837bSKentaro Takeda memmove(cp, cp + len, head->read_avail); 19729590837bSKentaro Takeda out: 19739590837bSKentaro Takeda mutex_unlock(&head->io_sem); 19749590837bSKentaro Takeda return len; 19759590837bSKentaro Takeda } 19769590837bSKentaro Takeda 19779590837bSKentaro Takeda /** 19789590837bSKentaro Takeda * tomoyo_write_control - write() for /sys/kernel/security/tomoyo/ interface. 19799590837bSKentaro Takeda * 19809590837bSKentaro Takeda * @file: Pointer to "struct file". 19819590837bSKentaro Takeda * @buffer: Pointer to buffer to read from. 19829590837bSKentaro Takeda * @buffer_len: Size of @buffer. 19839590837bSKentaro Takeda * 19849590837bSKentaro Takeda * Returns @buffer_len on success, negative value otherwise. 1985fdb8ebb7STetsuo Handa * 1986fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 19879590837bSKentaro Takeda */ 1988c3ef1500STetsuo Handa int tomoyo_write_control(struct file *file, const char __user *buffer, 19899590837bSKentaro Takeda const int buffer_len) 19909590837bSKentaro Takeda { 19919590837bSKentaro Takeda struct tomoyo_io_buffer *head = file->private_data; 19929590837bSKentaro Takeda int error = buffer_len; 19939590837bSKentaro Takeda int avail_len = buffer_len; 19949590837bSKentaro Takeda char *cp0 = head->write_buf; 19959590837bSKentaro Takeda 19969590837bSKentaro Takeda if (!head->write) 19979590837bSKentaro Takeda return -ENOSYS; 19989590837bSKentaro Takeda if (!access_ok(VERIFY_READ, buffer, buffer_len)) 19999590837bSKentaro Takeda return -EFAULT; 20009590837bSKentaro Takeda /* Don't allow updating policies by non manager programs. */ 20019590837bSKentaro Takeda if (head->write != tomoyo_write_pid && 20029590837bSKentaro Takeda head->write != tomoyo_write_domain_policy && 200375093152STetsuo Handa !tomoyo_policy_manager()) 20049590837bSKentaro Takeda return -EPERM; 20059590837bSKentaro Takeda if (mutex_lock_interruptible(&head->io_sem)) 20069590837bSKentaro Takeda return -EINTR; 20079590837bSKentaro Takeda /* Read a line and dispatch it to the policy handler. */ 20089590837bSKentaro Takeda while (avail_len > 0) { 20099590837bSKentaro Takeda char c; 20109590837bSKentaro Takeda if (head->write_avail >= head->writebuf_size - 1) { 20119590837bSKentaro Takeda error = -ENOMEM; 20129590837bSKentaro Takeda break; 20139590837bSKentaro Takeda } else if (get_user(c, buffer)) { 20149590837bSKentaro Takeda error = -EFAULT; 20159590837bSKentaro Takeda break; 20169590837bSKentaro Takeda } 20179590837bSKentaro Takeda buffer++; 20189590837bSKentaro Takeda avail_len--; 20199590837bSKentaro Takeda cp0[head->write_avail++] = c; 20209590837bSKentaro Takeda if (c != '\n') 20219590837bSKentaro Takeda continue; 20229590837bSKentaro Takeda cp0[head->write_avail - 1] = '\0'; 20239590837bSKentaro Takeda head->write_avail = 0; 20249590837bSKentaro Takeda tomoyo_normalize_line(cp0); 20259590837bSKentaro Takeda head->write(head); 20269590837bSKentaro Takeda } 20279590837bSKentaro Takeda mutex_unlock(&head->io_sem); 20289590837bSKentaro Takeda return error; 20299590837bSKentaro Takeda } 20309590837bSKentaro Takeda 20319590837bSKentaro Takeda /** 20329590837bSKentaro Takeda * tomoyo_close_control - close() for /sys/kernel/security/tomoyo/ interface. 20339590837bSKentaro Takeda * 20349590837bSKentaro Takeda * @file: Pointer to "struct file". 20359590837bSKentaro Takeda * 20369590837bSKentaro Takeda * Releases memory and returns 0. 2037fdb8ebb7STetsuo Handa * 2038fdb8ebb7STetsuo Handa * Caller looses tomoyo_read_lock(). 20399590837bSKentaro Takeda */ 2040c3ef1500STetsuo Handa int tomoyo_close_control(struct file *file) 20419590837bSKentaro Takeda { 20429590837bSKentaro Takeda struct tomoyo_io_buffer *head = file->private_data; 2043847b173eSTetsuo Handa const bool is_write = !!head->write_buf; 20449590837bSKentaro Takeda 204517fcfbd9STetsuo Handa /* 204617fcfbd9STetsuo Handa * If the file is /sys/kernel/security/tomoyo/query , decrement the 204717fcfbd9STetsuo Handa * observer counter. 204817fcfbd9STetsuo Handa */ 204917fcfbd9STetsuo Handa if (head->type == TOMOYO_QUERY) 205017fcfbd9STetsuo Handa atomic_dec(&tomoyo_query_observers); 205117fcfbd9STetsuo Handa else 2052fdb8ebb7STetsuo Handa tomoyo_read_unlock(head->reader_idx); 20539590837bSKentaro Takeda /* Release memory used for policy I/O. */ 20548e2d39a1STetsuo Handa kfree(head->read_buf); 20559590837bSKentaro Takeda head->read_buf = NULL; 20568e2d39a1STetsuo Handa kfree(head->write_buf); 20579590837bSKentaro Takeda head->write_buf = NULL; 20588e2d39a1STetsuo Handa kfree(head); 20599590837bSKentaro Takeda head = NULL; 20609590837bSKentaro Takeda file->private_data = NULL; 2061847b173eSTetsuo Handa if (is_write) 2062847b173eSTetsuo Handa tomoyo_run_gc(); 20639590837bSKentaro Takeda return 0; 20649590837bSKentaro Takeda } 20659590837bSKentaro Takeda 20669590837bSKentaro Takeda /** 2067c3ef1500STetsuo Handa * tomoyo_check_profile - Check all profiles currently assigned to domains are defined. 20689590837bSKentaro Takeda */ 2069c3ef1500STetsuo Handa void tomoyo_check_profile(void) 20709590837bSKentaro Takeda { 2071c3ef1500STetsuo Handa struct tomoyo_domain_info *domain; 2072c3ef1500STetsuo Handa const int idx = tomoyo_read_lock(); 2073c3ef1500STetsuo Handa tomoyo_policy_loaded = true; 2074c3ef1500STetsuo Handa /* Check all profiles currently assigned to domains are defined. */ 2075c3ef1500STetsuo Handa list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { 2076c3ef1500STetsuo Handa const u8 profile = domain->profile; 2077c3ef1500STetsuo Handa if (tomoyo_profile_ptr[profile]) 2078c3ef1500STetsuo Handa continue; 2079c3ef1500STetsuo Handa panic("Profile %u (used by '%s') not defined.\n", 2080c3ef1500STetsuo Handa profile, domain->domainname->name); 20819590837bSKentaro Takeda } 2082c3ef1500STetsuo Handa tomoyo_read_unlock(idx); 208357c2590fSTetsuo Handa if (tomoyo_profile_version != 20090903) 208457c2590fSTetsuo Handa panic("Profile version %u is not supported.\n", 208557c2590fSTetsuo Handa tomoyo_profile_version); 208657c2590fSTetsuo Handa printk(KERN_INFO "TOMOYO: 2.3.0-pre 2010/06/03\n"); 2087c3ef1500STetsuo Handa printk(KERN_INFO "Mandatory Access Control activated.\n"); 20889590837bSKentaro Takeda } 2089