]> nv-tegra.nvidia Code Review - linux-2.6.git/blob - security/tomoyo/memory.c
TOMOYO: Add auditing interface.
[linux-2.6.git] / security / tomoyo / memory.c
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  */
18 void 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 /* Memoy currently used by policy/audit log/query. */
33 unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT];
34 /* Memory quota for "policy"/"audit log"/"query". */
35 unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT];
36
37 /* Memory allocated for policy. */
38 static atomic_t tomoyo_policy_memory_size;
39 /* Quota for holding policy. */
40 static unsigned int tomoyo_quota_for_policy;
41
42 /**
43  * tomoyo_memory_ok - Check memory quota.
44  *
45  * @ptr: Pointer to allocated memory.
46  *
47  * Returns true on success, false otherwise.
48  *
49  * Returns true if @ptr is not NULL and quota not exceeded, false otherwise.
50  */
51 bool tomoyo_memory_ok(void *ptr)
52 {
53         size_t s = ptr ? ksize(ptr) : 0;
54         atomic_add(s, &tomoyo_policy_memory_size);
55         if (ptr && (!tomoyo_quota_for_policy ||
56                     atomic_read(&tomoyo_policy_memory_size)
57                     <= tomoyo_quota_for_policy)) {
58                 memset(ptr, 0, s);
59                 return true;
60         }
61         atomic_sub(s, &tomoyo_policy_memory_size);
62         tomoyo_warn_oom(__func__);
63         return false;
64 }
65
66 /**
67  * tomoyo_commit_ok - Check memory quota.
68  *
69  * @data:   Data to copy from.
70  * @size:   Size in byte.
71  *
72  * Returns pointer to allocated memory on success, NULL otherwise.
73  * @data is zero-cleared on success.
74  */
75 void *tomoyo_commit_ok(void *data, const unsigned int size)
76 {
77         void *ptr = kzalloc(size, GFP_NOFS);
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_memory_free - Free memory for elements.
89  *
90  * @ptr:  Pointer to allocated memory.
91  */
92 void tomoyo_memory_free(void *ptr)
93 {
94         atomic_sub(ksize(ptr), &tomoyo_policy_memory_size);
95         kfree(ptr);
96 }
97
98 /**
99  * tomoyo_get_group - Allocate memory for "struct tomoyo_path_group"/"struct tomoyo_number_group".
100  *
101  * @param: Pointer to "struct tomoyo_acl_param".
102  * @idx:   Index number.
103  *
104  * Returns pointer to "struct tomoyo_group" on success, NULL otherwise.
105  */
106 struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param,
107                                       const u8 idx)
108 {
109         struct tomoyo_group e = { };
110         struct tomoyo_group *group = NULL;
111         struct list_head *list;
112         const char *group_name = tomoyo_read_token(param);
113         bool found = false;
114         if (!tomoyo_correct_word(group_name) || idx >= TOMOYO_MAX_GROUP)
115                 return NULL;
116         e.group_name = tomoyo_get_name(group_name);
117         if (!e.group_name)
118                 return NULL;
119         if (mutex_lock_interruptible(&tomoyo_policy_lock))
120                 goto out;
121         list = &tomoyo_group_list[idx];
122         list_for_each_entry(group, list, head.list) {
123                 if (e.group_name != group->group_name)
124                         continue;
125                 atomic_inc(&group->head.users);
126                 found = true;
127                 break;
128         }
129         if (!found) {
130                 struct tomoyo_group *entry = tomoyo_commit_ok(&e, sizeof(e));
131                 if (entry) {
132                         INIT_LIST_HEAD(&entry->member_list);
133                         atomic_set(&entry->head.users, 1);
134                         list_add_tail_rcu(&entry->head.list, list);
135                         group = entry;
136                         found = true;
137                 }
138         }
139         mutex_unlock(&tomoyo_policy_lock);
140 out:
141         tomoyo_put_name(e.group_name);
142         return found ? group : NULL;
143 }
144
145 /*
146  * tomoyo_name_list is used for holding string data used by TOMOYO.
147  * Since same string data is likely used for multiple times (e.g.
148  * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of
149  * "const struct tomoyo_path_info *".
150  */
151 struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
152
153 /**
154  * tomoyo_get_name - Allocate permanent memory for string data.
155  *
156  * @name: The string to store into the permernent memory.
157  *
158  * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
159  */
160 const struct tomoyo_path_info *tomoyo_get_name(const char *name)
161 {
162         struct tomoyo_name *ptr;
163         unsigned int hash;
164         int len;
165         int allocated_len;
166         struct list_head *head;
167
168         if (!name)
169                 return NULL;
170         len = strlen(name) + 1;
171         hash = full_name_hash((const unsigned char *) name, len - 1);
172         head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)];
173         if (mutex_lock_interruptible(&tomoyo_policy_lock))
174                 return NULL;
175         list_for_each_entry(ptr, head, head.list) {
176                 if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
177                         continue;
178                 atomic_inc(&ptr->head.users);
179                 goto out;
180         }
181         ptr = kzalloc(sizeof(*ptr) + len, GFP_NOFS);
182         allocated_len = ptr ? ksize(ptr) : 0;
183         if (!ptr || (tomoyo_quota_for_policy &&
184                      atomic_read(&tomoyo_policy_memory_size) + allocated_len
185                      > tomoyo_quota_for_policy)) {
186                 kfree(ptr);
187                 ptr = NULL;
188                 tomoyo_warn_oom(__func__);
189                 goto out;
190         }
191         atomic_add(allocated_len, &tomoyo_policy_memory_size);
192         ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
193         memmove((char *) ptr->entry.name, name, len);
194         atomic_set(&ptr->head.users, 1);
195         tomoyo_fill_path_info(&ptr->entry);
196         list_add_tail(&ptr->head.list, head);
197  out:
198         mutex_unlock(&tomoyo_policy_lock);
199         return ptr ? &ptr->entry : NULL;
200 }
201
202 /**
203  * tomoyo_mm_init - Initialize mm related code.
204  */
205 void __init tomoyo_mm_init(void)
206 {
207         int idx;
208
209         for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++)
210                 INIT_LIST_HEAD(&tomoyo_policy_list[idx]);
211         for (idx = 0; idx < TOMOYO_MAX_GROUP; idx++)
212                 INIT_LIST_HEAD(&tomoyo_group_list[idx]);
213         for (idx = 0; idx < TOMOYO_MAX_HASH; idx++)
214                 INIT_LIST_HEAD(&tomoyo_name_list[idx]);
215         INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list);
216         tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME);
217         list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
218         idx = tomoyo_read_lock();
219         if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain)
220                 panic("Can't register tomoyo_kernel_domain");
221 #if 0
222         /* Will be replaced with tomoyo_load_builtin_policy(). */
223         {
224                 /* Load built-in policy. */
225                 tomoyo_write_transition_control("/sbin/hotplug", false,
226                                         TOMOYO_TRANSITION_CONTROL_INITIALIZE);
227                 tomoyo_write_transition_control("/sbin/modprobe", false,
228                                         TOMOYO_TRANSITION_CONTROL_INITIALIZE);
229         }
230 #endif
231         tomoyo_read_unlock(idx);
232 }
233
234
235 /* Memory allocated for query lists. */
236 unsigned int tomoyo_query_memory_size;
237 /* Quota for holding query lists. */
238 unsigned int tomoyo_quota_for_query;
239
240 /**
241  * tomoyo_read_memory_counter - Check for memory usage in bytes.
242  *
243  * @head: Pointer to "struct tomoyo_io_buffer".
244  *
245  * Returns memory usage.
246  */
247 void tomoyo_read_memory_counter(struct tomoyo_io_buffer *head)
248 {
249         if (!head->r.eof) {
250                 const unsigned int policy
251                         = atomic_read(&tomoyo_policy_memory_size);
252                 const unsigned int query = tomoyo_query_memory_size;
253                 char buffer[64];
254
255                 memset(buffer, 0, sizeof(buffer));
256                 if (tomoyo_quota_for_policy)
257                         snprintf(buffer, sizeof(buffer) - 1,
258                                  "   (Quota: %10u)",
259                                  tomoyo_quota_for_policy);
260                 else
261                         buffer[0] = '\0';
262                 tomoyo_io_printf(head, "Policy:       %10u%s\n", policy,
263                                  buffer);
264                 if (tomoyo_quota_for_query)
265                         snprintf(buffer, sizeof(buffer) - 1,
266                                  "   (Quota: %10u)",
267                                  tomoyo_quota_for_query);
268                 else
269                         buffer[0] = '\0';
270                 tomoyo_io_printf(head, "Query lists:  %10u%s\n", query,
271                                  buffer);
272                 tomoyo_io_printf(head, "Total:        %10u\n", policy + query);
273                 head->r.eof = true;
274         }
275 }
276
277 /**
278  * tomoyo_write_memory_quota - Set memory quota.
279  *
280  * @head: Pointer to "struct tomoyo_io_buffer".
281  *
282  * Returns 0.
283  */
284 int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head)
285 {
286         char *data = head->write_buf;
287         unsigned int size;
288
289         if (sscanf(data, "Policy: %u", &size) == 1)
290                 tomoyo_quota_for_policy = size;
291         else if (sscanf(data, "Query lists: %u", &size) == 1)
292                 tomoyo_quota_for_query = size;
293         return 0;
294 }