1 /* 2 * security/ccsecurity/memory.c 3 * 4 * Copyright (C) 2005-2012 NTT DATA CORPORATION 5 * 6 * Version: 1.8.11 2024/07/15 7 */ 8 9 #include "internal.h" 10 11 /***** SECTION1: Constants definition *****/ 12 13 /***** SECTION2: Structure definition *****/ 14 15 /***** SECTION3: Prototype definition section *****/ 16 17 bool ccs_memory_ok(const void *ptr, const unsigned int size); 18 const struct ccs_path_info *ccs_get_name(const char *name); 19 #ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY 20 struct ccs_security *ccs_find_task_security(const struct task_struct *task); 21 #endif 22 void *ccs_commit_ok(void *data, const unsigned int size); 23 void __init ccs_mm_init(void); 24 void ccs_warn_oom(const char *function); 25 26 #ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY 27 static int __ccs_alloc_task_security(const struct task_struct *task); 28 static void __ccs_free_task_security(const struct task_struct *task); 29 static void ccs_add_task_security(struct ccs_security *ptr, 30 struct list_head *list); 31 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8) 32 static void ccs_rcu_free(struct rcu_head *rcu); 33 #else 34 static void ccs_rcu_free(void *arg); 35 #endif 36 #endif 37 38 /***** SECTION4: Standalone functions section *****/ 39 40 /***** SECTION5: Variables definition section *****/ 41 42 /* Memoy currently used by policy/audit log/query. */ 43 unsigned int ccs_memory_used[CCS_MAX_MEMORY_STAT]; 44 45 /* Memory quota for "policy"/"audit log"/"query". */ 46 unsigned int ccs_memory_quota[CCS_MAX_MEMORY_STAT]; 47 48 /* The list for "struct ccs_name". */ 49 struct list_head ccs_name_list[CCS_MAX_HASH]; 50 51 #ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY 52 53 /* Dummy security context for avoiding NULL pointer dereference. */ 54 static struct ccs_security ccs_oom_security = { 55 .ccs_domain_info = &ccs_kernel_domain 56 }; 57 58 /* Dummy security context for avoiding NULL pointer dereference. */ 59 static struct ccs_security ccs_default_security = { 60 .ccs_domain_info = &ccs_kernel_domain 61 }; 62 63 /* List of "struct ccs_security". */ 64 struct list_head ccs_task_security_list[CCS_MAX_TASK_SECURITY_HASH]; 65 /* Lock for protecting ccs_task_security_list[]. */ 66 static DEFINE_SPINLOCK(ccs_task_security_list_lock); 67 68 #endif 69 70 /***** SECTION6: Dependent functions section *****/ 71 72 /** 73 * ccs_warn_oom - Print out of memory warning message. 74 * 75 * @function: Function's name. 76 * 77 * Returns nothing. 78 */ 79 void ccs_warn_oom(const char *function) 80 { 81 /* Reduce error messages. */ 82 static pid_t ccs_last_pid; 83 const pid_t pid = current->pid; 84 if (ccs_last_pid != pid) { 85 printk(KERN_WARNING "ERROR: Out of memory at %s.\n", 86 function); 87 ccs_last_pid = pid; 88 } 89 if (!ccs_policy_loaded) 90 panic("MAC Initialization failed.\n"); 91 } 92 93 /** 94 * ccs_memory_ok - Check memory quota. 95 * 96 * @ptr: Pointer to allocated memory. Maybe NULL. 97 * @size: Size in byte. Not used if @ptr is NULL. 98 * 99 * Returns true if @ptr is not NULL and quota not exceeded, false otherwise. 100 * 101 * Caller holds ccs_policy_lock mutex. 102 */ 103 bool ccs_memory_ok(const void *ptr, const unsigned int size) 104 { 105 if (ptr) { 106 const size_t s = ccs_round2(size); 107 ccs_memory_used[CCS_MEMORY_POLICY] += s; 108 if (!ccs_memory_quota[CCS_MEMORY_POLICY] || 109 ccs_memory_used[CCS_MEMORY_POLICY] <= 110 ccs_memory_quota[CCS_MEMORY_POLICY]) 111 return true; 112 ccs_memory_used[CCS_MEMORY_POLICY] -= s; 113 } 114 ccs_warn_oom(__func__); 115 return false; 116 } 117 118 /** 119 * ccs_commit_ok - Allocate memory and check memory quota. 120 * 121 * @data: Data to copy from. 122 * @size: Size in byte. 123 * 124 * Returns pointer to allocated memory on success, NULL otherwise. 125 * @data is zero-cleared on success. 126 * 127 * Caller holds ccs_policy_lock mutex. 128 */ 129 void *ccs_commit_ok(void *data, const unsigned int size) 130 { 131 void *ptr = kmalloc(size, CCS_GFP_FLAGS); 132 if (ccs_memory_ok(ptr, size)) { 133 memmove(ptr, data, size); 134 memset(data, 0, size); 135 return ptr; 136 } 137 kfree(ptr); 138 return NULL; 139 } 140 141 /** 142 * ccs_get_name - Allocate memory for string data. 143 * 144 * @name: The string to store into the permernent memory. 145 * 146 * Returns pointer to "struct ccs_path_info" on success, NULL otherwise. 147 */ 148 const struct ccs_path_info *ccs_get_name(const char *name) 149 { 150 struct ccs_name *ptr; 151 unsigned int hash; 152 int len; 153 int allocated_len; 154 struct list_head *head; 155 156 if (!name) 157 return NULL; 158 len = strlen(name) + 1; 159 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0) 160 hash = full_name_hash(NULL, name, len - 1); 161 #else 162 hash = full_name_hash((const unsigned char *) name, len - 1); 163 #endif 164 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) || defined(RHEL_MAJOR) 165 head = &ccs_name_list[hash_long(hash, CCS_HASH_BITS)]; 166 #else 167 head = &ccs_name_list[hash % CCS_MAX_HASH]; 168 #endif 169 if (mutex_lock_interruptible(&ccs_policy_lock)) 170 return NULL; 171 list_for_each_entry(ptr, head, head.list) { 172 if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name) || 173 atomic_read(&ptr->head.users) == CCS_GC_IN_PROGRESS) 174 continue; 175 atomic_inc(&ptr->head.users); 176 goto out; 177 } 178 allocated_len = sizeof(*ptr) + len; 179 ptr = kzalloc(allocated_len, CCS_GFP_FLAGS); 180 if (ccs_memory_ok(ptr, allocated_len)) { 181 ptr->entry.name = ((char *) ptr) + sizeof(*ptr); 182 memmove((char *) ptr->entry.name, name, len); 183 atomic_set(&ptr->head.users, 1); 184 ccs_fill_path_info(&ptr->entry); 185 ptr->size = allocated_len; 186 list_add_tail(&ptr->head.list, head); 187 } else { 188 kfree(ptr); 189 ptr = NULL; 190 } 191 out: 192 mutex_unlock(&ccs_policy_lock); 193 return ptr ? &ptr->entry : NULL; 194 } 195 196 #ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY 197 198 /** 199 * ccs_add_task_security - Add "struct ccs_security" to list. 200 * 201 * @ptr: Pointer to "struct ccs_security". 202 * @list: Pointer to "struct list_head". 203 * 204 * Returns nothing. 205 */ 206 static void ccs_add_task_security(struct ccs_security *ptr, 207 struct list_head *list) 208 { 209 unsigned long flags; 210 spin_lock_irqsave(&ccs_task_security_list_lock, flags); 211 list_add_rcu(&ptr->list, list); 212 spin_unlock_irqrestore(&ccs_task_security_list_lock, flags); 213 } 214 215 /** 216 * __ccs_alloc_task_security - Allocate memory for new tasks. 217 * 218 * @task: Pointer to "struct task_struct". 219 * 220 * Returns 0 on success, negative value otherwise. 221 */ 222 static int __ccs_alloc_task_security(const struct task_struct *task) 223 { 224 struct ccs_security *old_security = ccs_current_security(); 225 struct ccs_security *new_security = kzalloc(sizeof(*new_security), 226 GFP_KERNEL); 227 struct list_head *list = &ccs_task_security_list 228 [hash_ptr((void *) task, CCS_TASK_SECURITY_HASH_BITS)]; 229 if (!new_security) 230 return -ENOMEM; 231 new_security->task = task; 232 new_security->ccs_domain_info = old_security->ccs_domain_info; 233 new_security->ccs_flags = old_security->ccs_flags; 234 ccs_add_task_security(new_security, list); 235 return 0; 236 } 237 238 /** 239 * ccs_find_task_security - Find "struct ccs_security" for given task. 240 * 241 * @task: Pointer to "struct task_struct". 242 * 243 * Returns pointer to "struct ccs_security" on success, &ccs_oom_security on 244 * out of memory, &ccs_default_security otherwise. 245 * 246 * If @task is current thread and "struct ccs_security" for current thread was 247 * not found, I try to allocate it. But if allocation failed, current thread 248 * will be killed by SIGKILL. Note that if current->pid == 1, sending SIGKILL 249 * won't work. 250 */ 251 struct ccs_security *ccs_find_task_security(const struct task_struct *task) 252 { 253 struct ccs_security *ptr; 254 struct list_head *list = &ccs_task_security_list 255 [hash_ptr((void *) task, CCS_TASK_SECURITY_HASH_BITS)]; 256 /* Make sure INIT_LIST_HEAD() in ccs_mm_init() takes effect. */ 257 while (!list->next) 258 smp_rmb(); 259 rcu_read_lock(); 260 list_for_each_entry_rcu(ptr, list, list) { 261 if (ptr->task != task) 262 continue; 263 rcu_read_unlock(); 264 return ptr; 265 } 266 rcu_read_unlock(); 267 if (task != current) 268 return &ccs_default_security; 269 /* Use GFP_ATOMIC because caller may have called rcu_read_lock(). */ 270 ptr = kzalloc(sizeof(*ptr), GFP_ATOMIC); 271 if (!ptr) { 272 printk(KERN_WARNING "Unable to allocate memory for pid=%u\n", 273 task->pid); 274 send_sig(SIGKILL, current, 0); 275 return &ccs_oom_security; 276 } 277 *ptr = ccs_default_security; 278 ptr->task = task; 279 ccs_add_task_security(ptr, list); 280 return ptr; 281 } 282 283 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8) 284 285 /** 286 * ccs_rcu_free - RCU callback for releasing "struct ccs_security". 287 * 288 * @rcu: Pointer to "struct rcu_head". 289 * 290 * Returns nothing. 291 */ 292 static void ccs_rcu_free(struct rcu_head *rcu) 293 { 294 struct ccs_security *ptr = container_of(rcu, typeof(*ptr), rcu); 295 kfree(ptr); 296 } 297 298 #else 299 300 /** 301 * ccs_rcu_free - RCU callback for releasing "struct ccs_security". 302 * 303 * @arg: Pointer to "void". 304 * 305 * Returns nothing. 306 */ 307 static void ccs_rcu_free(void *arg) 308 { 309 struct ccs_security *ptr = arg; 310 kfree(ptr); 311 } 312 313 #endif 314 315 /** 316 * __ccs_free_task_security - Release memory associated with "struct task_struct". 317 * 318 * @task: Pointer to "struct task_struct". 319 * 320 * Returns nothing. 321 */ 322 static void __ccs_free_task_security(const struct task_struct *task) 323 { 324 unsigned long flags; 325 struct ccs_security *ptr = ccs_find_task_security(task); 326 if (ptr == &ccs_default_security || ptr == &ccs_oom_security) 327 return; 328 spin_lock_irqsave(&ccs_task_security_list_lock, flags); 329 list_del_rcu(&ptr->list); 330 spin_unlock_irqrestore(&ccs_task_security_list_lock, flags); 331 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8) 332 call_rcu(&ptr->rcu, ccs_rcu_free); 333 #else 334 call_rcu(&ptr->rcu, ccs_rcu_free, ptr); 335 #endif 336 } 337 338 #endif 339 340 /** 341 * ccs_mm_init - Initialize mm related code. 342 * 343 * Returns nothing. 344 */ 345 void __init ccs_mm_init(void) 346 { 347 int idx; 348 for (idx = 0; idx < CCS_MAX_HASH; idx++) 349 INIT_LIST_HEAD(&ccs_name_list[idx]); 350 #ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY 351 for (idx = 0; idx < CCS_MAX_TASK_SECURITY_HASH; idx++) 352 INIT_LIST_HEAD(&ccs_task_security_list[idx]); 353 #endif 354 smp_wmb(); /* Avoid out of order execution. */ 355 #ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY 356 ccsecurity_ops.alloc_task_security = __ccs_alloc_task_security; 357 ccsecurity_ops.free_task_security = __ccs_free_task_security; 358 #endif 359 ccs_kernel_domain.domainname = ccs_get_name("<kernel>"); 360 list_add_tail_rcu(&ccs_kernel_domain.list, &ccs_domain_list); 361 } 362
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.