オープンソース・ソフトウェアの開発とダウンロード

Subversion リポジトリの参照

Contents of /trunk/1.8.x/ccs-patch/security/ccsecurity/memory.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6407 - (show annotations) (download) (as text)
Tue Apr 21 08:15:55 2015 UTC (9 years ago) by kumaneko
File MIME type: text/x-csrc
File size: 9825 byte(s)


1 /*
2 * security/ccsecurity/memory.c
3 *
4 * Copyright (C) 2005-2012 NTT DATA CORPORATION
5 *
6 * Version: 1.8.3+ 2015/04/21
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 hash = full_name_hash((const unsigned char *) name, len - 1);
160 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) || defined(RHEL_MAJOR)
161 head = &ccs_name_list[hash_long(hash, CCS_HASH_BITS)];
162 #else
163 head = &ccs_name_list[hash % CCS_MAX_HASH];
164 #endif
165 if (mutex_lock_interruptible(&ccs_policy_lock))
166 return NULL;
167 list_for_each_entry(ptr, head, head.list) {
168 if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name) ||
169 atomic_read(&ptr->head.users) == CCS_GC_IN_PROGRESS)
170 continue;
171 atomic_inc(&ptr->head.users);
172 goto out;
173 }
174 allocated_len = sizeof(*ptr) + len;
175 ptr = kzalloc(allocated_len, CCS_GFP_FLAGS);
176 if (ccs_memory_ok(ptr, allocated_len)) {
177 ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
178 memmove((char *) ptr->entry.name, name, len);
179 atomic_set(&ptr->head.users, 1);
180 ccs_fill_path_info(&ptr->entry);
181 ptr->size = allocated_len;
182 list_add_tail(&ptr->head.list, head);
183 } else {
184 kfree(ptr);
185 ptr = NULL;
186 }
187 out:
188 mutex_unlock(&ccs_policy_lock);
189 return ptr ? &ptr->entry : NULL;
190 }
191
192 #ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
193
194 /**
195 * ccs_add_task_security - Add "struct ccs_security" to list.
196 *
197 * @ptr: Pointer to "struct ccs_security".
198 * @list: Pointer to "struct list_head".
199 *
200 * Returns nothing.
201 */
202 static void ccs_add_task_security(struct ccs_security *ptr,
203 struct list_head *list)
204 {
205 unsigned long flags;
206 spin_lock_irqsave(&ccs_task_security_list_lock, flags);
207 list_add_rcu(&ptr->list, list);
208 spin_unlock_irqrestore(&ccs_task_security_list_lock, flags);
209 }
210
211 /**
212 * __ccs_alloc_task_security - Allocate memory for new tasks.
213 *
214 * @task: Pointer to "struct task_struct".
215 *
216 * Returns 0 on success, negative value otherwise.
217 */
218 static int __ccs_alloc_task_security(const struct task_struct *task)
219 {
220 struct ccs_security *old_security = ccs_current_security();
221 struct ccs_security *new_security = kzalloc(sizeof(*new_security),
222 GFP_KERNEL);
223 struct list_head *list = &ccs_task_security_list
224 [hash_ptr((void *) task, CCS_TASK_SECURITY_HASH_BITS)];
225 if (!new_security)
226 return -ENOMEM;
227 new_security->task = task;
228 new_security->ccs_domain_info = old_security->ccs_domain_info;
229 new_security->ccs_flags = old_security->ccs_flags;
230 ccs_add_task_security(new_security, list);
231 return 0;
232 }
233
234 /**
235 * ccs_find_task_security - Find "struct ccs_security" for given task.
236 *
237 * @task: Pointer to "struct task_struct".
238 *
239 * Returns pointer to "struct ccs_security" on success, &ccs_oom_security on
240 * out of memory, &ccs_default_security otherwise.
241 *
242 * If @task is current thread and "struct ccs_security" for current thread was
243 * not found, I try to allocate it. But if allocation failed, current thread
244 * will be killed by SIGKILL. Note that if current->pid == 1, sending SIGKILL
245 * won't work.
246 */
247 struct ccs_security *ccs_find_task_security(const struct task_struct *task)
248 {
249 struct ccs_security *ptr;
250 struct list_head *list = &ccs_task_security_list
251 [hash_ptr((void *) task, CCS_TASK_SECURITY_HASH_BITS)];
252 /* Make sure INIT_LIST_HEAD() in ccs_mm_init() takes effect. */
253 while (!list->next);
254 rcu_read_lock();
255 list_for_each_entry_rcu(ptr, list, list) {
256 if (ptr->task != task)
257 continue;
258 rcu_read_unlock();
259 return ptr;
260 }
261 rcu_read_unlock();
262 if (task != current)
263 return &ccs_default_security;
264 /* Use GFP_ATOMIC because caller may have called rcu_read_lock(). */
265 ptr = kzalloc(sizeof(*ptr), GFP_ATOMIC);
266 if (!ptr) {
267 printk(KERN_WARNING "Unable to allocate memory for pid=%u\n",
268 task->pid);
269 send_sig(SIGKILL, current, 0);
270 return &ccs_oom_security;
271 }
272 *ptr = ccs_default_security;
273 ptr->task = task;
274 ccs_add_task_security(ptr, list);
275 return ptr;
276 }
277
278 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8)
279
280 /**
281 * ccs_rcu_free - RCU callback for releasing "struct ccs_security".
282 *
283 * @rcu: Pointer to "struct rcu_head".
284 *
285 * Returns nothing.
286 */
287 static void ccs_rcu_free(struct rcu_head *rcu)
288 {
289 struct ccs_security *ptr = container_of(rcu, typeof(*ptr), rcu);
290 kfree(ptr);
291 }
292
293 #else
294
295 /**
296 * ccs_rcu_free - RCU callback for releasing "struct ccs_security".
297 *
298 * @arg: Pointer to "void".
299 *
300 * Returns nothing.
301 */
302 static void ccs_rcu_free(void *arg)
303 {
304 struct ccs_security *ptr = arg;
305 kfree(ptr);
306 }
307
308 #endif
309
310 /**
311 * __ccs_free_task_security - Release memory associated with "struct task_struct".
312 *
313 * @task: Pointer to "struct task_struct".
314 *
315 * Returns nothing.
316 */
317 static void __ccs_free_task_security(const struct task_struct *task)
318 {
319 unsigned long flags;
320 struct ccs_security *ptr = ccs_find_task_security(task);
321 if (ptr == &ccs_default_security || ptr == &ccs_oom_security)
322 return;
323 spin_lock_irqsave(&ccs_task_security_list_lock, flags);
324 list_del_rcu(&ptr->list);
325 spin_unlock_irqrestore(&ccs_task_security_list_lock, flags);
326 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8)
327 call_rcu(&ptr->rcu, ccs_rcu_free);
328 #else
329 call_rcu(&ptr->rcu, ccs_rcu_free, ptr);
330 #endif
331 }
332
333 #endif
334
335 /**
336 * ccs_mm_init - Initialize mm related code.
337 *
338 * Returns nothing.
339 */
340 void __init ccs_mm_init(void)
341 {
342 int idx;
343 for (idx = 0; idx < CCS_MAX_HASH; idx++)
344 INIT_LIST_HEAD(&ccs_name_list[idx]);
345 #ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
346 for (idx = 0; idx < CCS_MAX_TASK_SECURITY_HASH; idx++)
347 INIT_LIST_HEAD(&ccs_task_security_list[idx]);
348 #endif
349 smp_wmb(); /* Avoid out of order execution. */
350 #ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
351 ccsecurity_ops.alloc_task_security = __ccs_alloc_task_security;
352 ccsecurity_ops.free_task_security = __ccs_free_task_security;
353 #endif
354 ccs_kernel_domain.domainname = ccs_get_name("<kernel>");
355 list_add_tail_rcu(&ccs_kernel_domain.list, &ccs_domain_list);
356 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26