~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/security/ccsecurity/memory.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php