memory.c (5561B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * security/tomoyo/memory.c 4 * 5 * Copyright (C) 2005-2011 NTT DATA CORPORATION 6 */ 7 8#include <linux/hash.h> 9#include <linux/slab.h> 10#include "common.h" 11 12/** 13 * tomoyo_warn_oom - Print out of memory warning message. 14 * 15 * @function: Function's name. 16 */ 17void tomoyo_warn_oom(const char *function) 18{ 19 /* Reduce error messages. */ 20 static pid_t tomoyo_last_pid; 21 const pid_t pid = current->pid; 22 23 if (tomoyo_last_pid != pid) { 24 pr_warn("ERROR: Out of memory at %s.\n", function); 25 tomoyo_last_pid = pid; 26 } 27 if (!tomoyo_policy_loaded) 28 panic("MAC Initialization failed.\n"); 29} 30 31/* Memoy currently used by policy/audit log/query. */ 32unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT]; 33/* Memory quota for "policy"/"audit log"/"query". */ 34unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT]; 35 36/** 37 * tomoyo_memory_ok - Check memory quota. 38 * 39 * @ptr: Pointer to allocated memory. 40 * 41 * Returns true on success, false otherwise. 42 * 43 * Returns true if @ptr is not NULL and quota not exceeded, false otherwise. 44 * 45 * Caller holds tomoyo_policy_lock mutex. 46 */ 47bool tomoyo_memory_ok(void *ptr) 48{ 49 if (ptr) { 50 const size_t s = ksize(ptr); 51 52 tomoyo_memory_used[TOMOYO_MEMORY_POLICY] += s; 53 if (!tomoyo_memory_quota[TOMOYO_MEMORY_POLICY] || 54 tomoyo_memory_used[TOMOYO_MEMORY_POLICY] <= 55 tomoyo_memory_quota[TOMOYO_MEMORY_POLICY]) 56 return true; 57 tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= s; 58 } 59 tomoyo_warn_oom(__func__); 60 return false; 61} 62 63/** 64 * tomoyo_commit_ok - Check memory quota. 65 * 66 * @data: Data to copy from. 67 * @size: Size in byte. 68 * 69 * Returns pointer to allocated memory on success, NULL otherwise. 70 * @data is zero-cleared on success. 71 * 72 * Caller holds tomoyo_policy_lock mutex. 73 */ 74void *tomoyo_commit_ok(void *data, const unsigned int size) 75{ 76 void *ptr = kzalloc(size, GFP_NOFS | __GFP_NOWARN); 77 78 if (tomoyo_memory_ok(ptr)) { 79 memmove(ptr, data, size); 80 memset(data, 0, size); 81 return ptr; 82 } 83 kfree(ptr); 84 return NULL; 85} 86 87/** 88 * tomoyo_get_group - Allocate memory for "struct tomoyo_path_group"/"struct tomoyo_number_group". 89 * 90 * @param: Pointer to "struct tomoyo_acl_param". 91 * @idx: Index number. 92 * 93 * Returns pointer to "struct tomoyo_group" on success, NULL otherwise. 94 */ 95struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param, 96 const u8 idx) 97{ 98 struct tomoyo_group e = { }; 99 struct tomoyo_group *group = NULL; 100 struct list_head *list; 101 const char *group_name = tomoyo_read_token(param); 102 bool found = false; 103 104 if (!tomoyo_correct_word(group_name) || idx >= TOMOYO_MAX_GROUP) 105 return NULL; 106 e.group_name = tomoyo_get_name(group_name); 107 if (!e.group_name) 108 return NULL; 109 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 110 goto out; 111 list = ¶m->ns->group_list[idx]; 112 list_for_each_entry(group, list, head.list) { 113 if (e.group_name != group->group_name || 114 atomic_read(&group->head.users) == TOMOYO_GC_IN_PROGRESS) 115 continue; 116 atomic_inc(&group->head.users); 117 found = true; 118 break; 119 } 120 if (!found) { 121 struct tomoyo_group *entry = tomoyo_commit_ok(&e, sizeof(e)); 122 123 if (entry) { 124 INIT_LIST_HEAD(&entry->member_list); 125 atomic_set(&entry->head.users, 1); 126 list_add_tail_rcu(&entry->head.list, list); 127 group = entry; 128 found = true; 129 } 130 } 131 mutex_unlock(&tomoyo_policy_lock); 132out: 133 tomoyo_put_name(e.group_name); 134 return found ? group : NULL; 135} 136 137/* 138 * tomoyo_name_list is used for holding string data used by TOMOYO. 139 * Since same string data is likely used for multiple times (e.g. 140 * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of 141 * "const struct tomoyo_path_info *". 142 */ 143struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; 144 145/** 146 * tomoyo_get_name - Allocate permanent memory for string data. 147 * 148 * @name: The string to store into the permernent memory. 149 * 150 * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. 151 */ 152const struct tomoyo_path_info *tomoyo_get_name(const char *name) 153{ 154 struct tomoyo_name *ptr; 155 unsigned int hash; 156 int len; 157 struct list_head *head; 158 159 if (!name) 160 return NULL; 161 len = strlen(name) + 1; 162 hash = full_name_hash(NULL, (const unsigned char *) name, len - 1); 163 head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; 164 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 165 return NULL; 166 list_for_each_entry(ptr, head, head.list) { 167 if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name) || 168 atomic_read(&ptr->head.users) == TOMOYO_GC_IN_PROGRESS) 169 continue; 170 atomic_inc(&ptr->head.users); 171 goto out; 172 } 173 ptr = kzalloc(sizeof(*ptr) + len, GFP_NOFS | __GFP_NOWARN); 174 if (tomoyo_memory_ok(ptr)) { 175 ptr->entry.name = ((char *) ptr) + sizeof(*ptr); 176 memmove((char *) ptr->entry.name, name, len); 177 atomic_set(&ptr->head.users, 1); 178 tomoyo_fill_path_info(&ptr->entry); 179 list_add_tail(&ptr->head.list, head); 180 } else { 181 kfree(ptr); 182 ptr = NULL; 183 } 184out: 185 mutex_unlock(&tomoyo_policy_lock); 186 return ptr ? &ptr->entry : NULL; 187} 188 189/* Initial namespace.*/ 190struct tomoyo_policy_namespace tomoyo_kernel_namespace; 191 192/** 193 * tomoyo_mm_init - Initialize mm related code. 194 */ 195void __init tomoyo_mm_init(void) 196{ 197 int idx; 198 199 for (idx = 0; idx < TOMOYO_MAX_HASH; idx++) 200 INIT_LIST_HEAD(&tomoyo_name_list[idx]); 201 tomoyo_kernel_namespace.name = "<kernel>"; 202 tomoyo_init_policy_namespace(&tomoyo_kernel_namespace); 203 tomoyo_kernel_domain.ns = &tomoyo_kernel_namespace; 204 INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); 205 tomoyo_kernel_domain.domainname = tomoyo_get_name("<kernel>"); 206 list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list); 207}