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 * 3569590837bSKentaro Takeda * Returns 0. 3579590837bSKentaro Takeda */ 3589590837bSKentaro Takeda static int tomoyo_read_profile(struct tomoyo_io_buffer *head) 3599590837bSKentaro Takeda { 36057c2590fSTetsuo Handa int index; 3619590837bSKentaro Takeda if (head->read_eof) 3629590837bSKentaro Takeda return 0; 36357c2590fSTetsuo Handa if (head->read_bit) 36457c2590fSTetsuo Handa goto body; 36557c2590fSTetsuo Handa tomoyo_io_printf(head, "PROFILE_VERSION=%s\n", "20090903"); 36657c2590fSTetsuo Handa tomoyo_io_printf(head, "PREFERENCE::learning={ verbose=%s " 36757c2590fSTetsuo Handa "max_entry=%u }\n", 36857c2590fSTetsuo Handa tomoyo_yesno(tomoyo_default_profile.preference. 36957c2590fSTetsuo Handa learning_verbose), 37057c2590fSTetsuo Handa tomoyo_default_profile.preference.learning_max_entry); 37157c2590fSTetsuo Handa tomoyo_io_printf(head, "PREFERENCE::permissive={ verbose=%s }\n", 37257c2590fSTetsuo Handa tomoyo_yesno(tomoyo_default_profile.preference. 37357c2590fSTetsuo Handa permissive_verbose)); 37457c2590fSTetsuo Handa tomoyo_io_printf(head, "PREFERENCE::enforcing={ verbose=%s }\n", 37557c2590fSTetsuo Handa tomoyo_yesno(tomoyo_default_profile.preference. 37657c2590fSTetsuo Handa enforcing_verbose)); 37757c2590fSTetsuo Handa head->read_bit = 1; 37857c2590fSTetsuo Handa body: 37957c2590fSTetsuo Handa for (index = head->read_step; index < TOMOYO_MAX_PROFILES; index++) { 38057c2590fSTetsuo Handa bool done; 38157c2590fSTetsuo Handa u8 config; 38257c2590fSTetsuo Handa int i; 38357c2590fSTetsuo Handa int pos; 3849590837bSKentaro Takeda const struct tomoyo_profile *profile 3859590837bSKentaro Takeda = tomoyo_profile_ptr[index]; 38657c2590fSTetsuo Handa const struct tomoyo_path_info *comment; 38757c2590fSTetsuo Handa head->read_step = index; 3889590837bSKentaro Takeda if (!profile) 3899590837bSKentaro Takeda continue; 39057c2590fSTetsuo Handa pos = head->read_avail; 39157c2590fSTetsuo Handa comment = profile->comment; 39257c2590fSTetsuo Handa done = tomoyo_io_printf(head, "%u-COMMENT=%s\n", index, 39357c2590fSTetsuo Handa comment ? comment->name : ""); 39457c2590fSTetsuo Handa if (!done) 39557c2590fSTetsuo Handa goto out; 39657c2590fSTetsuo Handa config = profile->default_config; 39757c2590fSTetsuo Handa if (!tomoyo_io_printf(head, "%u-CONFIG={ mode=%s }\n", index, 39857c2590fSTetsuo Handa tomoyo_mode_4[config & 3])) 39957c2590fSTetsuo Handa goto out; 40057c2590fSTetsuo Handa for (i = 0; i < TOMOYO_MAX_MAC_INDEX + 40157c2590fSTetsuo Handa TOMOYO_MAX_MAC_CATEGORY_INDEX; i++) { 40257c2590fSTetsuo Handa config = profile->config[i]; 40357c2590fSTetsuo Handa if (config == TOMOYO_CONFIG_USE_DEFAULT) 4049590837bSKentaro Takeda continue; 40557c2590fSTetsuo Handa if (!tomoyo_io_printf(head, 40657c2590fSTetsuo Handa "%u-CONFIG::%s={ mode=%s }\n", 40757c2590fSTetsuo Handa index, tomoyo_mac_keywords[i], 40857c2590fSTetsuo Handa tomoyo_mode_4[config & 3])) 40957c2590fSTetsuo Handa goto out; 4109590837bSKentaro Takeda } 41157c2590fSTetsuo Handa if (profile->learning != &tomoyo_default_profile.preference && 41257c2590fSTetsuo Handa !tomoyo_io_printf(head, "%u-PREFERENCE::learning={ " 41357c2590fSTetsuo Handa "verbose=%s max_entry=%u }\n", index, 41457c2590fSTetsuo Handa tomoyo_yesno(profile->preference. 41557c2590fSTetsuo Handa learning_verbose), 41657c2590fSTetsuo Handa profile->preference.learning_max_entry)) 41757c2590fSTetsuo Handa goto out; 41857c2590fSTetsuo Handa if (profile->permissive != &tomoyo_default_profile.preference 41957c2590fSTetsuo Handa && !tomoyo_io_printf(head, "%u-PREFERENCE::permissive={ " 42057c2590fSTetsuo Handa "verbose=%s }\n", index, 42157c2590fSTetsuo Handa tomoyo_yesno(profile->preference. 42257c2590fSTetsuo Handa permissive_verbose))) 42357c2590fSTetsuo Handa goto out; 42457c2590fSTetsuo Handa if (profile->enforcing != &tomoyo_default_profile.preference && 42557c2590fSTetsuo Handa !tomoyo_io_printf(head, "%u-PREFERENCE::enforcing={ " 42657c2590fSTetsuo Handa "verbose=%s }\n", index, 42757c2590fSTetsuo Handa tomoyo_yesno(profile->preference. 42857c2590fSTetsuo Handa enforcing_verbose))) 42957c2590fSTetsuo Handa goto out; 43057c2590fSTetsuo Handa continue; 43157c2590fSTetsuo Handa out: 43257c2590fSTetsuo Handa head->read_avail = pos; 4339590837bSKentaro Takeda break; 4349590837bSKentaro Takeda } 43557c2590fSTetsuo Handa if (index == TOMOYO_MAX_PROFILES) 4369590837bSKentaro Takeda head->read_eof = true; 4379590837bSKentaro Takeda return 0; 4389590837bSKentaro Takeda } 4399590837bSKentaro Takeda 440c3fa109aSTetsuo Handa /* 441c3fa109aSTetsuo Handa * tomoyo_policy_manager_list is used for holding list of domainnames or 442c3fa109aSTetsuo Handa * programs which are permitted to modify configuration via 443c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/ interface. 444c3fa109aSTetsuo Handa * 445c3fa109aSTetsuo Handa * An entry is added by 446c3fa109aSTetsuo Handa * 447c3fa109aSTetsuo Handa * # echo '<kernel> /sbin/mingetty /bin/login /bin/bash' > \ 448c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/manager 449c3fa109aSTetsuo Handa * (if you want to specify by a domainname) 450c3fa109aSTetsuo Handa * 451c3fa109aSTetsuo Handa * or 452c3fa109aSTetsuo Handa * 4539b244373STetsuo Handa * # echo '/usr/sbin/tomoyo-editpolicy' > /sys/kernel/security/tomoyo/manager 454c3fa109aSTetsuo Handa * (if you want to specify by a program's location) 455c3fa109aSTetsuo Handa * 456c3fa109aSTetsuo Handa * and is deleted by 457c3fa109aSTetsuo Handa * 458c3fa109aSTetsuo Handa * # echo 'delete <kernel> /sbin/mingetty /bin/login /bin/bash' > \ 459c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/manager 460c3fa109aSTetsuo Handa * 461c3fa109aSTetsuo Handa * or 462c3fa109aSTetsuo Handa * 4639b244373STetsuo Handa * # echo 'delete /usr/sbin/tomoyo-editpolicy' > \ 464c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/manager 465c3fa109aSTetsuo Handa * 466c3fa109aSTetsuo Handa * and all entries are retrieved by 467c3fa109aSTetsuo Handa * 468c3fa109aSTetsuo Handa * # cat /sys/kernel/security/tomoyo/manager 469c3fa109aSTetsuo Handa */ 470847b173eSTetsuo Handa LIST_HEAD(tomoyo_policy_manager_list); 4719590837bSKentaro Takeda 472*36f5e1ffSTetsuo Handa static bool tomoyo_same_manager_entry(const struct tomoyo_acl_head *a, 473*36f5e1ffSTetsuo Handa const struct tomoyo_acl_head *b) 474*36f5e1ffSTetsuo Handa { 475*36f5e1ffSTetsuo Handa return container_of(a, struct tomoyo_policy_manager_entry, head) 476*36f5e1ffSTetsuo Handa ->manager == 477*36f5e1ffSTetsuo Handa container_of(b, struct tomoyo_policy_manager_entry, head) 478*36f5e1ffSTetsuo Handa ->manager; 479*36f5e1ffSTetsuo Handa } 480*36f5e1ffSTetsuo Handa 4819590837bSKentaro Takeda /** 4829590837bSKentaro Takeda * tomoyo_update_manager_entry - Add a manager entry. 4839590837bSKentaro Takeda * 4849590837bSKentaro Takeda * @manager: The path to manager or the domainnamme. 4859590837bSKentaro Takeda * @is_delete: True if it is a delete request. 4869590837bSKentaro Takeda * 4879590837bSKentaro Takeda * Returns 0 on success, negative value otherwise. 488fdb8ebb7STetsuo Handa * 489fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 4909590837bSKentaro Takeda */ 4919590837bSKentaro Takeda static int tomoyo_update_manager_entry(const char *manager, 4929590837bSKentaro Takeda const bool is_delete) 4939590837bSKentaro Takeda { 4949e4b50e9STetsuo Handa struct tomoyo_policy_manager_entry e = { }; 495*36f5e1ffSTetsuo Handa int error; 4969590837bSKentaro Takeda 4979590837bSKentaro Takeda if (tomoyo_is_domain_def(manager)) { 49817080008STetsuo Handa if (!tomoyo_is_correct_domain(manager)) 4999590837bSKentaro Takeda return -EINVAL; 5009e4b50e9STetsuo Handa e.is_domain = true; 5019590837bSKentaro Takeda } else { 5023f629636STetsuo Handa if (!tomoyo_is_correct_path(manager)) 5039590837bSKentaro Takeda return -EINVAL; 5049590837bSKentaro Takeda } 5059e4b50e9STetsuo Handa e.manager = tomoyo_get_name(manager); 5069e4b50e9STetsuo Handa if (!e.manager) 5079590837bSKentaro Takeda return -ENOMEM; 508*36f5e1ffSTetsuo Handa error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, 509*36f5e1ffSTetsuo Handa &tomoyo_policy_manager_list, 510*36f5e1ffSTetsuo Handa tomoyo_same_manager_entry); 5119e4b50e9STetsuo Handa tomoyo_put_name(e.manager); 5129590837bSKentaro Takeda return error; 5139590837bSKentaro Takeda } 5149590837bSKentaro Takeda 5159590837bSKentaro Takeda /** 5169590837bSKentaro Takeda * tomoyo_write_manager_policy - Write manager policy. 5179590837bSKentaro Takeda * 5189590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 5199590837bSKentaro Takeda * 5209590837bSKentaro Takeda * Returns 0 on success, negative value otherwise. 521fdb8ebb7STetsuo Handa * 522fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 5239590837bSKentaro Takeda */ 5249590837bSKentaro Takeda static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head) 5259590837bSKentaro Takeda { 5269590837bSKentaro Takeda char *data = head->write_buf; 5279590837bSKentaro Takeda bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE); 5289590837bSKentaro Takeda 5299590837bSKentaro Takeda if (!strcmp(data, "manage_by_non_root")) { 5309590837bSKentaro Takeda tomoyo_manage_by_non_root = !is_delete; 5319590837bSKentaro Takeda return 0; 5329590837bSKentaro Takeda } 5339590837bSKentaro Takeda return tomoyo_update_manager_entry(data, is_delete); 5349590837bSKentaro Takeda } 5359590837bSKentaro Takeda 5369590837bSKentaro Takeda /** 5379590837bSKentaro Takeda * tomoyo_read_manager_policy - Read manager policy. 5389590837bSKentaro Takeda * 5399590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 5409590837bSKentaro Takeda * 5419590837bSKentaro Takeda * Returns 0. 542fdb8ebb7STetsuo Handa * 543fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 5449590837bSKentaro Takeda */ 5459590837bSKentaro Takeda static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head) 5469590837bSKentaro Takeda { 5479590837bSKentaro Takeda struct list_head *pos; 5489590837bSKentaro Takeda bool done = true; 5499590837bSKentaro Takeda 5509590837bSKentaro Takeda if (head->read_eof) 5519590837bSKentaro Takeda return 0; 5529590837bSKentaro Takeda list_for_each_cookie(pos, head->read_var2, 5539590837bSKentaro Takeda &tomoyo_policy_manager_list) { 5549590837bSKentaro Takeda struct tomoyo_policy_manager_entry *ptr; 5559590837bSKentaro Takeda ptr = list_entry(pos, struct tomoyo_policy_manager_entry, 55682e0f001STetsuo Handa head.list); 55782e0f001STetsuo Handa if (ptr->head.is_deleted) 5589590837bSKentaro Takeda continue; 5597d2948b1STetsuo Handa done = tomoyo_io_printf(head, "%s\n", ptr->manager->name); 5607d2948b1STetsuo Handa if (!done) 5619590837bSKentaro Takeda break; 5629590837bSKentaro Takeda } 5639590837bSKentaro Takeda head->read_eof = done; 5649590837bSKentaro Takeda return 0; 5659590837bSKentaro Takeda } 5669590837bSKentaro Takeda 5679590837bSKentaro Takeda /** 5689590837bSKentaro Takeda * tomoyo_is_policy_manager - Check whether the current process is a policy manager. 5699590837bSKentaro Takeda * 5709590837bSKentaro Takeda * Returns true if the current process is permitted to modify policy 5719590837bSKentaro Takeda * via /sys/kernel/security/tomoyo/ interface. 572fdb8ebb7STetsuo Handa * 573fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 5749590837bSKentaro Takeda */ 5759590837bSKentaro Takeda static bool tomoyo_is_policy_manager(void) 5769590837bSKentaro Takeda { 5779590837bSKentaro Takeda struct tomoyo_policy_manager_entry *ptr; 5789590837bSKentaro Takeda const char *exe; 5799590837bSKentaro Takeda const struct task_struct *task = current; 5809590837bSKentaro Takeda const struct tomoyo_path_info *domainname = tomoyo_domain()->domainname; 5819590837bSKentaro Takeda bool found = false; 5829590837bSKentaro Takeda 5839590837bSKentaro Takeda if (!tomoyo_policy_loaded) 5849590837bSKentaro Takeda return true; 5859590837bSKentaro Takeda if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid)) 5869590837bSKentaro Takeda return false; 58782e0f001STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, head.list) { 58882e0f001STetsuo Handa if (!ptr->head.is_deleted && ptr->is_domain 5899590837bSKentaro Takeda && !tomoyo_pathcmp(domainname, ptr->manager)) { 5909590837bSKentaro Takeda found = true; 5919590837bSKentaro Takeda break; 5929590837bSKentaro Takeda } 5939590837bSKentaro Takeda } 5949590837bSKentaro Takeda if (found) 5959590837bSKentaro Takeda return true; 5969590837bSKentaro Takeda exe = tomoyo_get_exe(); 5979590837bSKentaro Takeda if (!exe) 5989590837bSKentaro Takeda return false; 59982e0f001STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, head.list) { 60082e0f001STetsuo Handa if (!ptr->head.is_deleted && !ptr->is_domain 6019590837bSKentaro Takeda && !strcmp(exe, ptr->manager->name)) { 6029590837bSKentaro Takeda found = true; 6039590837bSKentaro Takeda break; 6049590837bSKentaro Takeda } 6059590837bSKentaro Takeda } 6069590837bSKentaro Takeda if (!found) { /* Reduce error messages. */ 6079590837bSKentaro Takeda static pid_t last_pid; 6089590837bSKentaro Takeda const pid_t pid = current->pid; 6099590837bSKentaro Takeda if (last_pid != pid) { 6109590837bSKentaro Takeda printk(KERN_WARNING "%s ( %s ) is not permitted to " 6119590837bSKentaro Takeda "update policies.\n", domainname->name, exe); 6129590837bSKentaro Takeda last_pid = pid; 6139590837bSKentaro Takeda } 6149590837bSKentaro Takeda } 6158e2d39a1STetsuo Handa kfree(exe); 6169590837bSKentaro Takeda return found; 6179590837bSKentaro Takeda } 6189590837bSKentaro Takeda 6199590837bSKentaro Takeda /** 6209590837bSKentaro Takeda * tomoyo_is_select_one - Parse select command. 6219590837bSKentaro Takeda * 6229590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 6239590837bSKentaro Takeda * @data: String to parse. 6249590837bSKentaro Takeda * 6259590837bSKentaro Takeda * Returns true on success, false otherwise. 626fdb8ebb7STetsuo Handa * 627fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 6289590837bSKentaro Takeda */ 6299590837bSKentaro Takeda static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, 6309590837bSKentaro Takeda const char *data) 6319590837bSKentaro Takeda { 6329590837bSKentaro Takeda unsigned int pid; 6339590837bSKentaro Takeda struct tomoyo_domain_info *domain = NULL; 6349b244373STetsuo Handa bool global_pid = false; 6359590837bSKentaro Takeda 6369b244373STetsuo Handa if (sscanf(data, "pid=%u", &pid) == 1 || 6379b244373STetsuo Handa (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) { 6389590837bSKentaro Takeda struct task_struct *p; 6391fcdc7c5STetsuo Handa rcu_read_lock(); 6409590837bSKentaro Takeda read_lock(&tasklist_lock); 6419b244373STetsuo Handa if (global_pid) 6429b244373STetsuo Handa p = find_task_by_pid_ns(pid, &init_pid_ns); 6439b244373STetsuo Handa else 6449590837bSKentaro Takeda p = find_task_by_vpid(pid); 6459590837bSKentaro Takeda if (p) 6469590837bSKentaro Takeda domain = tomoyo_real_domain(p); 6479590837bSKentaro Takeda read_unlock(&tasklist_lock); 6481fcdc7c5STetsuo Handa rcu_read_unlock(); 6499590837bSKentaro Takeda } else if (!strncmp(data, "domain=", 7)) { 650fdb8ebb7STetsuo Handa if (tomoyo_is_domain_def(data + 7)) 6519590837bSKentaro Takeda domain = tomoyo_find_domain(data + 7); 6529590837bSKentaro Takeda } else 6539590837bSKentaro Takeda return false; 6549590837bSKentaro Takeda head->write_var1 = domain; 6559590837bSKentaro Takeda /* Accessing read_buf is safe because head->io_sem is held. */ 6569590837bSKentaro Takeda if (!head->read_buf) 6579590837bSKentaro Takeda return true; /* Do nothing if open(O_WRONLY). */ 6589590837bSKentaro Takeda head->read_avail = 0; 6599590837bSKentaro Takeda tomoyo_io_printf(head, "# select %s\n", data); 6609590837bSKentaro Takeda head->read_single_domain = true; 6619590837bSKentaro Takeda head->read_eof = !domain; 6629590837bSKentaro Takeda if (domain) { 6639590837bSKentaro Takeda struct tomoyo_domain_info *d; 6649590837bSKentaro Takeda head->read_var1 = NULL; 665fdb8ebb7STetsuo Handa list_for_each_entry_rcu(d, &tomoyo_domain_list, list) { 6669590837bSKentaro Takeda if (d == domain) 6679590837bSKentaro Takeda break; 6689590837bSKentaro Takeda head->read_var1 = &d->list; 6699590837bSKentaro Takeda } 6709590837bSKentaro Takeda head->read_var2 = NULL; 6719590837bSKentaro Takeda head->read_bit = 0; 6729590837bSKentaro Takeda head->read_step = 0; 6739590837bSKentaro Takeda if (domain->is_deleted) 6749590837bSKentaro Takeda tomoyo_io_printf(head, "# This is a deleted domain.\n"); 6759590837bSKentaro Takeda } 6769590837bSKentaro Takeda return true; 6779590837bSKentaro Takeda } 6789590837bSKentaro Takeda 6799590837bSKentaro Takeda /** 680ccf135f5STetsuo Handa * tomoyo_delete_domain - Delete a domain. 681ccf135f5STetsuo Handa * 682ccf135f5STetsuo Handa * @domainname: The name of domain. 683ccf135f5STetsuo Handa * 684ccf135f5STetsuo Handa * Returns 0. 685fdb8ebb7STetsuo Handa * 686fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 687ccf135f5STetsuo Handa */ 688ccf135f5STetsuo Handa static int tomoyo_delete_domain(char *domainname) 689ccf135f5STetsuo Handa { 690ccf135f5STetsuo Handa struct tomoyo_domain_info *domain; 691ccf135f5STetsuo Handa struct tomoyo_path_info name; 692ccf135f5STetsuo Handa 693ccf135f5STetsuo Handa name.name = domainname; 694ccf135f5STetsuo Handa tomoyo_fill_path_info(&name); 69529282381STetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 69629282381STetsuo Handa return 0; 697ccf135f5STetsuo Handa /* Is there an active domain? */ 698fdb8ebb7STetsuo Handa list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { 699ccf135f5STetsuo Handa /* Never delete tomoyo_kernel_domain */ 700ccf135f5STetsuo Handa if (domain == &tomoyo_kernel_domain) 701ccf135f5STetsuo Handa continue; 702ccf135f5STetsuo Handa if (domain->is_deleted || 703ccf135f5STetsuo Handa tomoyo_pathcmp(domain->domainname, &name)) 704ccf135f5STetsuo Handa continue; 705ccf135f5STetsuo Handa domain->is_deleted = true; 706ccf135f5STetsuo Handa break; 707ccf135f5STetsuo Handa } 708f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 709ccf135f5STetsuo Handa return 0; 710ccf135f5STetsuo Handa } 711ccf135f5STetsuo Handa 712ccf135f5STetsuo Handa /** 71317fcfbd9STetsuo Handa * tomoyo_write_domain_policy2 - Write domain policy. 71417fcfbd9STetsuo Handa * 71517fcfbd9STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 71617fcfbd9STetsuo Handa * 71717fcfbd9STetsuo Handa * Returns 0 on success, negative value otherwise. 71817fcfbd9STetsuo Handa * 71917fcfbd9STetsuo Handa * Caller holds tomoyo_read_lock(). 72017fcfbd9STetsuo Handa */ 72117fcfbd9STetsuo Handa static int tomoyo_write_domain_policy2(char *data, 72217fcfbd9STetsuo Handa struct tomoyo_domain_info *domain, 72317fcfbd9STetsuo Handa const bool is_delete) 72417fcfbd9STetsuo Handa { 72517fcfbd9STetsuo Handa if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_MOUNT)) 72617fcfbd9STetsuo Handa return tomoyo_write_mount_policy(data, domain, is_delete); 72717fcfbd9STetsuo Handa return tomoyo_write_file_policy(data, domain, is_delete); 72817fcfbd9STetsuo Handa } 72917fcfbd9STetsuo Handa 73017fcfbd9STetsuo Handa /** 7319590837bSKentaro Takeda * tomoyo_write_domain_policy - Write domain policy. 7329590837bSKentaro Takeda * 7339590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 7349590837bSKentaro Takeda * 7359590837bSKentaro Takeda * Returns 0 on success, negative value otherwise. 736fdb8ebb7STetsuo Handa * 737fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 7389590837bSKentaro Takeda */ 7399590837bSKentaro Takeda static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head) 7409590837bSKentaro Takeda { 7419590837bSKentaro Takeda char *data = head->write_buf; 7429590837bSKentaro Takeda struct tomoyo_domain_info *domain = head->write_var1; 7439590837bSKentaro Takeda bool is_delete = false; 7449590837bSKentaro Takeda bool is_select = false; 7459590837bSKentaro Takeda unsigned int profile; 7469590837bSKentaro Takeda 7479590837bSKentaro Takeda if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE)) 7489590837bSKentaro Takeda is_delete = true; 7499590837bSKentaro Takeda else if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_SELECT)) 7509590837bSKentaro Takeda is_select = true; 7519590837bSKentaro Takeda if (is_select && tomoyo_is_select_one(head, data)) 7529590837bSKentaro Takeda return 0; 7539590837bSKentaro Takeda /* Don't allow updating policies by non manager programs. */ 7549590837bSKentaro Takeda if (!tomoyo_is_policy_manager()) 7559590837bSKentaro Takeda return -EPERM; 7569590837bSKentaro Takeda if (tomoyo_is_domain_def(data)) { 7579590837bSKentaro Takeda domain = NULL; 7589590837bSKentaro Takeda if (is_delete) 7599590837bSKentaro Takeda tomoyo_delete_domain(data); 760fdb8ebb7STetsuo Handa else if (is_select) 7619590837bSKentaro Takeda domain = tomoyo_find_domain(data); 762fdb8ebb7STetsuo Handa else 7639590837bSKentaro Takeda domain = tomoyo_find_or_assign_new_domain(data, 0); 7649590837bSKentaro Takeda head->write_var1 = domain; 7659590837bSKentaro Takeda return 0; 7669590837bSKentaro Takeda } 7679590837bSKentaro Takeda if (!domain) 7689590837bSKentaro Takeda return -EINVAL; 7699590837bSKentaro Takeda 7709590837bSKentaro Takeda if (sscanf(data, TOMOYO_KEYWORD_USE_PROFILE "%u", &profile) == 1 7719590837bSKentaro Takeda && profile < TOMOYO_MAX_PROFILES) { 7729590837bSKentaro Takeda if (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded) 7739590837bSKentaro Takeda domain->profile = (u8) profile; 7749590837bSKentaro Takeda return 0; 7759590837bSKentaro Takeda } 7769590837bSKentaro Takeda if (!strcmp(data, TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ)) { 777ea13ddbaSTetsuo Handa domain->ignore_global_allow_read = !is_delete; 7789590837bSKentaro Takeda return 0; 7799590837bSKentaro Takeda } 7809b244373STetsuo Handa if (!strcmp(data, TOMOYO_KEYWORD_QUOTA_EXCEEDED)) { 7819b244373STetsuo Handa domain->quota_warned = !is_delete; 7829b244373STetsuo Handa return 0; 7839b244373STetsuo Handa } 7849b244373STetsuo Handa if (!strcmp(data, TOMOYO_KEYWORD_TRANSITION_FAILED)) { 7859b244373STetsuo Handa domain->transition_failed = !is_delete; 7869b244373STetsuo Handa return 0; 7879b244373STetsuo Handa } 78817fcfbd9STetsuo Handa return tomoyo_write_domain_policy2(data, domain, is_delete); 7899590837bSKentaro Takeda } 7909590837bSKentaro Takeda 7919590837bSKentaro Takeda /** 7927ef61233STetsuo Handa * tomoyo_print_path_acl - Print a single path ACL entry. 7939590837bSKentaro Takeda * 7949590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 7957ef61233STetsuo Handa * @ptr: Pointer to "struct tomoyo_path_acl". 7969590837bSKentaro Takeda * 7979590837bSKentaro Takeda * Returns true on success, false otherwise. 7989590837bSKentaro Takeda */ 7997ef61233STetsuo Handa static bool tomoyo_print_path_acl(struct tomoyo_io_buffer *head, 8007ef61233STetsuo Handa struct tomoyo_path_acl *ptr) 8019590837bSKentaro Takeda { 8029590837bSKentaro Takeda int pos; 8039590837bSKentaro Takeda u8 bit; 804a1f9bb6aSTetsuo Handa const u16 perm = ptr->perm; 8059590837bSKentaro Takeda 8067ef61233STetsuo Handa for (bit = head->read_bit; bit < TOMOYO_MAX_PATH_OPERATION; bit++) { 8079590837bSKentaro Takeda if (!(perm & (1 << bit))) 8089590837bSKentaro Takeda continue; 8099590837bSKentaro Takeda /* Print "read/write" instead of "read" and "write". */ 8107ef61233STetsuo Handa if ((bit == TOMOYO_TYPE_READ || bit == TOMOYO_TYPE_WRITE) 8117ef61233STetsuo Handa && (perm & (1 << TOMOYO_TYPE_READ_WRITE))) 8129590837bSKentaro Takeda continue; 8139590837bSKentaro Takeda pos = head->read_avail; 8147762fbffSTetsuo Handa if (!tomoyo_io_printf(head, "allow_%s ", 8157762fbffSTetsuo Handa tomoyo_path2keyword(bit)) || 8167762fbffSTetsuo Handa !tomoyo_print_name_union(head, &ptr->name) || 8177762fbffSTetsuo Handa !tomoyo_io_printf(head, "\n")) 8189590837bSKentaro Takeda goto out; 8199590837bSKentaro Takeda } 8209590837bSKentaro Takeda head->read_bit = 0; 8219590837bSKentaro Takeda return true; 8229590837bSKentaro Takeda out: 8239590837bSKentaro Takeda head->read_bit = bit; 8249590837bSKentaro Takeda head->read_avail = pos; 8259590837bSKentaro Takeda return false; 8269590837bSKentaro Takeda } 8279590837bSKentaro Takeda 8289590837bSKentaro Takeda /** 8297ef61233STetsuo Handa * tomoyo_print_path2_acl - Print a double path ACL entry. 8309590837bSKentaro Takeda * 8319590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 8327ef61233STetsuo Handa * @ptr: Pointer to "struct tomoyo_path2_acl". 8339590837bSKentaro Takeda * 8349590837bSKentaro Takeda * Returns true on success, false otherwise. 8359590837bSKentaro Takeda */ 8367ef61233STetsuo Handa static bool tomoyo_print_path2_acl(struct tomoyo_io_buffer *head, 8377ef61233STetsuo Handa struct tomoyo_path2_acl *ptr) 8389590837bSKentaro Takeda { 8399590837bSKentaro Takeda int pos; 8409590837bSKentaro Takeda const u8 perm = ptr->perm; 8419590837bSKentaro Takeda u8 bit; 8429590837bSKentaro Takeda 8437ef61233STetsuo Handa for (bit = head->read_bit; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) { 8449590837bSKentaro Takeda if (!(perm & (1 << bit))) 8459590837bSKentaro Takeda continue; 8469590837bSKentaro Takeda pos = head->read_avail; 8477762fbffSTetsuo Handa if (!tomoyo_io_printf(head, "allow_%s ", 8487762fbffSTetsuo Handa tomoyo_path22keyword(bit)) || 8497762fbffSTetsuo Handa !tomoyo_print_name_union(head, &ptr->name1) || 8507762fbffSTetsuo Handa !tomoyo_print_name_union(head, &ptr->name2) || 8517762fbffSTetsuo Handa !tomoyo_io_printf(head, "\n")) 8529590837bSKentaro Takeda goto out; 8539590837bSKentaro Takeda } 8549590837bSKentaro Takeda head->read_bit = 0; 8559590837bSKentaro Takeda return true; 8569590837bSKentaro Takeda out: 8579590837bSKentaro Takeda head->read_bit = bit; 8589590837bSKentaro Takeda head->read_avail = pos; 8599590837bSKentaro Takeda return false; 8609590837bSKentaro Takeda } 8619590837bSKentaro Takeda 8629590837bSKentaro Takeda /** 863a1f9bb6aSTetsuo Handa * tomoyo_print_path_number_acl - Print a path_number ACL entry. 864a1f9bb6aSTetsuo Handa * 865a1f9bb6aSTetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 866a1f9bb6aSTetsuo Handa * @ptr: Pointer to "struct tomoyo_path_number_acl". 867a1f9bb6aSTetsuo Handa * 868a1f9bb6aSTetsuo Handa * Returns true on success, false otherwise. 869a1f9bb6aSTetsuo Handa */ 870a1f9bb6aSTetsuo Handa static bool tomoyo_print_path_number_acl(struct tomoyo_io_buffer *head, 871a1f9bb6aSTetsuo Handa struct tomoyo_path_number_acl *ptr) 872a1f9bb6aSTetsuo Handa { 873a1f9bb6aSTetsuo Handa int pos; 874a1f9bb6aSTetsuo Handa u8 bit; 875a1f9bb6aSTetsuo Handa const u8 perm = ptr->perm; 876a1f9bb6aSTetsuo Handa for (bit = head->read_bit; bit < TOMOYO_MAX_PATH_NUMBER_OPERATION; 877a1f9bb6aSTetsuo Handa bit++) { 878a1f9bb6aSTetsuo Handa if (!(perm & (1 << bit))) 879a1f9bb6aSTetsuo Handa continue; 880a1f9bb6aSTetsuo Handa pos = head->read_avail; 881a1f9bb6aSTetsuo Handa if (!tomoyo_io_printf(head, "allow_%s", 882a1f9bb6aSTetsuo Handa tomoyo_path_number2keyword(bit)) || 883a1f9bb6aSTetsuo Handa !tomoyo_print_name_union(head, &ptr->name) || 884a1f9bb6aSTetsuo Handa !tomoyo_print_number_union(head, &ptr->number) || 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 /** 897a1f9bb6aSTetsuo Handa * tomoyo_print_path_number3_acl - Print a path_number3 ACL entry. 898a1f9bb6aSTetsuo Handa * 899a1f9bb6aSTetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 900a1f9bb6aSTetsuo Handa * @ptr: Pointer to "struct tomoyo_path_number3_acl". 901a1f9bb6aSTetsuo Handa * 902a1f9bb6aSTetsuo Handa * Returns true on success, false otherwise. 903a1f9bb6aSTetsuo Handa */ 904a1f9bb6aSTetsuo Handa static bool tomoyo_print_path_number3_acl(struct tomoyo_io_buffer *head, 905a1f9bb6aSTetsuo Handa struct tomoyo_path_number3_acl *ptr) 906a1f9bb6aSTetsuo Handa { 907a1f9bb6aSTetsuo Handa int pos; 908a1f9bb6aSTetsuo Handa u8 bit; 909a1f9bb6aSTetsuo Handa const u16 perm = ptr->perm; 910a1f9bb6aSTetsuo Handa for (bit = head->read_bit; bit < TOMOYO_MAX_PATH_NUMBER3_OPERATION; 911a1f9bb6aSTetsuo Handa bit++) { 912a1f9bb6aSTetsuo Handa if (!(perm & (1 << bit))) 913a1f9bb6aSTetsuo Handa continue; 914a1f9bb6aSTetsuo Handa pos = head->read_avail; 915a1f9bb6aSTetsuo Handa if (!tomoyo_io_printf(head, "allow_%s", 916a1f9bb6aSTetsuo Handa tomoyo_path_number32keyword(bit)) || 917a1f9bb6aSTetsuo Handa !tomoyo_print_name_union(head, &ptr->name) || 918a1f9bb6aSTetsuo Handa !tomoyo_print_number_union(head, &ptr->mode) || 919a1f9bb6aSTetsuo Handa !tomoyo_print_number_union(head, &ptr->major) || 920a1f9bb6aSTetsuo Handa !tomoyo_print_number_union(head, &ptr->minor) || 921a1f9bb6aSTetsuo Handa !tomoyo_io_printf(head, "\n")) 922a1f9bb6aSTetsuo Handa goto out; 923a1f9bb6aSTetsuo Handa } 924a1f9bb6aSTetsuo Handa head->read_bit = 0; 925a1f9bb6aSTetsuo Handa return true; 926a1f9bb6aSTetsuo Handa out: 927a1f9bb6aSTetsuo Handa head->read_bit = bit; 928a1f9bb6aSTetsuo Handa head->read_avail = pos; 929a1f9bb6aSTetsuo Handa return false; 930a1f9bb6aSTetsuo Handa } 931a1f9bb6aSTetsuo Handa 932a1f9bb6aSTetsuo Handa /** 9332106ccd9STetsuo Handa * tomoyo_print_mount_acl - Print a mount ACL entry. 9342106ccd9STetsuo Handa * 9352106ccd9STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 9362106ccd9STetsuo Handa * @ptr: Pointer to "struct tomoyo_mount_acl". 9372106ccd9STetsuo Handa * 9382106ccd9STetsuo Handa * Returns true on success, false otherwise. 9392106ccd9STetsuo Handa */ 9402106ccd9STetsuo Handa static bool tomoyo_print_mount_acl(struct tomoyo_io_buffer *head, 9412106ccd9STetsuo Handa struct tomoyo_mount_acl *ptr) 9422106ccd9STetsuo Handa { 9432106ccd9STetsuo Handa const int pos = head->read_avail; 9442106ccd9STetsuo Handa if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_MOUNT) || 9452106ccd9STetsuo Handa !tomoyo_print_name_union(head, &ptr->dev_name) || 9462106ccd9STetsuo Handa !tomoyo_print_name_union(head, &ptr->dir_name) || 9472106ccd9STetsuo Handa !tomoyo_print_name_union(head, &ptr->fs_type) || 9482106ccd9STetsuo Handa !tomoyo_print_number_union(head, &ptr->flags) || 9492106ccd9STetsuo Handa !tomoyo_io_printf(head, "\n")) { 9502106ccd9STetsuo Handa head->read_avail = pos; 9512106ccd9STetsuo Handa return false; 9522106ccd9STetsuo Handa } 9532106ccd9STetsuo Handa return true; 9542106ccd9STetsuo Handa } 9552106ccd9STetsuo Handa 9562106ccd9STetsuo Handa /** 9579590837bSKentaro Takeda * tomoyo_print_entry - Print an ACL entry. 9589590837bSKentaro Takeda * 9599590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 9609590837bSKentaro Takeda * @ptr: Pointer to an ACL entry. 9619590837bSKentaro Takeda * 9629590837bSKentaro Takeda * Returns true on success, false otherwise. 9639590837bSKentaro Takeda */ 9649590837bSKentaro Takeda static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, 9659590837bSKentaro Takeda struct tomoyo_acl_info *ptr) 9669590837bSKentaro Takeda { 967ea13ddbaSTetsuo Handa const u8 acl_type = ptr->type; 9689590837bSKentaro Takeda 969237ab459STetsuo Handa if (ptr->is_deleted) 970237ab459STetsuo Handa return true; 9717ef61233STetsuo Handa if (acl_type == TOMOYO_TYPE_PATH_ACL) { 9727ef61233STetsuo Handa struct tomoyo_path_acl *acl 9737ef61233STetsuo Handa = container_of(ptr, struct tomoyo_path_acl, head); 9747ef61233STetsuo Handa return tomoyo_print_path_acl(head, acl); 9759590837bSKentaro Takeda } 9767ef61233STetsuo Handa if (acl_type == TOMOYO_TYPE_PATH2_ACL) { 9777ef61233STetsuo Handa struct tomoyo_path2_acl *acl 9787ef61233STetsuo Handa = container_of(ptr, struct tomoyo_path2_acl, head); 9797ef61233STetsuo Handa return tomoyo_print_path2_acl(head, acl); 9809590837bSKentaro Takeda } 981a1f9bb6aSTetsuo Handa if (acl_type == TOMOYO_TYPE_PATH_NUMBER_ACL) { 982a1f9bb6aSTetsuo Handa struct tomoyo_path_number_acl *acl 983a1f9bb6aSTetsuo Handa = container_of(ptr, struct tomoyo_path_number_acl, 984a1f9bb6aSTetsuo Handa head); 985a1f9bb6aSTetsuo Handa return tomoyo_print_path_number_acl(head, acl); 986a1f9bb6aSTetsuo Handa } 987a1f9bb6aSTetsuo Handa if (acl_type == TOMOYO_TYPE_PATH_NUMBER3_ACL) { 988a1f9bb6aSTetsuo Handa struct tomoyo_path_number3_acl *acl 989a1f9bb6aSTetsuo Handa = container_of(ptr, struct tomoyo_path_number3_acl, 990a1f9bb6aSTetsuo Handa head); 991a1f9bb6aSTetsuo Handa return tomoyo_print_path_number3_acl(head, acl); 992a1f9bb6aSTetsuo Handa } 9932106ccd9STetsuo Handa if (acl_type == TOMOYO_TYPE_MOUNT_ACL) { 9942106ccd9STetsuo Handa struct tomoyo_mount_acl *acl 9952106ccd9STetsuo Handa = container_of(ptr, struct tomoyo_mount_acl, head); 9962106ccd9STetsuo Handa return tomoyo_print_mount_acl(head, acl); 9972106ccd9STetsuo Handa } 9989590837bSKentaro Takeda BUG(); /* This must not happen. */ 9999590837bSKentaro Takeda return false; 10009590837bSKentaro Takeda } 10019590837bSKentaro Takeda 10029590837bSKentaro Takeda /** 10039590837bSKentaro Takeda * tomoyo_read_domain_policy - Read domain policy. 10049590837bSKentaro Takeda * 10059590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 10069590837bSKentaro Takeda * 10079590837bSKentaro Takeda * Returns 0. 1008fdb8ebb7STetsuo Handa * 1009fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 10109590837bSKentaro Takeda */ 10119590837bSKentaro Takeda static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head) 10129590837bSKentaro Takeda { 10139590837bSKentaro Takeda struct list_head *dpos; 10149590837bSKentaro Takeda struct list_head *apos; 10159590837bSKentaro Takeda bool done = true; 10169590837bSKentaro Takeda 10179590837bSKentaro Takeda if (head->read_eof) 10189590837bSKentaro Takeda return 0; 10199590837bSKentaro Takeda if (head->read_step == 0) 10209590837bSKentaro Takeda head->read_step = 1; 10219590837bSKentaro Takeda list_for_each_cookie(dpos, head->read_var1, &tomoyo_domain_list) { 10229590837bSKentaro Takeda struct tomoyo_domain_info *domain; 10239590837bSKentaro Takeda const char *quota_exceeded = ""; 10249590837bSKentaro Takeda const char *transition_failed = ""; 10259590837bSKentaro Takeda const char *ignore_global_allow_read = ""; 10269590837bSKentaro Takeda domain = list_entry(dpos, struct tomoyo_domain_info, list); 10279590837bSKentaro Takeda if (head->read_step != 1) 10289590837bSKentaro Takeda goto acl_loop; 10299590837bSKentaro Takeda if (domain->is_deleted && !head->read_single_domain) 10309590837bSKentaro Takeda continue; 10319590837bSKentaro Takeda /* Print domainname and flags. */ 10329590837bSKentaro Takeda if (domain->quota_warned) 10339590837bSKentaro Takeda quota_exceeded = "quota_exceeded\n"; 1034ea13ddbaSTetsuo Handa if (domain->transition_failed) 10359590837bSKentaro Takeda transition_failed = "transition_failed\n"; 1036ea13ddbaSTetsuo Handa if (domain->ignore_global_allow_read) 10379590837bSKentaro Takeda ignore_global_allow_read 10389590837bSKentaro Takeda = TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n"; 10397d2948b1STetsuo Handa done = tomoyo_io_printf(head, "%s\n" TOMOYO_KEYWORD_USE_PROFILE 10407d2948b1STetsuo Handa "%u\n%s%s%s\n", 10417d2948b1STetsuo Handa domain->domainname->name, 10429590837bSKentaro Takeda domain->profile, quota_exceeded, 10439590837bSKentaro Takeda transition_failed, 10447d2948b1STetsuo Handa ignore_global_allow_read); 10457d2948b1STetsuo Handa if (!done) 10469590837bSKentaro Takeda break; 10479590837bSKentaro Takeda head->read_step = 2; 10489590837bSKentaro Takeda acl_loop: 10499590837bSKentaro Takeda if (head->read_step == 3) 10509590837bSKentaro Takeda goto tail_mark; 10519590837bSKentaro Takeda /* Print ACL entries in the domain. */ 10529590837bSKentaro Takeda list_for_each_cookie(apos, head->read_var2, 10539590837bSKentaro Takeda &domain->acl_info_list) { 10549590837bSKentaro Takeda struct tomoyo_acl_info *ptr 10559590837bSKentaro Takeda = list_entry(apos, struct tomoyo_acl_info, 10569590837bSKentaro Takeda list); 10577d2948b1STetsuo Handa done = tomoyo_print_entry(head, ptr); 10587d2948b1STetsuo Handa if (!done) 10599590837bSKentaro Takeda break; 10609590837bSKentaro Takeda } 10619590837bSKentaro Takeda if (!done) 10629590837bSKentaro Takeda break; 10639590837bSKentaro Takeda head->read_step = 3; 10649590837bSKentaro Takeda tail_mark: 10657d2948b1STetsuo Handa done = tomoyo_io_printf(head, "\n"); 10667d2948b1STetsuo Handa if (!done) 10679590837bSKentaro Takeda break; 10689590837bSKentaro Takeda head->read_step = 1; 10699590837bSKentaro Takeda if (head->read_single_domain) 10709590837bSKentaro Takeda break; 10719590837bSKentaro Takeda } 10729590837bSKentaro Takeda head->read_eof = done; 10739590837bSKentaro Takeda return 0; 10749590837bSKentaro Takeda } 10759590837bSKentaro Takeda 10769590837bSKentaro Takeda /** 10779590837bSKentaro Takeda * tomoyo_write_domain_profile - Assign profile for specified domain. 10789590837bSKentaro Takeda * 10799590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 10809590837bSKentaro Takeda * 10819590837bSKentaro Takeda * Returns 0 on success, -EINVAL otherwise. 10829590837bSKentaro Takeda * 10839590837bSKentaro Takeda * This is equivalent to doing 10849590837bSKentaro Takeda * 10859590837bSKentaro Takeda * ( echo "select " $domainname; echo "use_profile " $profile ) | 10869b244373STetsuo Handa * /usr/sbin/tomoyo-loadpolicy -d 1087fdb8ebb7STetsuo Handa * 1088fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 10899590837bSKentaro Takeda */ 10909590837bSKentaro Takeda static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head) 10919590837bSKentaro Takeda { 10929590837bSKentaro Takeda char *data = head->write_buf; 10939590837bSKentaro Takeda char *cp = strchr(data, ' '); 10949590837bSKentaro Takeda struct tomoyo_domain_info *domain; 10959590837bSKentaro Takeda unsigned long profile; 10969590837bSKentaro Takeda 10979590837bSKentaro Takeda if (!cp) 10989590837bSKentaro Takeda return -EINVAL; 10999590837bSKentaro Takeda *cp = '\0'; 11009590837bSKentaro Takeda domain = tomoyo_find_domain(cp + 1); 11019590837bSKentaro Takeda if (strict_strtoul(data, 10, &profile)) 11029590837bSKentaro Takeda return -EINVAL; 11039590837bSKentaro Takeda if (domain && profile < TOMOYO_MAX_PROFILES 11049590837bSKentaro Takeda && (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded)) 11059590837bSKentaro Takeda domain->profile = (u8) profile; 11069590837bSKentaro Takeda return 0; 11079590837bSKentaro Takeda } 11089590837bSKentaro Takeda 11099590837bSKentaro Takeda /** 11109590837bSKentaro Takeda * tomoyo_read_domain_profile - Read only domainname and profile. 11119590837bSKentaro Takeda * 11129590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 11139590837bSKentaro Takeda * 11149590837bSKentaro Takeda * Returns list of profile number and domainname pairs. 11159590837bSKentaro Takeda * 11169590837bSKentaro Takeda * This is equivalent to doing 11179590837bSKentaro Takeda * 11189590837bSKentaro Takeda * grep -A 1 '^<kernel>' /sys/kernel/security/tomoyo/domain_policy | 11199590837bSKentaro Takeda * awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" ) 11209590837bSKentaro Takeda * domainname = $0; } else if ( $1 == "use_profile" ) { 11219590837bSKentaro Takeda * print $2 " " domainname; domainname = ""; } } ; ' 1122fdb8ebb7STetsuo Handa * 1123fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 11249590837bSKentaro Takeda */ 11259590837bSKentaro Takeda static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head) 11269590837bSKentaro Takeda { 11279590837bSKentaro Takeda struct list_head *pos; 11289590837bSKentaro Takeda bool done = true; 11299590837bSKentaro Takeda 11309590837bSKentaro Takeda if (head->read_eof) 11319590837bSKentaro Takeda return 0; 11329590837bSKentaro Takeda list_for_each_cookie(pos, head->read_var1, &tomoyo_domain_list) { 11339590837bSKentaro Takeda struct tomoyo_domain_info *domain; 11349590837bSKentaro Takeda domain = list_entry(pos, struct tomoyo_domain_info, list); 11359590837bSKentaro Takeda if (domain->is_deleted) 11369590837bSKentaro Takeda continue; 11377d2948b1STetsuo Handa done = tomoyo_io_printf(head, "%u %s\n", domain->profile, 11387d2948b1STetsuo Handa domain->domainname->name); 11397d2948b1STetsuo Handa if (!done) 11409590837bSKentaro Takeda break; 11419590837bSKentaro Takeda } 11429590837bSKentaro Takeda head->read_eof = done; 11439590837bSKentaro Takeda return 0; 11449590837bSKentaro Takeda } 11459590837bSKentaro Takeda 11469590837bSKentaro Takeda /** 11479590837bSKentaro Takeda * tomoyo_write_pid: Specify PID to obtain domainname. 11489590837bSKentaro Takeda * 11499590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 11509590837bSKentaro Takeda * 11519590837bSKentaro Takeda * Returns 0. 11529590837bSKentaro Takeda */ 11539590837bSKentaro Takeda static int tomoyo_write_pid(struct tomoyo_io_buffer *head) 11549590837bSKentaro Takeda { 11559590837bSKentaro Takeda unsigned long pid; 11569590837bSKentaro Takeda /* No error check. */ 11579590837bSKentaro Takeda strict_strtoul(head->write_buf, 10, &pid); 11589590837bSKentaro Takeda head->read_step = (int) pid; 11599590837bSKentaro Takeda head->read_eof = false; 11609590837bSKentaro Takeda return 0; 11619590837bSKentaro Takeda } 11629590837bSKentaro Takeda 11639590837bSKentaro Takeda /** 11649590837bSKentaro Takeda * tomoyo_read_pid - Get domainname of the specified PID. 11659590837bSKentaro Takeda * 11669590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 11679590837bSKentaro Takeda * 11689590837bSKentaro Takeda * Returns the domainname which the specified PID is in on success, 11699590837bSKentaro Takeda * empty string otherwise. 11709590837bSKentaro Takeda * The PID is specified by tomoyo_write_pid() so that the user can obtain 11719590837bSKentaro Takeda * using read()/write() interface rather than sysctl() interface. 11729590837bSKentaro Takeda */ 11739590837bSKentaro Takeda static int tomoyo_read_pid(struct tomoyo_io_buffer *head) 11749590837bSKentaro Takeda { 11759590837bSKentaro Takeda if (head->read_avail == 0 && !head->read_eof) { 11769590837bSKentaro Takeda const int pid = head->read_step; 11779590837bSKentaro Takeda struct task_struct *p; 11789590837bSKentaro Takeda struct tomoyo_domain_info *domain = NULL; 11791fcdc7c5STetsuo Handa rcu_read_lock(); 11809590837bSKentaro Takeda read_lock(&tasklist_lock); 11819590837bSKentaro Takeda p = find_task_by_vpid(pid); 11829590837bSKentaro Takeda if (p) 11839590837bSKentaro Takeda domain = tomoyo_real_domain(p); 11849590837bSKentaro Takeda read_unlock(&tasklist_lock); 11851fcdc7c5STetsuo Handa rcu_read_unlock(); 11869590837bSKentaro Takeda if (domain) 11879590837bSKentaro Takeda tomoyo_io_printf(head, "%d %u %s", pid, domain->profile, 11889590837bSKentaro Takeda domain->domainname->name); 11899590837bSKentaro Takeda head->read_eof = true; 11909590837bSKentaro Takeda } 11919590837bSKentaro Takeda return 0; 11929590837bSKentaro Takeda } 11939590837bSKentaro Takeda 11949590837bSKentaro Takeda /** 11959590837bSKentaro Takeda * tomoyo_write_exception_policy - Write exception policy. 11969590837bSKentaro Takeda * 11979590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 11989590837bSKentaro Takeda * 11999590837bSKentaro Takeda * Returns 0 on success, negative value otherwise. 1200fdb8ebb7STetsuo Handa * 1201fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 12029590837bSKentaro Takeda */ 12039590837bSKentaro Takeda static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head) 12049590837bSKentaro Takeda { 12059590837bSKentaro Takeda char *data = head->write_buf; 12069590837bSKentaro Takeda bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE); 12079590837bSKentaro Takeda 12089590837bSKentaro Takeda if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_KEEP_DOMAIN)) 12099590837bSKentaro Takeda return tomoyo_write_domain_keeper_policy(data, false, 12109590837bSKentaro Takeda is_delete); 12119590837bSKentaro Takeda if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_KEEP_DOMAIN)) 12129590837bSKentaro Takeda return tomoyo_write_domain_keeper_policy(data, true, is_delete); 12139590837bSKentaro Takeda if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_INITIALIZE_DOMAIN)) 12149590837bSKentaro Takeda return tomoyo_write_domain_initializer_policy(data, false, 12159590837bSKentaro Takeda is_delete); 12169590837bSKentaro Takeda if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN)) 12179590837bSKentaro Takeda return tomoyo_write_domain_initializer_policy(data, true, 12189590837bSKentaro Takeda is_delete); 12191084307cSTetsuo Handa if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_AGGREGATOR)) 12201084307cSTetsuo Handa return tomoyo_write_aggregator_policy(data, is_delete); 12219590837bSKentaro Takeda if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALIAS)) 12229590837bSKentaro Takeda return tomoyo_write_alias_policy(data, is_delete); 12239590837bSKentaro Takeda if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_READ)) 12249590837bSKentaro Takeda return tomoyo_write_globally_readable_policy(data, is_delete); 12259590837bSKentaro Takeda if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_FILE_PATTERN)) 12269590837bSKentaro Takeda return tomoyo_write_pattern_policy(data, is_delete); 12279590837bSKentaro Takeda if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DENY_REWRITE)) 12289590837bSKentaro Takeda return tomoyo_write_no_rewrite_policy(data, is_delete); 12297762fbffSTetsuo Handa if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_PATH_GROUP)) 12307762fbffSTetsuo Handa return tomoyo_write_path_group_policy(data, is_delete); 12314c3e9e2dSTetsuo Handa if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NUMBER_GROUP)) 12324c3e9e2dSTetsuo Handa return tomoyo_write_number_group_policy(data, is_delete); 12339590837bSKentaro Takeda return -EINVAL; 12349590837bSKentaro Takeda } 12359590837bSKentaro Takeda 12369590837bSKentaro Takeda /** 12379590837bSKentaro Takeda * tomoyo_read_exception_policy - Read exception policy. 12389590837bSKentaro Takeda * 12399590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 12409590837bSKentaro Takeda * 12419590837bSKentaro Takeda * Returns 0 on success, -EINVAL otherwise. 1242fdb8ebb7STetsuo Handa * 1243fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 12449590837bSKentaro Takeda */ 12459590837bSKentaro Takeda static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head) 12469590837bSKentaro Takeda { 12479590837bSKentaro Takeda if (!head->read_eof) { 12489590837bSKentaro Takeda switch (head->read_step) { 12499590837bSKentaro Takeda case 0: 12509590837bSKentaro Takeda head->read_var2 = NULL; 12519590837bSKentaro Takeda head->read_step = 1; 12529590837bSKentaro Takeda case 1: 12539590837bSKentaro Takeda if (!tomoyo_read_domain_keeper_policy(head)) 12549590837bSKentaro Takeda break; 12559590837bSKentaro Takeda head->read_var2 = NULL; 12569590837bSKentaro Takeda head->read_step = 2; 12579590837bSKentaro Takeda case 2: 12589590837bSKentaro Takeda if (!tomoyo_read_globally_readable_policy(head)) 12599590837bSKentaro Takeda break; 12609590837bSKentaro Takeda head->read_var2 = NULL; 12619590837bSKentaro Takeda head->read_step = 3; 12629590837bSKentaro Takeda case 3: 12639590837bSKentaro Takeda head->read_var2 = NULL; 12649590837bSKentaro Takeda head->read_step = 4; 12659590837bSKentaro Takeda case 4: 12669590837bSKentaro Takeda if (!tomoyo_read_domain_initializer_policy(head)) 12679590837bSKentaro Takeda break; 12689590837bSKentaro Takeda head->read_var2 = NULL; 12699590837bSKentaro Takeda head->read_step = 5; 12709590837bSKentaro Takeda case 5: 12719590837bSKentaro Takeda if (!tomoyo_read_alias_policy(head)) 12729590837bSKentaro Takeda break; 12739590837bSKentaro Takeda head->read_var2 = NULL; 12749590837bSKentaro Takeda head->read_step = 6; 12759590837bSKentaro Takeda case 6: 12761084307cSTetsuo Handa if (!tomoyo_read_aggregator_policy(head)) 12771084307cSTetsuo Handa break; 12789590837bSKentaro Takeda head->read_var2 = NULL; 12799590837bSKentaro Takeda head->read_step = 7; 12809590837bSKentaro Takeda case 7: 12819590837bSKentaro Takeda if (!tomoyo_read_file_pattern(head)) 12829590837bSKentaro Takeda break; 12839590837bSKentaro Takeda head->read_var2 = NULL; 12849590837bSKentaro Takeda head->read_step = 8; 12859590837bSKentaro Takeda case 8: 12869590837bSKentaro Takeda if (!tomoyo_read_no_rewrite_policy(head)) 12879590837bSKentaro Takeda break; 12889590837bSKentaro Takeda head->read_var2 = NULL; 12899590837bSKentaro Takeda head->read_step = 9; 12909590837bSKentaro Takeda case 9: 12917762fbffSTetsuo Handa if (!tomoyo_read_path_group_policy(head)) 12927762fbffSTetsuo Handa break; 12937762fbffSTetsuo Handa head->read_var1 = NULL; 12947762fbffSTetsuo Handa head->read_var2 = NULL; 12957762fbffSTetsuo Handa head->read_step = 10; 12967762fbffSTetsuo Handa case 10: 12974c3e9e2dSTetsuo Handa if (!tomoyo_read_number_group_policy(head)) 12984c3e9e2dSTetsuo Handa break; 12994c3e9e2dSTetsuo Handa head->read_var1 = NULL; 13004c3e9e2dSTetsuo Handa head->read_var2 = NULL; 13014c3e9e2dSTetsuo Handa head->read_step = 11; 13024c3e9e2dSTetsuo Handa case 11: 13039590837bSKentaro Takeda head->read_eof = true; 13049590837bSKentaro Takeda break; 13059590837bSKentaro Takeda default: 13069590837bSKentaro Takeda return -EINVAL; 13079590837bSKentaro Takeda } 13089590837bSKentaro Takeda } 13099590837bSKentaro Takeda return 0; 13109590837bSKentaro Takeda } 13119590837bSKentaro Takeda 13129590837bSKentaro Takeda /** 131317fcfbd9STetsuo Handa * tomoyo_print_header - Get header line of audit log. 131417fcfbd9STetsuo Handa * 131517fcfbd9STetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 131617fcfbd9STetsuo Handa * 131717fcfbd9STetsuo Handa * Returns string representation. 131817fcfbd9STetsuo Handa * 131917fcfbd9STetsuo Handa * This function uses kmalloc(), so caller must kfree() if this function 132017fcfbd9STetsuo Handa * didn't return NULL. 132117fcfbd9STetsuo Handa */ 132217fcfbd9STetsuo Handa static char *tomoyo_print_header(struct tomoyo_request_info *r) 132317fcfbd9STetsuo Handa { 132417fcfbd9STetsuo Handa static const char *tomoyo_mode_4[4] = { 132517fcfbd9STetsuo Handa "disabled", "learning", "permissive", "enforcing" 132617fcfbd9STetsuo Handa }; 132717fcfbd9STetsuo Handa struct timeval tv; 132817fcfbd9STetsuo Handa const pid_t gpid = task_pid_nr(current); 132917fcfbd9STetsuo Handa static const int tomoyo_buffer_len = 4096; 133017fcfbd9STetsuo Handa char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS); 133117fcfbd9STetsuo Handa if (!buffer) 133217fcfbd9STetsuo Handa return NULL; 133317fcfbd9STetsuo Handa do_gettimeofday(&tv); 133417fcfbd9STetsuo Handa snprintf(buffer, tomoyo_buffer_len - 1, 133517fcfbd9STetsuo Handa "#timestamp=%lu profile=%u mode=%s (global-pid=%u)" 133617fcfbd9STetsuo Handa " task={ pid=%u ppid=%u uid=%u gid=%u euid=%u" 133717fcfbd9STetsuo Handa " egid=%u suid=%u sgid=%u fsuid=%u fsgid=%u }", 133817fcfbd9STetsuo Handa tv.tv_sec, r->profile, tomoyo_mode_4[r->mode], gpid, 133917fcfbd9STetsuo Handa (pid_t) sys_getpid(), (pid_t) sys_getppid(), 134017fcfbd9STetsuo Handa current_uid(), current_gid(), current_euid(), 134117fcfbd9STetsuo Handa current_egid(), current_suid(), current_sgid(), 134217fcfbd9STetsuo Handa current_fsuid(), current_fsgid()); 134317fcfbd9STetsuo Handa return buffer; 134417fcfbd9STetsuo Handa } 134517fcfbd9STetsuo Handa 134617fcfbd9STetsuo Handa /** 134717fcfbd9STetsuo Handa * tomoyo_init_audit_log - Allocate buffer for audit logs. 134817fcfbd9STetsuo Handa * 134917fcfbd9STetsuo Handa * @len: Required size. 135017fcfbd9STetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 135117fcfbd9STetsuo Handa * 135217fcfbd9STetsuo Handa * Returns pointer to allocated memory. 135317fcfbd9STetsuo Handa * 135417fcfbd9STetsuo Handa * The @len is updated to add the header lines' size on success. 135517fcfbd9STetsuo Handa * 135617fcfbd9STetsuo Handa * This function uses kzalloc(), so caller must kfree() if this function 135717fcfbd9STetsuo Handa * didn't return NULL. 135817fcfbd9STetsuo Handa */ 135917fcfbd9STetsuo Handa static char *tomoyo_init_audit_log(int *len, struct tomoyo_request_info *r) 136017fcfbd9STetsuo Handa { 136117fcfbd9STetsuo Handa char *buf = NULL; 136217fcfbd9STetsuo Handa const char *header; 136317fcfbd9STetsuo Handa const char *domainname; 136417fcfbd9STetsuo Handa if (!r->domain) 136517fcfbd9STetsuo Handa r->domain = tomoyo_domain(); 136617fcfbd9STetsuo Handa domainname = r->domain->domainname->name; 136717fcfbd9STetsuo Handa header = tomoyo_print_header(r); 136817fcfbd9STetsuo Handa if (!header) 136917fcfbd9STetsuo Handa return NULL; 137017fcfbd9STetsuo Handa *len += strlen(domainname) + strlen(header) + 10; 137117fcfbd9STetsuo Handa buf = kzalloc(*len, GFP_NOFS); 137217fcfbd9STetsuo Handa if (buf) 137317fcfbd9STetsuo Handa snprintf(buf, (*len) - 1, "%s\n%s\n", header, domainname); 137417fcfbd9STetsuo Handa kfree(header); 137517fcfbd9STetsuo Handa return buf; 137617fcfbd9STetsuo Handa } 137717fcfbd9STetsuo Handa 137817fcfbd9STetsuo Handa /* Wait queue for tomoyo_query_list. */ 137917fcfbd9STetsuo Handa static DECLARE_WAIT_QUEUE_HEAD(tomoyo_query_wait); 138017fcfbd9STetsuo Handa 138117fcfbd9STetsuo Handa /* Lock for manipulating tomoyo_query_list. */ 138217fcfbd9STetsuo Handa static DEFINE_SPINLOCK(tomoyo_query_list_lock); 138317fcfbd9STetsuo Handa 138417fcfbd9STetsuo Handa /* Structure for query. */ 138517fcfbd9STetsuo Handa struct tomoyo_query_entry { 138617fcfbd9STetsuo Handa struct list_head list; 138717fcfbd9STetsuo Handa char *query; 138817fcfbd9STetsuo Handa int query_len; 138917fcfbd9STetsuo Handa unsigned int serial; 139017fcfbd9STetsuo Handa int timer; 139117fcfbd9STetsuo Handa int answer; 139217fcfbd9STetsuo Handa }; 139317fcfbd9STetsuo Handa 139417fcfbd9STetsuo Handa /* The list for "struct tomoyo_query_entry". */ 139517fcfbd9STetsuo Handa static LIST_HEAD(tomoyo_query_list); 139617fcfbd9STetsuo Handa 139717fcfbd9STetsuo Handa /* 139817fcfbd9STetsuo Handa * Number of "struct file" referring /sys/kernel/security/tomoyo/query 139917fcfbd9STetsuo Handa * interface. 140017fcfbd9STetsuo Handa */ 140117fcfbd9STetsuo Handa static atomic_t tomoyo_query_observers = ATOMIC_INIT(0); 140217fcfbd9STetsuo Handa 140317fcfbd9STetsuo Handa /** 140417fcfbd9STetsuo Handa * tomoyo_supervisor - Ask for the supervisor's decision. 140517fcfbd9STetsuo Handa * 140617fcfbd9STetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 140717fcfbd9STetsuo Handa * @fmt: The printf()'s format string, followed by parameters. 140817fcfbd9STetsuo Handa * 140917fcfbd9STetsuo Handa * Returns 0 if the supervisor decided to permit the access request which 141017fcfbd9STetsuo Handa * violated the policy in enforcing mode, TOMOYO_RETRY_REQUEST if the 141117fcfbd9STetsuo Handa * supervisor decided to retry the access request which violated the policy in 141217fcfbd9STetsuo Handa * enforcing mode, 0 if it is not in enforcing mode, -EPERM otherwise. 141317fcfbd9STetsuo Handa */ 141417fcfbd9STetsuo Handa int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) 141517fcfbd9STetsuo Handa { 141617fcfbd9STetsuo Handa va_list args; 141717fcfbd9STetsuo Handa int error = -EPERM; 141817fcfbd9STetsuo Handa int pos; 141917fcfbd9STetsuo Handa int len; 142017fcfbd9STetsuo Handa static unsigned int tomoyo_serial; 142117fcfbd9STetsuo Handa struct tomoyo_query_entry *tomoyo_query_entry = NULL; 142217fcfbd9STetsuo Handa bool quota_exceeded = false; 142317fcfbd9STetsuo Handa char *header; 142417fcfbd9STetsuo Handa switch (r->mode) { 142517fcfbd9STetsuo Handa char *buffer; 142617fcfbd9STetsuo Handa case TOMOYO_CONFIG_LEARNING: 142717fcfbd9STetsuo Handa if (!tomoyo_domain_quota_is_ok(r)) 142817fcfbd9STetsuo Handa return 0; 142917fcfbd9STetsuo Handa va_start(args, fmt); 143017fcfbd9STetsuo Handa len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 4; 143117fcfbd9STetsuo Handa va_end(args); 143217fcfbd9STetsuo Handa buffer = kmalloc(len, GFP_NOFS); 143317fcfbd9STetsuo Handa if (!buffer) 143417fcfbd9STetsuo Handa return 0; 143517fcfbd9STetsuo Handa va_start(args, fmt); 143617fcfbd9STetsuo Handa vsnprintf(buffer, len - 1, fmt, args); 143717fcfbd9STetsuo Handa va_end(args); 143817fcfbd9STetsuo Handa tomoyo_normalize_line(buffer); 143917fcfbd9STetsuo Handa tomoyo_write_domain_policy2(buffer, r->domain, false); 144017fcfbd9STetsuo Handa kfree(buffer); 144117fcfbd9STetsuo Handa /* fall through */ 144217fcfbd9STetsuo Handa case TOMOYO_CONFIG_PERMISSIVE: 144317fcfbd9STetsuo Handa return 0; 144417fcfbd9STetsuo Handa } 144517fcfbd9STetsuo Handa if (!r->domain) 144617fcfbd9STetsuo Handa r->domain = tomoyo_domain(); 144717fcfbd9STetsuo Handa if (!atomic_read(&tomoyo_query_observers)) 144817fcfbd9STetsuo Handa return -EPERM; 144917fcfbd9STetsuo Handa va_start(args, fmt); 145017fcfbd9STetsuo Handa len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 32; 145117fcfbd9STetsuo Handa va_end(args); 145217fcfbd9STetsuo Handa header = tomoyo_init_audit_log(&len, r); 145317fcfbd9STetsuo Handa if (!header) 145417fcfbd9STetsuo Handa goto out; 145517fcfbd9STetsuo Handa tomoyo_query_entry = kzalloc(sizeof(*tomoyo_query_entry), GFP_NOFS); 145617fcfbd9STetsuo Handa if (!tomoyo_query_entry) 145717fcfbd9STetsuo Handa goto out; 145817fcfbd9STetsuo Handa tomoyo_query_entry->query = kzalloc(len, GFP_NOFS); 145917fcfbd9STetsuo Handa if (!tomoyo_query_entry->query) 146017fcfbd9STetsuo Handa goto out; 146117fcfbd9STetsuo Handa len = ksize(tomoyo_query_entry->query); 146217fcfbd9STetsuo Handa INIT_LIST_HEAD(&tomoyo_query_entry->list); 146317fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 146417fcfbd9STetsuo Handa if (tomoyo_quota_for_query && tomoyo_query_memory_size + len + 146517fcfbd9STetsuo Handa sizeof(*tomoyo_query_entry) >= tomoyo_quota_for_query) { 146617fcfbd9STetsuo Handa quota_exceeded = true; 146717fcfbd9STetsuo Handa } else { 146817fcfbd9STetsuo Handa tomoyo_query_memory_size += len + sizeof(*tomoyo_query_entry); 146917fcfbd9STetsuo Handa tomoyo_query_entry->serial = tomoyo_serial++; 147017fcfbd9STetsuo Handa } 147117fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 147217fcfbd9STetsuo Handa if (quota_exceeded) 147317fcfbd9STetsuo Handa goto out; 147417fcfbd9STetsuo Handa pos = snprintf(tomoyo_query_entry->query, len - 1, "Q%u-%hu\n%s", 147517fcfbd9STetsuo Handa tomoyo_query_entry->serial, r->retry, header); 147617fcfbd9STetsuo Handa kfree(header); 147717fcfbd9STetsuo Handa header = NULL; 147817fcfbd9STetsuo Handa va_start(args, fmt); 147917fcfbd9STetsuo Handa vsnprintf(tomoyo_query_entry->query + pos, len - 1 - pos, fmt, args); 148017fcfbd9STetsuo Handa tomoyo_query_entry->query_len = strlen(tomoyo_query_entry->query) + 1; 148117fcfbd9STetsuo Handa va_end(args); 148217fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 148317fcfbd9STetsuo Handa list_add_tail(&tomoyo_query_entry->list, &tomoyo_query_list); 148417fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 148517fcfbd9STetsuo Handa /* Give 10 seconds for supervisor's opinion. */ 148617fcfbd9STetsuo Handa for (tomoyo_query_entry->timer = 0; 148717fcfbd9STetsuo Handa atomic_read(&tomoyo_query_observers) && tomoyo_query_entry->timer < 100; 148817fcfbd9STetsuo Handa tomoyo_query_entry->timer++) { 148917fcfbd9STetsuo Handa wake_up(&tomoyo_query_wait); 149017fcfbd9STetsuo Handa set_current_state(TASK_INTERRUPTIBLE); 149117fcfbd9STetsuo Handa schedule_timeout(HZ / 10); 149217fcfbd9STetsuo Handa if (tomoyo_query_entry->answer) 149317fcfbd9STetsuo Handa break; 149417fcfbd9STetsuo Handa } 149517fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 149617fcfbd9STetsuo Handa list_del(&tomoyo_query_entry->list); 149717fcfbd9STetsuo Handa tomoyo_query_memory_size -= len + sizeof(*tomoyo_query_entry); 149817fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 149917fcfbd9STetsuo Handa switch (tomoyo_query_entry->answer) { 150017fcfbd9STetsuo Handa case 3: /* Asked to retry by administrator. */ 150117fcfbd9STetsuo Handa error = TOMOYO_RETRY_REQUEST; 150217fcfbd9STetsuo Handa r->retry++; 150317fcfbd9STetsuo Handa break; 150417fcfbd9STetsuo Handa case 1: 150517fcfbd9STetsuo Handa /* Granted by administrator. */ 150617fcfbd9STetsuo Handa error = 0; 150717fcfbd9STetsuo Handa break; 150817fcfbd9STetsuo Handa case 0: 150917fcfbd9STetsuo Handa /* Timed out. */ 151017fcfbd9STetsuo Handa break; 151117fcfbd9STetsuo Handa default: 151217fcfbd9STetsuo Handa /* Rejected by administrator. */ 151317fcfbd9STetsuo Handa break; 151417fcfbd9STetsuo Handa } 151517fcfbd9STetsuo Handa out: 151617fcfbd9STetsuo Handa if (tomoyo_query_entry) 151717fcfbd9STetsuo Handa kfree(tomoyo_query_entry->query); 151817fcfbd9STetsuo Handa kfree(tomoyo_query_entry); 151917fcfbd9STetsuo Handa kfree(header); 152017fcfbd9STetsuo Handa return error; 152117fcfbd9STetsuo Handa } 152217fcfbd9STetsuo Handa 152317fcfbd9STetsuo Handa /** 152417fcfbd9STetsuo Handa * tomoyo_poll_query - poll() for /sys/kernel/security/tomoyo/query. 152517fcfbd9STetsuo Handa * 152617fcfbd9STetsuo Handa * @file: Pointer to "struct file". 152717fcfbd9STetsuo Handa * @wait: Pointer to "poll_table". 152817fcfbd9STetsuo Handa * 152917fcfbd9STetsuo Handa * Returns POLLIN | POLLRDNORM when ready to read, 0 otherwise. 153017fcfbd9STetsuo Handa * 153117fcfbd9STetsuo Handa * Waits for access requests which violated policy in enforcing mode. 153217fcfbd9STetsuo Handa */ 153317fcfbd9STetsuo Handa static int tomoyo_poll_query(struct file *file, poll_table *wait) 153417fcfbd9STetsuo Handa { 153517fcfbd9STetsuo Handa struct list_head *tmp; 153617fcfbd9STetsuo Handa bool found = false; 153717fcfbd9STetsuo Handa u8 i; 153817fcfbd9STetsuo Handa for (i = 0; i < 2; i++) { 153917fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 154017fcfbd9STetsuo Handa list_for_each(tmp, &tomoyo_query_list) { 154117fcfbd9STetsuo Handa struct tomoyo_query_entry *ptr 154217fcfbd9STetsuo Handa = list_entry(tmp, struct tomoyo_query_entry, 154317fcfbd9STetsuo Handa list); 154417fcfbd9STetsuo Handa if (ptr->answer) 154517fcfbd9STetsuo Handa continue; 154617fcfbd9STetsuo Handa found = true; 154717fcfbd9STetsuo Handa break; 154817fcfbd9STetsuo Handa } 154917fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 155017fcfbd9STetsuo Handa if (found) 155117fcfbd9STetsuo Handa return POLLIN | POLLRDNORM; 155217fcfbd9STetsuo Handa if (i) 155317fcfbd9STetsuo Handa break; 155417fcfbd9STetsuo Handa poll_wait(file, &tomoyo_query_wait, wait); 155517fcfbd9STetsuo Handa } 155617fcfbd9STetsuo Handa return 0; 155717fcfbd9STetsuo Handa } 155817fcfbd9STetsuo Handa 155917fcfbd9STetsuo Handa /** 156017fcfbd9STetsuo Handa * tomoyo_read_query - Read access requests which violated policy in enforcing mode. 156117fcfbd9STetsuo Handa * 156217fcfbd9STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 156317fcfbd9STetsuo Handa * 156417fcfbd9STetsuo Handa * Returns 0. 156517fcfbd9STetsuo Handa */ 156617fcfbd9STetsuo Handa static int tomoyo_read_query(struct tomoyo_io_buffer *head) 156717fcfbd9STetsuo Handa { 156817fcfbd9STetsuo Handa struct list_head *tmp; 156917fcfbd9STetsuo Handa int pos = 0; 157017fcfbd9STetsuo Handa int len = 0; 157117fcfbd9STetsuo Handa char *buf; 157217fcfbd9STetsuo Handa if (head->read_avail) 157317fcfbd9STetsuo Handa return 0; 157417fcfbd9STetsuo Handa if (head->read_buf) { 157517fcfbd9STetsuo Handa kfree(head->read_buf); 157617fcfbd9STetsuo Handa head->read_buf = NULL; 157717fcfbd9STetsuo Handa head->readbuf_size = 0; 157817fcfbd9STetsuo Handa } 157917fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 158017fcfbd9STetsuo Handa list_for_each(tmp, &tomoyo_query_list) { 158117fcfbd9STetsuo Handa struct tomoyo_query_entry *ptr 158217fcfbd9STetsuo Handa = list_entry(tmp, struct tomoyo_query_entry, list); 158317fcfbd9STetsuo Handa if (ptr->answer) 158417fcfbd9STetsuo Handa continue; 158517fcfbd9STetsuo Handa if (pos++ != head->read_step) 158617fcfbd9STetsuo Handa continue; 158717fcfbd9STetsuo Handa len = ptr->query_len; 158817fcfbd9STetsuo Handa break; 158917fcfbd9STetsuo Handa } 159017fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 159117fcfbd9STetsuo Handa if (!len) { 159217fcfbd9STetsuo Handa head->read_step = 0; 159317fcfbd9STetsuo Handa return 0; 159417fcfbd9STetsuo Handa } 159517fcfbd9STetsuo Handa buf = kzalloc(len, GFP_NOFS); 159617fcfbd9STetsuo Handa if (!buf) 159717fcfbd9STetsuo Handa return 0; 159817fcfbd9STetsuo Handa pos = 0; 159917fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 160017fcfbd9STetsuo Handa list_for_each(tmp, &tomoyo_query_list) { 160117fcfbd9STetsuo Handa struct tomoyo_query_entry *ptr 160217fcfbd9STetsuo Handa = list_entry(tmp, struct tomoyo_query_entry, list); 160317fcfbd9STetsuo Handa if (ptr->answer) 160417fcfbd9STetsuo Handa continue; 160517fcfbd9STetsuo Handa if (pos++ != head->read_step) 160617fcfbd9STetsuo Handa continue; 160717fcfbd9STetsuo Handa /* 160817fcfbd9STetsuo Handa * Some query can be skipped because tomoyo_query_list 160917fcfbd9STetsuo Handa * can change, but I don't care. 161017fcfbd9STetsuo Handa */ 161117fcfbd9STetsuo Handa if (len == ptr->query_len) 161217fcfbd9STetsuo Handa memmove(buf, ptr->query, len); 161317fcfbd9STetsuo Handa break; 161417fcfbd9STetsuo Handa } 161517fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 161617fcfbd9STetsuo Handa if (buf[0]) { 161717fcfbd9STetsuo Handa head->read_avail = len; 161817fcfbd9STetsuo Handa head->readbuf_size = head->read_avail; 161917fcfbd9STetsuo Handa head->read_buf = buf; 162017fcfbd9STetsuo Handa head->read_step++; 162117fcfbd9STetsuo Handa } else { 162217fcfbd9STetsuo Handa kfree(buf); 162317fcfbd9STetsuo Handa } 162417fcfbd9STetsuo Handa return 0; 162517fcfbd9STetsuo Handa } 162617fcfbd9STetsuo Handa 162717fcfbd9STetsuo Handa /** 162817fcfbd9STetsuo Handa * tomoyo_write_answer - Write the supervisor's decision. 162917fcfbd9STetsuo Handa * 163017fcfbd9STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 163117fcfbd9STetsuo Handa * 163217fcfbd9STetsuo Handa * Returns 0 on success, -EINVAL otherwise. 163317fcfbd9STetsuo Handa */ 163417fcfbd9STetsuo Handa static int tomoyo_write_answer(struct tomoyo_io_buffer *head) 163517fcfbd9STetsuo Handa { 163617fcfbd9STetsuo Handa char *data = head->write_buf; 163717fcfbd9STetsuo Handa struct list_head *tmp; 163817fcfbd9STetsuo Handa unsigned int serial; 163917fcfbd9STetsuo Handa unsigned int answer; 164017fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 164117fcfbd9STetsuo Handa list_for_each(tmp, &tomoyo_query_list) { 164217fcfbd9STetsuo Handa struct tomoyo_query_entry *ptr 164317fcfbd9STetsuo Handa = list_entry(tmp, struct tomoyo_query_entry, list); 164417fcfbd9STetsuo Handa ptr->timer = 0; 164517fcfbd9STetsuo Handa } 164617fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 164717fcfbd9STetsuo Handa if (sscanf(data, "A%u=%u", &serial, &answer) != 2) 164817fcfbd9STetsuo Handa return -EINVAL; 164917fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 165017fcfbd9STetsuo Handa list_for_each(tmp, &tomoyo_query_list) { 165117fcfbd9STetsuo Handa struct tomoyo_query_entry *ptr 165217fcfbd9STetsuo Handa = list_entry(tmp, struct tomoyo_query_entry, list); 165317fcfbd9STetsuo Handa if (ptr->serial != serial) 165417fcfbd9STetsuo Handa continue; 165517fcfbd9STetsuo Handa if (!ptr->answer) 165617fcfbd9STetsuo Handa ptr->answer = answer; 165717fcfbd9STetsuo Handa break; 165817fcfbd9STetsuo Handa } 165917fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 166017fcfbd9STetsuo Handa return 0; 166117fcfbd9STetsuo Handa } 166217fcfbd9STetsuo Handa 166317fcfbd9STetsuo Handa /** 16649590837bSKentaro Takeda * tomoyo_read_version: Get version. 16659590837bSKentaro Takeda * 16669590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 16679590837bSKentaro Takeda * 16689590837bSKentaro Takeda * Returns version information. 16699590837bSKentaro Takeda */ 16709590837bSKentaro Takeda static int tomoyo_read_version(struct tomoyo_io_buffer *head) 16719590837bSKentaro Takeda { 16729590837bSKentaro Takeda if (!head->read_eof) { 167357c2590fSTetsuo Handa tomoyo_io_printf(head, "2.3.0-pre"); 16749590837bSKentaro Takeda head->read_eof = true; 16759590837bSKentaro Takeda } 16769590837bSKentaro Takeda return 0; 16779590837bSKentaro Takeda } 16789590837bSKentaro Takeda 16799590837bSKentaro Takeda /** 16809590837bSKentaro Takeda * tomoyo_read_self_domain - Get the current process's domainname. 16819590837bSKentaro Takeda * 16829590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 16839590837bSKentaro Takeda * 16849590837bSKentaro Takeda * Returns the current process's domainname. 16859590837bSKentaro Takeda */ 16869590837bSKentaro Takeda static int tomoyo_read_self_domain(struct tomoyo_io_buffer *head) 16879590837bSKentaro Takeda { 16889590837bSKentaro Takeda if (!head->read_eof) { 16899590837bSKentaro Takeda /* 16909590837bSKentaro Takeda * tomoyo_domain()->domainname != NULL 16919590837bSKentaro Takeda * because every process belongs to a domain and 16929590837bSKentaro Takeda * the domain's name cannot be NULL. 16939590837bSKentaro Takeda */ 16949590837bSKentaro Takeda tomoyo_io_printf(head, "%s", tomoyo_domain()->domainname->name); 16959590837bSKentaro Takeda head->read_eof = true; 16969590837bSKentaro Takeda } 16979590837bSKentaro Takeda return 0; 16989590837bSKentaro Takeda } 16999590837bSKentaro Takeda 17009590837bSKentaro Takeda /** 17019590837bSKentaro Takeda * tomoyo_open_control - open() for /sys/kernel/security/tomoyo/ interface. 17029590837bSKentaro Takeda * 17039590837bSKentaro Takeda * @type: Type of interface. 17049590837bSKentaro Takeda * @file: Pointer to "struct file". 17059590837bSKentaro Takeda * 17069590837bSKentaro Takeda * Associates policy handler and returns 0 on success, -ENOMEM otherwise. 1707fdb8ebb7STetsuo Handa * 1708fdb8ebb7STetsuo Handa * Caller acquires tomoyo_read_lock(). 17099590837bSKentaro Takeda */ 1710c3ef1500STetsuo Handa int tomoyo_open_control(const u8 type, struct file *file) 17119590837bSKentaro Takeda { 17124e5d6f7eSTetsuo Handa struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_NOFS); 17139590837bSKentaro Takeda 17149590837bSKentaro Takeda if (!head) 17159590837bSKentaro Takeda return -ENOMEM; 17169590837bSKentaro Takeda mutex_init(&head->io_sem); 171717fcfbd9STetsuo Handa head->type = type; 17189590837bSKentaro Takeda switch (type) { 17199590837bSKentaro Takeda case TOMOYO_DOMAINPOLICY: 17209590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/domain_policy */ 17219590837bSKentaro Takeda head->write = tomoyo_write_domain_policy; 17229590837bSKentaro Takeda head->read = tomoyo_read_domain_policy; 17239590837bSKentaro Takeda break; 17249590837bSKentaro Takeda case TOMOYO_EXCEPTIONPOLICY: 17259590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/exception_policy */ 17269590837bSKentaro Takeda head->write = tomoyo_write_exception_policy; 17279590837bSKentaro Takeda head->read = tomoyo_read_exception_policy; 17289590837bSKentaro Takeda break; 17299590837bSKentaro Takeda case TOMOYO_SELFDOMAIN: 17309590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/self_domain */ 17319590837bSKentaro Takeda head->read = tomoyo_read_self_domain; 17329590837bSKentaro Takeda break; 17339590837bSKentaro Takeda case TOMOYO_DOMAIN_STATUS: 17349590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/.domain_status */ 17359590837bSKentaro Takeda head->write = tomoyo_write_domain_profile; 17369590837bSKentaro Takeda head->read = tomoyo_read_domain_profile; 17379590837bSKentaro Takeda break; 17389590837bSKentaro Takeda case TOMOYO_PROCESS_STATUS: 17399590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/.process_status */ 17409590837bSKentaro Takeda head->write = tomoyo_write_pid; 17419590837bSKentaro Takeda head->read = tomoyo_read_pid; 17429590837bSKentaro Takeda break; 17439590837bSKentaro Takeda case TOMOYO_VERSION: 17449590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/version */ 17459590837bSKentaro Takeda head->read = tomoyo_read_version; 17469590837bSKentaro Takeda head->readbuf_size = 128; 17479590837bSKentaro Takeda break; 17489590837bSKentaro Takeda case TOMOYO_MEMINFO: 17499590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/meminfo */ 17509590837bSKentaro Takeda head->write = tomoyo_write_memory_quota; 17519590837bSKentaro Takeda head->read = tomoyo_read_memory_counter; 17529590837bSKentaro Takeda head->readbuf_size = 512; 17539590837bSKentaro Takeda break; 17549590837bSKentaro Takeda case TOMOYO_PROFILE: 17559590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/profile */ 17569590837bSKentaro Takeda head->write = tomoyo_write_profile; 17579590837bSKentaro Takeda head->read = tomoyo_read_profile; 17589590837bSKentaro Takeda break; 175917fcfbd9STetsuo Handa case TOMOYO_QUERY: /* /sys/kernel/security/tomoyo/query */ 176017fcfbd9STetsuo Handa head->poll = tomoyo_poll_query; 176117fcfbd9STetsuo Handa head->write = tomoyo_write_answer; 176217fcfbd9STetsuo Handa head->read = tomoyo_read_query; 176317fcfbd9STetsuo Handa break; 17649590837bSKentaro Takeda case TOMOYO_MANAGER: 17659590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/manager */ 17669590837bSKentaro Takeda head->write = tomoyo_write_manager_policy; 17679590837bSKentaro Takeda head->read = tomoyo_read_manager_policy; 17689590837bSKentaro Takeda break; 17699590837bSKentaro Takeda } 17709590837bSKentaro Takeda if (!(file->f_mode & FMODE_READ)) { 17719590837bSKentaro Takeda /* 17729590837bSKentaro Takeda * No need to allocate read_buf since it is not opened 17739590837bSKentaro Takeda * for reading. 17749590837bSKentaro Takeda */ 17759590837bSKentaro Takeda head->read = NULL; 177617fcfbd9STetsuo Handa head->poll = NULL; 177717fcfbd9STetsuo Handa } else if (!head->poll) { 177817fcfbd9STetsuo Handa /* Don't allocate read_buf for poll() access. */ 17799590837bSKentaro Takeda if (!head->readbuf_size) 17809590837bSKentaro Takeda head->readbuf_size = 4096 * 2; 17814e5d6f7eSTetsuo Handa head->read_buf = kzalloc(head->readbuf_size, GFP_NOFS); 17829590837bSKentaro Takeda if (!head->read_buf) { 17838e2d39a1STetsuo Handa kfree(head); 17849590837bSKentaro Takeda return -ENOMEM; 17859590837bSKentaro Takeda } 17869590837bSKentaro Takeda } 17879590837bSKentaro Takeda if (!(file->f_mode & FMODE_WRITE)) { 17889590837bSKentaro Takeda /* 17899590837bSKentaro Takeda * No need to allocate write_buf since it is not opened 17909590837bSKentaro Takeda * for writing. 17919590837bSKentaro Takeda */ 17929590837bSKentaro Takeda head->write = NULL; 17939590837bSKentaro Takeda } else if (head->write) { 17949590837bSKentaro Takeda head->writebuf_size = 4096 * 2; 17954e5d6f7eSTetsuo Handa head->write_buf = kzalloc(head->writebuf_size, GFP_NOFS); 17969590837bSKentaro Takeda if (!head->write_buf) { 17978e2d39a1STetsuo Handa kfree(head->read_buf); 17988e2d39a1STetsuo Handa kfree(head); 17999590837bSKentaro Takeda return -ENOMEM; 18009590837bSKentaro Takeda } 18019590837bSKentaro Takeda } 180217fcfbd9STetsuo Handa if (type != TOMOYO_QUERY) 1803fdb8ebb7STetsuo Handa head->reader_idx = tomoyo_read_lock(); 18049590837bSKentaro Takeda file->private_data = head; 18059590837bSKentaro Takeda /* 18069590837bSKentaro Takeda * Call the handler now if the file is 18079590837bSKentaro Takeda * /sys/kernel/security/tomoyo/self_domain 18089590837bSKentaro Takeda * so that the user can use 18099590837bSKentaro Takeda * cat < /sys/kernel/security/tomoyo/self_domain" 18109590837bSKentaro Takeda * to know the current process's domainname. 18119590837bSKentaro Takeda */ 18129590837bSKentaro Takeda if (type == TOMOYO_SELFDOMAIN) 18139590837bSKentaro Takeda tomoyo_read_control(file, NULL, 0); 181417fcfbd9STetsuo Handa /* 181517fcfbd9STetsuo Handa * If the file is /sys/kernel/security/tomoyo/query , increment the 181617fcfbd9STetsuo Handa * observer counter. 181717fcfbd9STetsuo Handa * The obserber counter is used by tomoyo_supervisor() to see if 181817fcfbd9STetsuo Handa * there is some process monitoring /sys/kernel/security/tomoyo/query. 181917fcfbd9STetsuo Handa */ 182017fcfbd9STetsuo Handa else if (type == TOMOYO_QUERY) 182117fcfbd9STetsuo Handa atomic_inc(&tomoyo_query_observers); 18229590837bSKentaro Takeda return 0; 18239590837bSKentaro Takeda } 18249590837bSKentaro Takeda 18259590837bSKentaro Takeda /** 182617fcfbd9STetsuo Handa * tomoyo_poll_control - poll() for /sys/kernel/security/tomoyo/ interface. 182717fcfbd9STetsuo Handa * 182817fcfbd9STetsuo Handa * @file: Pointer to "struct file". 182917fcfbd9STetsuo Handa * @wait: Pointer to "poll_table". 183017fcfbd9STetsuo Handa * 183117fcfbd9STetsuo Handa * Waits for read readiness. 183217fcfbd9STetsuo Handa * /sys/kernel/security/tomoyo/query is handled by /usr/sbin/tomoyo-queryd . 183317fcfbd9STetsuo Handa */ 183417fcfbd9STetsuo Handa int tomoyo_poll_control(struct file *file, poll_table *wait) 183517fcfbd9STetsuo Handa { 183617fcfbd9STetsuo Handa struct tomoyo_io_buffer *head = file->private_data; 183717fcfbd9STetsuo Handa if (!head->poll) 183817fcfbd9STetsuo Handa return -ENOSYS; 183917fcfbd9STetsuo Handa return head->poll(file, wait); 184017fcfbd9STetsuo Handa } 184117fcfbd9STetsuo Handa 184217fcfbd9STetsuo Handa /** 18439590837bSKentaro Takeda * tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface. 18449590837bSKentaro Takeda * 18459590837bSKentaro Takeda * @file: Pointer to "struct file". 18469590837bSKentaro Takeda * @buffer: Poiner to buffer to write to. 18479590837bSKentaro Takeda * @buffer_len: Size of @buffer. 18489590837bSKentaro Takeda * 18499590837bSKentaro Takeda * Returns bytes read on success, negative value otherwise. 1850fdb8ebb7STetsuo Handa * 1851fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 18529590837bSKentaro Takeda */ 1853c3ef1500STetsuo Handa int tomoyo_read_control(struct file *file, char __user *buffer, 18549590837bSKentaro Takeda const int buffer_len) 18559590837bSKentaro Takeda { 18569590837bSKentaro Takeda int len = 0; 18579590837bSKentaro Takeda struct tomoyo_io_buffer *head = file->private_data; 18589590837bSKentaro Takeda char *cp; 18599590837bSKentaro Takeda 18609590837bSKentaro Takeda if (!head->read) 18619590837bSKentaro Takeda return -ENOSYS; 18629590837bSKentaro Takeda if (mutex_lock_interruptible(&head->io_sem)) 18639590837bSKentaro Takeda return -EINTR; 18649590837bSKentaro Takeda /* Call the policy handler. */ 18659590837bSKentaro Takeda len = head->read(head); 18669590837bSKentaro Takeda if (len < 0) 18679590837bSKentaro Takeda goto out; 18689590837bSKentaro Takeda /* Write to buffer. */ 18699590837bSKentaro Takeda len = head->read_avail; 18709590837bSKentaro Takeda if (len > buffer_len) 18719590837bSKentaro Takeda len = buffer_len; 18729590837bSKentaro Takeda if (!len) 18739590837bSKentaro Takeda goto out; 18749590837bSKentaro Takeda /* head->read_buf changes by some functions. */ 18759590837bSKentaro Takeda cp = head->read_buf; 18769590837bSKentaro Takeda if (copy_to_user(buffer, cp, len)) { 18779590837bSKentaro Takeda len = -EFAULT; 18789590837bSKentaro Takeda goto out; 18799590837bSKentaro Takeda } 18809590837bSKentaro Takeda head->read_avail -= len; 18819590837bSKentaro Takeda memmove(cp, cp + len, head->read_avail); 18829590837bSKentaro Takeda out: 18839590837bSKentaro Takeda mutex_unlock(&head->io_sem); 18849590837bSKentaro Takeda return len; 18859590837bSKentaro Takeda } 18869590837bSKentaro Takeda 18879590837bSKentaro Takeda /** 18889590837bSKentaro Takeda * tomoyo_write_control - write() for /sys/kernel/security/tomoyo/ interface. 18899590837bSKentaro Takeda * 18909590837bSKentaro Takeda * @file: Pointer to "struct file". 18919590837bSKentaro Takeda * @buffer: Pointer to buffer to read from. 18929590837bSKentaro Takeda * @buffer_len: Size of @buffer. 18939590837bSKentaro Takeda * 18949590837bSKentaro Takeda * Returns @buffer_len on success, negative value otherwise. 1895fdb8ebb7STetsuo Handa * 1896fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 18979590837bSKentaro Takeda */ 1898c3ef1500STetsuo Handa int tomoyo_write_control(struct file *file, const char __user *buffer, 18999590837bSKentaro Takeda const int buffer_len) 19009590837bSKentaro Takeda { 19019590837bSKentaro Takeda struct tomoyo_io_buffer *head = file->private_data; 19029590837bSKentaro Takeda int error = buffer_len; 19039590837bSKentaro Takeda int avail_len = buffer_len; 19049590837bSKentaro Takeda char *cp0 = head->write_buf; 19059590837bSKentaro Takeda 19069590837bSKentaro Takeda if (!head->write) 19079590837bSKentaro Takeda return -ENOSYS; 19089590837bSKentaro Takeda if (!access_ok(VERIFY_READ, buffer, buffer_len)) 19099590837bSKentaro Takeda return -EFAULT; 19109590837bSKentaro Takeda /* Don't allow updating policies by non manager programs. */ 19119590837bSKentaro Takeda if (head->write != tomoyo_write_pid && 19129590837bSKentaro Takeda head->write != tomoyo_write_domain_policy && 19139590837bSKentaro Takeda !tomoyo_is_policy_manager()) 19149590837bSKentaro Takeda return -EPERM; 19159590837bSKentaro Takeda if (mutex_lock_interruptible(&head->io_sem)) 19169590837bSKentaro Takeda return -EINTR; 19179590837bSKentaro Takeda /* Read a line and dispatch it to the policy handler. */ 19189590837bSKentaro Takeda while (avail_len > 0) { 19199590837bSKentaro Takeda char c; 19209590837bSKentaro Takeda if (head->write_avail >= head->writebuf_size - 1) { 19219590837bSKentaro Takeda error = -ENOMEM; 19229590837bSKentaro Takeda break; 19239590837bSKentaro Takeda } else if (get_user(c, buffer)) { 19249590837bSKentaro Takeda error = -EFAULT; 19259590837bSKentaro Takeda break; 19269590837bSKentaro Takeda } 19279590837bSKentaro Takeda buffer++; 19289590837bSKentaro Takeda avail_len--; 19299590837bSKentaro Takeda cp0[head->write_avail++] = c; 19309590837bSKentaro Takeda if (c != '\n') 19319590837bSKentaro Takeda continue; 19329590837bSKentaro Takeda cp0[head->write_avail - 1] = '\0'; 19339590837bSKentaro Takeda head->write_avail = 0; 19349590837bSKentaro Takeda tomoyo_normalize_line(cp0); 19359590837bSKentaro Takeda head->write(head); 19369590837bSKentaro Takeda } 19379590837bSKentaro Takeda mutex_unlock(&head->io_sem); 19389590837bSKentaro Takeda return error; 19399590837bSKentaro Takeda } 19409590837bSKentaro Takeda 19419590837bSKentaro Takeda /** 19429590837bSKentaro Takeda * tomoyo_close_control - close() for /sys/kernel/security/tomoyo/ interface. 19439590837bSKentaro Takeda * 19449590837bSKentaro Takeda * @file: Pointer to "struct file". 19459590837bSKentaro Takeda * 19469590837bSKentaro Takeda * Releases memory and returns 0. 1947fdb8ebb7STetsuo Handa * 1948fdb8ebb7STetsuo Handa * Caller looses tomoyo_read_lock(). 19499590837bSKentaro Takeda */ 1950c3ef1500STetsuo Handa int tomoyo_close_control(struct file *file) 19519590837bSKentaro Takeda { 19529590837bSKentaro Takeda struct tomoyo_io_buffer *head = file->private_data; 1953847b173eSTetsuo Handa const bool is_write = !!head->write_buf; 19549590837bSKentaro Takeda 195517fcfbd9STetsuo Handa /* 195617fcfbd9STetsuo Handa * If the file is /sys/kernel/security/tomoyo/query , decrement the 195717fcfbd9STetsuo Handa * observer counter. 195817fcfbd9STetsuo Handa */ 195917fcfbd9STetsuo Handa if (head->type == TOMOYO_QUERY) 196017fcfbd9STetsuo Handa atomic_dec(&tomoyo_query_observers); 196117fcfbd9STetsuo Handa else 1962fdb8ebb7STetsuo Handa tomoyo_read_unlock(head->reader_idx); 19639590837bSKentaro Takeda /* Release memory used for policy I/O. */ 19648e2d39a1STetsuo Handa kfree(head->read_buf); 19659590837bSKentaro Takeda head->read_buf = NULL; 19668e2d39a1STetsuo Handa kfree(head->write_buf); 19679590837bSKentaro Takeda head->write_buf = NULL; 19688e2d39a1STetsuo Handa kfree(head); 19699590837bSKentaro Takeda head = NULL; 19709590837bSKentaro Takeda file->private_data = NULL; 1971847b173eSTetsuo Handa if (is_write) 1972847b173eSTetsuo Handa tomoyo_run_gc(); 19739590837bSKentaro Takeda return 0; 19749590837bSKentaro Takeda } 19759590837bSKentaro Takeda 19769590837bSKentaro Takeda /** 1977c3ef1500STetsuo Handa * tomoyo_check_profile - Check all profiles currently assigned to domains are defined. 19789590837bSKentaro Takeda */ 1979c3ef1500STetsuo Handa void tomoyo_check_profile(void) 19809590837bSKentaro Takeda { 1981c3ef1500STetsuo Handa struct tomoyo_domain_info *domain; 1982c3ef1500STetsuo Handa const int idx = tomoyo_read_lock(); 1983c3ef1500STetsuo Handa tomoyo_policy_loaded = true; 1984c3ef1500STetsuo Handa /* Check all profiles currently assigned to domains are defined. */ 1985c3ef1500STetsuo Handa list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { 1986c3ef1500STetsuo Handa const u8 profile = domain->profile; 1987c3ef1500STetsuo Handa if (tomoyo_profile_ptr[profile]) 1988c3ef1500STetsuo Handa continue; 1989c3ef1500STetsuo Handa panic("Profile %u (used by '%s') not defined.\n", 1990c3ef1500STetsuo Handa profile, domain->domainname->name); 19919590837bSKentaro Takeda } 1992c3ef1500STetsuo Handa tomoyo_read_unlock(idx); 199357c2590fSTetsuo Handa if (tomoyo_profile_version != 20090903) 199457c2590fSTetsuo Handa panic("Profile version %u is not supported.\n", 199557c2590fSTetsuo Handa tomoyo_profile_version); 199657c2590fSTetsuo Handa printk(KERN_INFO "TOMOYO: 2.3.0-pre 2010/06/03\n"); 1997c3ef1500STetsuo Handa printk(KERN_INFO "Mandatory Access Control activated.\n"); 19989590837bSKentaro Takeda } 1999