18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * security/tomoyo/memory.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2005-2011 NTT DATA CORPORATION 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/hash.h> 98c2ecf20Sopenharmony_ci#include <linux/slab.h> 108c2ecf20Sopenharmony_ci#include "common.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci/** 138c2ecf20Sopenharmony_ci * tomoyo_warn_oom - Print out of memory warning message. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * @function: Function's name. 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_civoid tomoyo_warn_oom(const char *function) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci /* Reduce error messages. */ 208c2ecf20Sopenharmony_ci static pid_t tomoyo_last_pid; 218c2ecf20Sopenharmony_ci const pid_t pid = current->pid; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci if (tomoyo_last_pid != pid) { 248c2ecf20Sopenharmony_ci pr_warn("ERROR: Out of memory at %s.\n", function); 258c2ecf20Sopenharmony_ci tomoyo_last_pid = pid; 268c2ecf20Sopenharmony_ci } 278c2ecf20Sopenharmony_ci if (!tomoyo_policy_loaded) 288c2ecf20Sopenharmony_ci panic("MAC Initialization failed.\n"); 298c2ecf20Sopenharmony_ci} 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* Memoy currently used by policy/audit log/query. */ 328c2ecf20Sopenharmony_ciunsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT]; 338c2ecf20Sopenharmony_ci/* Memory quota for "policy"/"audit log"/"query". */ 348c2ecf20Sopenharmony_ciunsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT]; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/** 378c2ecf20Sopenharmony_ci * tomoyo_memory_ok - Check memory quota. 388c2ecf20Sopenharmony_ci * 398c2ecf20Sopenharmony_ci * @ptr: Pointer to allocated memory. 408c2ecf20Sopenharmony_ci * 418c2ecf20Sopenharmony_ci * Returns true on success, false otherwise. 428c2ecf20Sopenharmony_ci * 438c2ecf20Sopenharmony_ci * Returns true if @ptr is not NULL and quota not exceeded, false otherwise. 448c2ecf20Sopenharmony_ci * 458c2ecf20Sopenharmony_ci * Caller holds tomoyo_policy_lock mutex. 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_cibool tomoyo_memory_ok(void *ptr) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci if (ptr) { 508c2ecf20Sopenharmony_ci const size_t s = ksize(ptr); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci tomoyo_memory_used[TOMOYO_MEMORY_POLICY] += s; 538c2ecf20Sopenharmony_ci if (!tomoyo_memory_quota[TOMOYO_MEMORY_POLICY] || 548c2ecf20Sopenharmony_ci tomoyo_memory_used[TOMOYO_MEMORY_POLICY] <= 558c2ecf20Sopenharmony_ci tomoyo_memory_quota[TOMOYO_MEMORY_POLICY]) 568c2ecf20Sopenharmony_ci return true; 578c2ecf20Sopenharmony_ci tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= s; 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci tomoyo_warn_oom(__func__); 608c2ecf20Sopenharmony_ci return false; 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/** 648c2ecf20Sopenharmony_ci * tomoyo_commit_ok - Check memory quota. 658c2ecf20Sopenharmony_ci * 668c2ecf20Sopenharmony_ci * @data: Data to copy from. 678c2ecf20Sopenharmony_ci * @size: Size in byte. 688c2ecf20Sopenharmony_ci * 698c2ecf20Sopenharmony_ci * Returns pointer to allocated memory on success, NULL otherwise. 708c2ecf20Sopenharmony_ci * @data is zero-cleared on success. 718c2ecf20Sopenharmony_ci * 728c2ecf20Sopenharmony_ci * Caller holds tomoyo_policy_lock mutex. 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_civoid *tomoyo_commit_ok(void *data, const unsigned int size) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci void *ptr = kzalloc(size, GFP_NOFS); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (tomoyo_memory_ok(ptr)) { 798c2ecf20Sopenharmony_ci memmove(ptr, data, size); 808c2ecf20Sopenharmony_ci memset(data, 0, size); 818c2ecf20Sopenharmony_ci return ptr; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci kfree(ptr); 848c2ecf20Sopenharmony_ci return NULL; 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/** 888c2ecf20Sopenharmony_ci * tomoyo_get_group - Allocate memory for "struct tomoyo_path_group"/"struct tomoyo_number_group". 898c2ecf20Sopenharmony_ci * 908c2ecf20Sopenharmony_ci * @param: Pointer to "struct tomoyo_acl_param". 918c2ecf20Sopenharmony_ci * @idx: Index number. 928c2ecf20Sopenharmony_ci * 938c2ecf20Sopenharmony_ci * Returns pointer to "struct tomoyo_group" on success, NULL otherwise. 948c2ecf20Sopenharmony_ci */ 958c2ecf20Sopenharmony_cistruct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param, 968c2ecf20Sopenharmony_ci const u8 idx) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct tomoyo_group e = { }; 998c2ecf20Sopenharmony_ci struct tomoyo_group *group = NULL; 1008c2ecf20Sopenharmony_ci struct list_head *list; 1018c2ecf20Sopenharmony_ci const char *group_name = tomoyo_read_token(param); 1028c2ecf20Sopenharmony_ci bool found = false; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (!tomoyo_correct_word(group_name) || idx >= TOMOYO_MAX_GROUP) 1058c2ecf20Sopenharmony_ci return NULL; 1068c2ecf20Sopenharmony_ci e.group_name = tomoyo_get_name(group_name); 1078c2ecf20Sopenharmony_ci if (!e.group_name) 1088c2ecf20Sopenharmony_ci return NULL; 1098c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&tomoyo_policy_lock)) 1108c2ecf20Sopenharmony_ci goto out; 1118c2ecf20Sopenharmony_ci list = ¶m->ns->group_list[idx]; 1128c2ecf20Sopenharmony_ci list_for_each_entry(group, list, head.list) { 1138c2ecf20Sopenharmony_ci if (e.group_name != group->group_name || 1148c2ecf20Sopenharmony_ci atomic_read(&group->head.users) == TOMOYO_GC_IN_PROGRESS) 1158c2ecf20Sopenharmony_ci continue; 1168c2ecf20Sopenharmony_ci atomic_inc(&group->head.users); 1178c2ecf20Sopenharmony_ci found = true; 1188c2ecf20Sopenharmony_ci break; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci if (!found) { 1218c2ecf20Sopenharmony_ci struct tomoyo_group *entry = tomoyo_commit_ok(&e, sizeof(e)); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (entry) { 1248c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&entry->member_list); 1258c2ecf20Sopenharmony_ci atomic_set(&entry->head.users, 1); 1268c2ecf20Sopenharmony_ci list_add_tail_rcu(&entry->head.list, list); 1278c2ecf20Sopenharmony_ci group = entry; 1288c2ecf20Sopenharmony_ci found = true; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci mutex_unlock(&tomoyo_policy_lock); 1328c2ecf20Sopenharmony_ciout: 1338c2ecf20Sopenharmony_ci tomoyo_put_name(e.group_name); 1348c2ecf20Sopenharmony_ci return found ? group : NULL; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci/* 1388c2ecf20Sopenharmony_ci * tomoyo_name_list is used for holding string data used by TOMOYO. 1398c2ecf20Sopenharmony_ci * Since same string data is likely used for multiple times (e.g. 1408c2ecf20Sopenharmony_ci * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of 1418c2ecf20Sopenharmony_ci * "const struct tomoyo_path_info *". 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_cistruct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci/** 1468c2ecf20Sopenharmony_ci * tomoyo_get_name - Allocate permanent memory for string data. 1478c2ecf20Sopenharmony_ci * 1488c2ecf20Sopenharmony_ci * @name: The string to store into the permernent memory. 1498c2ecf20Sopenharmony_ci * 1508c2ecf20Sopenharmony_ci * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. 1518c2ecf20Sopenharmony_ci */ 1528c2ecf20Sopenharmony_ciconst struct tomoyo_path_info *tomoyo_get_name(const char *name) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci struct tomoyo_name *ptr; 1558c2ecf20Sopenharmony_ci unsigned int hash; 1568c2ecf20Sopenharmony_ci int len; 1578c2ecf20Sopenharmony_ci struct list_head *head; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if (!name) 1608c2ecf20Sopenharmony_ci return NULL; 1618c2ecf20Sopenharmony_ci len = strlen(name) + 1; 1628c2ecf20Sopenharmony_ci hash = full_name_hash(NULL, (const unsigned char *) name, len - 1); 1638c2ecf20Sopenharmony_ci head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; 1648c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&tomoyo_policy_lock)) 1658c2ecf20Sopenharmony_ci return NULL; 1668c2ecf20Sopenharmony_ci list_for_each_entry(ptr, head, head.list) { 1678c2ecf20Sopenharmony_ci if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name) || 1688c2ecf20Sopenharmony_ci atomic_read(&ptr->head.users) == TOMOYO_GC_IN_PROGRESS) 1698c2ecf20Sopenharmony_ci continue; 1708c2ecf20Sopenharmony_ci atomic_inc(&ptr->head.users); 1718c2ecf20Sopenharmony_ci goto out; 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci ptr = kzalloc(sizeof(*ptr) + len, GFP_NOFS); 1748c2ecf20Sopenharmony_ci if (tomoyo_memory_ok(ptr)) { 1758c2ecf20Sopenharmony_ci ptr->entry.name = ((char *) ptr) + sizeof(*ptr); 1768c2ecf20Sopenharmony_ci memmove((char *) ptr->entry.name, name, len); 1778c2ecf20Sopenharmony_ci atomic_set(&ptr->head.users, 1); 1788c2ecf20Sopenharmony_ci tomoyo_fill_path_info(&ptr->entry); 1798c2ecf20Sopenharmony_ci list_add_tail(&ptr->head.list, head); 1808c2ecf20Sopenharmony_ci } else { 1818c2ecf20Sopenharmony_ci kfree(ptr); 1828c2ecf20Sopenharmony_ci ptr = NULL; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ciout: 1858c2ecf20Sopenharmony_ci mutex_unlock(&tomoyo_policy_lock); 1868c2ecf20Sopenharmony_ci return ptr ? &ptr->entry : NULL; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci/* Initial namespace.*/ 1908c2ecf20Sopenharmony_cistruct tomoyo_policy_namespace tomoyo_kernel_namespace; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/** 1938c2ecf20Sopenharmony_ci * tomoyo_mm_init - Initialize mm related code. 1948c2ecf20Sopenharmony_ci */ 1958c2ecf20Sopenharmony_civoid __init tomoyo_mm_init(void) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci int idx; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci for (idx = 0; idx < TOMOYO_MAX_HASH; idx++) 2008c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tomoyo_name_list[idx]); 2018c2ecf20Sopenharmony_ci tomoyo_kernel_namespace.name = "<kernel>"; 2028c2ecf20Sopenharmony_ci tomoyo_init_policy_namespace(&tomoyo_kernel_namespace); 2038c2ecf20Sopenharmony_ci tomoyo_kernel_domain.ns = &tomoyo_kernel_namespace; 2048c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); 2058c2ecf20Sopenharmony_ci tomoyo_kernel_domain.domainname = tomoyo_get_name("<kernel>"); 2068c2ecf20Sopenharmony_ci list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list); 2078c2ecf20Sopenharmony_ci} 208