Commit | Line | Data |
---|---|---|
c3ef1500 TH |
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 | ||
b22b8b9f TH |
32 | /* Lock for protecting tomoyo_memory_used. */ |
33 | static DEFINE_SPINLOCK(tomoyo_policy_memory_lock); | |
eadd99cc TH |
34 | /* Memoy currently used by policy/audit log/query. */ |
35 | unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT]; | |
36 | /* Memory quota for "policy"/"audit log"/"query". */ | |
37 | unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT]; | |
38 | ||
c3ef1500 TH |
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 | */ | |
48 | bool tomoyo_memory_ok(void *ptr) | |
49 | { | |
b22b8b9f TH |
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; | |
c3ef1500 | 63 | } |
c3ef1500 TH |
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 | */ | |
77 | void *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 | } | |
cfc64fd9 | 85 | kfree(ptr); |
c3ef1500 TH |
86 | return NULL; |
87 | } | |
88 | ||
89 | /** | |
90 | * tomoyo_memory_free - Free memory for elements. | |
91 | * | |
92 | * @ptr: Pointer to allocated memory. | |
93 | */ | |
94 | void tomoyo_memory_free(void *ptr) | |
95 | { | |
b22b8b9f TH |
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); | |
c3ef1500 TH |
100 | kfree(ptr); |
101 | } | |
102 | ||
7c2ea22e TH |
103 | /** |
104 | * tomoyo_get_group - Allocate memory for "struct tomoyo_path_group"/"struct tomoyo_number_group". | |
105 | * | |
a238cf5b TH |
106 | * @param: Pointer to "struct tomoyo_acl_param". |
107 | * @idx: Index number. | |
7c2ea22e TH |
108 | * |
109 | * Returns pointer to "struct tomoyo_group" on success, NULL otherwise. | |
110 | */ | |
a238cf5b TH |
111 | struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param, |
112 | const u8 idx) | |
7c2ea22e TH |
113 | { |
114 | struct tomoyo_group e = { }; | |
115 | struct tomoyo_group *group = NULL; | |
a238cf5b TH |
116 | struct list_head *list; |
117 | const char *group_name = tomoyo_read_token(param); | |
7c2ea22e TH |
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; | |
bd03a3e4 | 126 | list = ¶m->ns->group_list[idx]; |
a238cf5b | 127 | list_for_each_entry(group, list, head.list) { |
7c2ea22e TH |
128 | if (e.group_name != group->group_name) |
129 | continue; | |
0df7e8b8 | 130 | atomic_inc(&group->head.users); |
7c2ea22e TH |
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); | |
0df7e8b8 | 138 | atomic_set(&entry->head.users, 1); |
a238cf5b | 139 | list_add_tail_rcu(&entry->head.list, list); |
7c2ea22e TH |
140 | group = entry; |
141 | found = true; | |
142 | } | |
143 | } | |
144 | mutex_unlock(&tomoyo_policy_lock); | |
a238cf5b | 145 | out: |
7c2ea22e TH |
146 | tomoyo_put_name(e.group_name); |
147 | return found ? group : NULL; | |
148 | } | |
149 | ||
c3ef1500 TH |
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 | */ | |
156 | struct 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 | */ | |
165 | const struct tomoyo_path_info *tomoyo_get_name(const char *name) | |
166 | { | |
e2bf6907 | 167 | struct tomoyo_name *ptr; |
c3ef1500 TH |
168 | unsigned int hash; |
169 | int len; | |
c3ef1500 TH |
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; | |
0df7e8b8 | 179 | list_for_each_entry(ptr, head, head.list) { |
c3ef1500 TH |
180 | if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name)) |
181 | continue; | |
0df7e8b8 | 182 | atomic_inc(&ptr->head.users); |
c3ef1500 TH |
183 | goto out; |
184 | } | |
185 | ptr = kzalloc(sizeof(*ptr) + len, GFP_NOFS); | |
b22b8b9f TH |
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 { | |
c3ef1500 TH |
193 | kfree(ptr); |
194 | ptr = NULL; | |
c3ef1500 | 195 | } |
b22b8b9f | 196 | out: |
c3ef1500 TH |
197 | mutex_unlock(&tomoyo_policy_lock); |
198 | return ptr ? &ptr->entry : NULL; | |
199 | } | |
200 | ||
bd03a3e4 TH |
201 | /* Initial namespace.*/ |
202 | struct tomoyo_policy_namespace tomoyo_kernel_namespace; | |
203 | ||
c3ef1500 TH |
204 | /** |
205 | * tomoyo_mm_init - Initialize mm related code. | |
206 | */ | |
207 | void __init tomoyo_mm_init(void) | |
208 | { | |
209 | int idx; | |
c3ef1500 TH |
210 | for (idx = 0; idx < TOMOYO_MAX_HASH; idx++) |
211 | INIT_LIST_HEAD(&tomoyo_name_list[idx]); | |
bd03a3e4 TH |
212 | tomoyo_kernel_namespace.name = "<kernel>"; |
213 | tomoyo_init_policy_namespace(&tomoyo_kernel_namespace); | |
214 | tomoyo_kernel_domain.ns = &tomoyo_kernel_namespace; | |
c3ef1500 | 215 | INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); |
bd03a3e4 | 216 | tomoyo_kernel_domain.domainname = tomoyo_get_name("<kernel>"); |
c3ef1500 | 217 | list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list); |
c3ef1500 | 218 | } |