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