diff options
Diffstat (limited to 'security/tomoyo/realpath.c')
-rw-r--r-- | security/tomoyo/realpath.c | 269 |
1 files changed, 71 insertions, 198 deletions
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 455bc391b76d..cf7d61f781b9 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c | |||
@@ -14,9 +14,8 @@ | |||
14 | #include <linux/mnt_namespace.h> | 14 | #include <linux/mnt_namespace.h> |
15 | #include <linux/fs_struct.h> | 15 | #include <linux/fs_struct.h> |
16 | #include <linux/hash.h> | 16 | #include <linux/hash.h> |
17 | 17 | #include <linux/magic.h> | |
18 | #include "common.h" | 18 | #include "common.h" |
19 | #include "realpath.h" | ||
20 | 19 | ||
21 | /** | 20 | /** |
22 | * tomoyo_encode: Convert binary string to ascii string. | 21 | * tomoyo_encode: Convert binary string to ascii string. |
@@ -97,7 +96,7 @@ int tomoyo_realpath_from_path2(struct path *path, char *newname, | |||
97 | spin_unlock(&dcache_lock); | 96 | spin_unlock(&dcache_lock); |
98 | /* Prepend "/proc" prefix if using internal proc vfs mount. */ | 97 | /* Prepend "/proc" prefix if using internal proc vfs mount. */ |
99 | if (!IS_ERR(sp) && (path->mnt->mnt_flags & MNT_INTERNAL) && | 98 | if (!IS_ERR(sp) && (path->mnt->mnt_flags & MNT_INTERNAL) && |
100 | (strcmp(path->mnt->mnt_sb->s_type->name, "proc") == 0)) { | 99 | (path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) { |
101 | sp -= 5; | 100 | sp -= 5; |
102 | if (sp >= newname) | 101 | if (sp >= newname) |
103 | memcpy(sp, "/proc", 5); | 102 | memcpy(sp, "/proc", 5); |
@@ -134,12 +133,12 @@ int tomoyo_realpath_from_path2(struct path *path, char *newname, | |||
134 | * | 133 | * |
135 | * Returns the realpath of the given @path on success, NULL otherwise. | 134 | * Returns the realpath of the given @path on success, NULL otherwise. |
136 | * | 135 | * |
137 | * These functions use tomoyo_alloc(), so the caller must call tomoyo_free() | 136 | * These functions use kzalloc(), so the caller must call kfree() |
138 | * if these functions didn't return NULL. | 137 | * if these functions didn't return NULL. |
139 | */ | 138 | */ |
140 | char *tomoyo_realpath_from_path(struct path *path) | 139 | char *tomoyo_realpath_from_path(struct path *path) |
141 | { | 140 | { |
142 | char *buf = tomoyo_alloc(sizeof(struct tomoyo_page_buffer)); | 141 | char *buf = kzalloc(sizeof(struct tomoyo_page_buffer), GFP_KERNEL); |
143 | 142 | ||
144 | BUILD_BUG_ON(sizeof(struct tomoyo_page_buffer) | 143 | BUILD_BUG_ON(sizeof(struct tomoyo_page_buffer) |
145 | <= TOMOYO_MAX_PATHNAME_LEN - 1); | 144 | <= TOMOYO_MAX_PATHNAME_LEN - 1); |
@@ -148,7 +147,7 @@ char *tomoyo_realpath_from_path(struct path *path) | |||
148 | if (tomoyo_realpath_from_path2(path, buf, | 147 | if (tomoyo_realpath_from_path2(path, buf, |
149 | TOMOYO_MAX_PATHNAME_LEN - 1) == 0) | 148 | TOMOYO_MAX_PATHNAME_LEN - 1) == 0) |
150 | return buf; | 149 | return buf; |
151 | tomoyo_free(buf); | 150 | kfree(buf); |
152 | return NULL; | 151 | return NULL; |
153 | } | 152 | } |
154 | 153 | ||
@@ -191,98 +190,47 @@ char *tomoyo_realpath_nofollow(const char *pathname) | |||
191 | } | 190 | } |
192 | 191 | ||
193 | /* Memory allocated for non-string data. */ | 192 | /* Memory allocated for non-string data. */ |
194 | static unsigned int tomoyo_allocated_memory_for_elements; | 193 | static atomic_t tomoyo_policy_memory_size; |
195 | /* Quota for holding non-string data. */ | 194 | /* Quota for holding policy. */ |
196 | static unsigned int tomoyo_quota_for_elements; | 195 | static unsigned int tomoyo_quota_for_policy; |
197 | 196 | ||
198 | /** | 197 | /** |
199 | * tomoyo_alloc_element - Allocate permanent memory for structures. | 198 | * tomoyo_memory_ok - Check memory quota. |
200 | * | 199 | * |
201 | * @size: Size in bytes. | 200 | * @ptr: Pointer to allocated memory. |
202 | * | 201 | * |
203 | * Returns pointer to allocated memory on success, NULL otherwise. | 202 | * Returns true on success, false otherwise. |
204 | * | 203 | * |
205 | * Memory has to be zeroed. | 204 | * Caller holds tomoyo_policy_lock. |
206 | * The RAM is chunked, so NEVER try to kfree() the returned pointer. | 205 | * Memory pointed by @ptr will be zeroed on success. |
207 | */ | 206 | */ |
208 | void *tomoyo_alloc_element(const unsigned int size) | 207 | bool tomoyo_memory_ok(void *ptr) |
209 | { | 208 | { |
210 | static char *buf; | 209 | int allocated_len = ptr ? ksize(ptr) : 0; |
211 | static DEFINE_MUTEX(lock); | 210 | atomic_add(allocated_len, &tomoyo_policy_memory_size); |
212 | static unsigned int buf_used_len = PATH_MAX; | 211 | if (ptr && (!tomoyo_quota_for_policy || |
213 | char *ptr = NULL; | 212 | atomic_read(&tomoyo_policy_memory_size) |
214 | /*Assumes sizeof(void *) >= sizeof(long) is true. */ | 213 | <= tomoyo_quota_for_policy)) { |
215 | const unsigned int word_aligned_size | 214 | memset(ptr, 0, allocated_len); |
216 | = roundup(size, max(sizeof(void *), sizeof(long))); | 215 | return true; |
217 | if (word_aligned_size > PATH_MAX) | ||
218 | return NULL; | ||
219 | mutex_lock(&lock); | ||
220 | if (buf_used_len + word_aligned_size > PATH_MAX) { | ||
221 | if (!tomoyo_quota_for_elements || | ||
222 | tomoyo_allocated_memory_for_elements | ||
223 | + PATH_MAX <= tomoyo_quota_for_elements) | ||
224 | ptr = kzalloc(PATH_MAX, GFP_KERNEL); | ||
225 | if (!ptr) { | ||
226 | printk(KERN_WARNING "ERROR: Out of memory " | ||
227 | "for tomoyo_alloc_element().\n"); | ||
228 | if (!tomoyo_policy_loaded) | ||
229 | panic("MAC Initialization failed.\n"); | ||
230 | } else { | ||
231 | buf = ptr; | ||
232 | tomoyo_allocated_memory_for_elements += PATH_MAX; | ||
233 | buf_used_len = word_aligned_size; | ||
234 | ptr = buf; | ||
235 | } | ||
236 | } else if (word_aligned_size) { | ||
237 | int i; | ||
238 | ptr = buf + buf_used_len; | ||
239 | buf_used_len += word_aligned_size; | ||
240 | for (i = 0; i < word_aligned_size; i++) { | ||
241 | if (!ptr[i]) | ||
242 | continue; | ||
243 | printk(KERN_ERR "WARNING: Reserved memory was tainted! " | ||
244 | "The system might go wrong.\n"); | ||
245 | ptr[i] = '\0'; | ||
246 | } | ||
247 | } | 216 | } |
248 | mutex_unlock(&lock); | 217 | printk(KERN_WARNING "ERROR: Out of memory " |
249 | return ptr; | 218 | "for tomoyo_alloc_element().\n"); |
219 | if (!tomoyo_policy_loaded) | ||
220 | panic("MAC Initialization failed.\n"); | ||
221 | return false; | ||
250 | } | 222 | } |
251 | 223 | ||
252 | /* Memory allocated for string data in bytes. */ | 224 | /** |
253 | static unsigned int tomoyo_allocated_memory_for_savename; | 225 | * tomoyo_memory_free - Free memory for elements. |
254 | /* Quota for holding string data in bytes. */ | ||
255 | static unsigned int tomoyo_quota_for_savename; | ||
256 | |||
257 | /* | ||
258 | * TOMOYO uses this hash only when appending a string into the string | ||
259 | * table. Frequency of appending strings is very low. So we don't need | ||
260 | * large (e.g. 64k) hash size. 256 will be sufficient. | ||
261 | */ | ||
262 | #define TOMOYO_HASH_BITS 8 | ||
263 | #define TOMOYO_MAX_HASH (1u<<TOMOYO_HASH_BITS) | ||
264 | |||
265 | /* | ||
266 | * tomoyo_name_entry is a structure which is used for linking | ||
267 | * "struct tomoyo_path_info" into tomoyo_name_list . | ||
268 | * | 226 | * |
269 | * Since tomoyo_name_list manages a list of strings which are shared by | 227 | * @ptr: Pointer to allocated memory. |
270 | * multiple processes (whereas "struct tomoyo_path_info" inside | ||
271 | * "struct tomoyo_path_info_with_data" is not shared), a reference counter will | ||
272 | * be added to "struct tomoyo_name_entry" rather than "struct tomoyo_path_info" | ||
273 | * when TOMOYO starts supporting garbage collector. | ||
274 | */ | 228 | */ |
275 | struct tomoyo_name_entry { | 229 | void tomoyo_memory_free(void *ptr) |
276 | struct list_head list; | 230 | { |
277 | struct tomoyo_path_info entry; | 231 | atomic_sub(ksize(ptr), &tomoyo_policy_memory_size); |
278 | }; | 232 | kfree(ptr); |
279 | 233 | } | |
280 | /* Structure for available memory region. */ | ||
281 | struct tomoyo_free_memory_block_list { | ||
282 | struct list_head list; | ||
283 | char *ptr; /* Pointer to a free area. */ | ||
284 | int len; /* Length of the area. */ | ||
285 | }; | ||
286 | 234 | ||
287 | /* | 235 | /* |
288 | * tomoyo_name_list is used for holding string data used by TOMOYO. | 236 | * tomoyo_name_list is used for holding string data used by TOMOYO. |
@@ -290,87 +238,58 @@ struct tomoyo_free_memory_block_list { | |||
290 | * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of | 238 | * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of |
291 | * "const struct tomoyo_path_info *". | 239 | * "const struct tomoyo_path_info *". |
292 | */ | 240 | */ |
293 | static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; | 241 | struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; |
242 | /* Lock for protecting tomoyo_name_list . */ | ||
243 | DEFINE_MUTEX(tomoyo_name_list_lock); | ||
294 | 244 | ||
295 | /** | 245 | /** |
296 | * tomoyo_save_name - Allocate permanent memory for string data. | 246 | * tomoyo_get_name - Allocate permanent memory for string data. |
297 | * | 247 | * |
298 | * @name: The string to store into the permernent memory. | 248 | * @name: The string to store into the permernent memory. |
299 | * | 249 | * |
300 | * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. | 250 | * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. |
301 | * | ||
302 | * The RAM is shared, so NEVER try to modify or kfree() the returned name. | ||
303 | */ | 251 | */ |
304 | const struct tomoyo_path_info *tomoyo_save_name(const char *name) | 252 | const struct tomoyo_path_info *tomoyo_get_name(const char *name) |
305 | { | 253 | { |
306 | static LIST_HEAD(fmb_list); | ||
307 | static DEFINE_MUTEX(lock); | ||
308 | struct tomoyo_name_entry *ptr; | 254 | struct tomoyo_name_entry *ptr; |
309 | unsigned int hash; | 255 | unsigned int hash; |
310 | /* fmb contains available size in bytes. | ||
311 | fmb is removed from the fmb_list when fmb->len becomes 0. */ | ||
312 | struct tomoyo_free_memory_block_list *fmb; | ||
313 | int len; | 256 | int len; |
314 | char *cp; | 257 | int allocated_len; |
315 | struct list_head *head; | 258 | struct list_head *head; |
316 | 259 | ||
317 | if (!name) | 260 | if (!name) |
318 | return NULL; | 261 | return NULL; |
319 | len = strlen(name) + 1; | 262 | len = strlen(name) + 1; |
320 | if (len > TOMOYO_MAX_PATHNAME_LEN) { | ||
321 | printk(KERN_WARNING "ERROR: Name too long " | ||
322 | "for tomoyo_save_name().\n"); | ||
323 | return NULL; | ||
324 | } | ||
325 | hash = full_name_hash((const unsigned char *) name, len - 1); | 263 | hash = full_name_hash((const unsigned char *) name, len - 1); |
326 | head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; | 264 | head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; |
327 | 265 | mutex_lock(&tomoyo_name_list_lock); | |
328 | mutex_lock(&lock); | ||
329 | list_for_each_entry(ptr, head, list) { | 266 | list_for_each_entry(ptr, head, list) { |
330 | if (hash == ptr->entry.hash && !strcmp(name, ptr->entry.name)) | 267 | if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name)) |
331 | goto out; | 268 | continue; |
332 | } | 269 | atomic_inc(&ptr->users); |
333 | list_for_each_entry(fmb, &fmb_list, list) { | 270 | goto out; |
334 | if (len <= fmb->len) | ||
335 | goto ready; | ||
336 | } | 271 | } |
337 | if (!tomoyo_quota_for_savename || | 272 | ptr = kzalloc(sizeof(*ptr) + len, GFP_KERNEL); |
338 | tomoyo_allocated_memory_for_savename + PATH_MAX | 273 | allocated_len = ptr ? ksize(ptr) : 0; |
339 | <= tomoyo_quota_for_savename) | 274 | if (!ptr || (tomoyo_quota_for_policy && |
340 | cp = kzalloc(PATH_MAX, GFP_KERNEL); | 275 | atomic_read(&tomoyo_policy_memory_size) + allocated_len |
341 | else | 276 | > tomoyo_quota_for_policy)) { |
342 | cp = NULL; | 277 | kfree(ptr); |
343 | fmb = kzalloc(sizeof(*fmb), GFP_KERNEL); | ||
344 | if (!cp || !fmb) { | ||
345 | kfree(cp); | ||
346 | kfree(fmb); | ||
347 | printk(KERN_WARNING "ERROR: Out of memory " | 278 | printk(KERN_WARNING "ERROR: Out of memory " |
348 | "for tomoyo_save_name().\n"); | 279 | "for tomoyo_get_name().\n"); |
349 | if (!tomoyo_policy_loaded) | 280 | if (!tomoyo_policy_loaded) |
350 | panic("MAC Initialization failed.\n"); | 281 | panic("MAC Initialization failed.\n"); |
351 | ptr = NULL; | 282 | ptr = NULL; |
352 | goto out; | 283 | goto out; |
353 | } | 284 | } |
354 | tomoyo_allocated_memory_for_savename += PATH_MAX; | 285 | atomic_add(allocated_len, &tomoyo_policy_memory_size); |
355 | list_add(&fmb->list, &fmb_list); | 286 | ptr->entry.name = ((char *) ptr) + sizeof(*ptr); |
356 | fmb->ptr = cp; | 287 | memmove((char *) ptr->entry.name, name, len); |
357 | fmb->len = PATH_MAX; | 288 | atomic_set(&ptr->users, 1); |
358 | ready: | ||
359 | ptr = tomoyo_alloc_element(sizeof(*ptr)); | ||
360 | if (!ptr) | ||
361 | goto out; | ||
362 | ptr->entry.name = fmb->ptr; | ||
363 | memmove(fmb->ptr, name, len); | ||
364 | tomoyo_fill_path_info(&ptr->entry); | 289 | tomoyo_fill_path_info(&ptr->entry); |
365 | fmb->ptr += len; | ||
366 | fmb->len -= len; | ||
367 | list_add_tail(&ptr->list, head); | 290 | list_add_tail(&ptr->list, head); |
368 | if (fmb->len == 0) { | ||
369 | list_del(&fmb->list); | ||
370 | kfree(fmb); | ||
371 | } | ||
372 | out: | 291 | out: |
373 | mutex_unlock(&lock); | 292 | mutex_unlock(&tomoyo_name_list_lock); |
374 | return ptr ? &ptr->entry : NULL; | 293 | return ptr ? &ptr->entry : NULL; |
375 | } | 294 | } |
376 | 295 | ||
@@ -385,45 +304,14 @@ void __init tomoyo_realpath_init(void) | |||
385 | for (i = 0; i < TOMOYO_MAX_HASH; i++) | 304 | for (i = 0; i < TOMOYO_MAX_HASH; i++) |
386 | INIT_LIST_HEAD(&tomoyo_name_list[i]); | 305 | INIT_LIST_HEAD(&tomoyo_name_list[i]); |
387 | INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); | 306 | INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); |
388 | tomoyo_kernel_domain.domainname = tomoyo_save_name(TOMOYO_ROOT_NAME); | 307 | tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME); |
389 | list_add_tail(&tomoyo_kernel_domain.list, &tomoyo_domain_list); | 308 | /* |
390 | down_read(&tomoyo_domain_list_lock); | 309 | * tomoyo_read_lock() is not needed because this function is |
310 | * called before the first "delete" request. | ||
311 | */ | ||
312 | list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list); | ||
391 | if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain) | 313 | if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain) |
392 | panic("Can't register tomoyo_kernel_domain"); | 314 | panic("Can't register tomoyo_kernel_domain"); |
393 | up_read(&tomoyo_domain_list_lock); | ||
394 | } | ||
395 | |||
396 | /* Memory allocated for temporary purpose. */ | ||
397 | static atomic_t tomoyo_dynamic_memory_size; | ||
398 | |||
399 | /** | ||
400 | * tomoyo_alloc - Allocate memory for temporary purpose. | ||
401 | * | ||
402 | * @size: Size in bytes. | ||
403 | * | ||
404 | * Returns pointer to allocated memory on success, NULL otherwise. | ||
405 | */ | ||
406 | void *tomoyo_alloc(const size_t size) | ||
407 | { | ||
408 | void *p = kzalloc(size, GFP_KERNEL); | ||
409 | if (p) | ||
410 | atomic_add(ksize(p), &tomoyo_dynamic_memory_size); | ||
411 | return p; | ||
412 | } | ||
413 | |||
414 | /** | ||
415 | * tomoyo_free - Release memory allocated by tomoyo_alloc(). | ||
416 | * | ||
417 | * @p: Pointer returned by tomoyo_alloc(). May be NULL. | ||
418 | * | ||
419 | * Returns nothing. | ||
420 | */ | ||
421 | void tomoyo_free(const void *p) | ||
422 | { | ||
423 | if (p) { | ||
424 | atomic_sub(ksize(p), &tomoyo_dynamic_memory_size); | ||
425 | kfree(p); | ||
426 | } | ||
427 | } | 315 | } |
428 | 316 | ||
429 | /** | 317 | /** |
@@ -436,32 +324,19 @@ void tomoyo_free(const void *p) | |||
436 | int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head) | 324 | int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head) |
437 | { | 325 | { |
438 | if (!head->read_eof) { | 326 | if (!head->read_eof) { |
439 | const unsigned int shared | 327 | const unsigned int policy |
440 | = tomoyo_allocated_memory_for_savename; | 328 | = atomic_read(&tomoyo_policy_memory_size); |
441 | const unsigned int private | ||
442 | = tomoyo_allocated_memory_for_elements; | ||
443 | const unsigned int dynamic | ||
444 | = atomic_read(&tomoyo_dynamic_memory_size); | ||
445 | char buffer[64]; | 329 | char buffer[64]; |
446 | 330 | ||
447 | memset(buffer, 0, sizeof(buffer)); | 331 | memset(buffer, 0, sizeof(buffer)); |
448 | if (tomoyo_quota_for_savename) | 332 | if (tomoyo_quota_for_policy) |
449 | snprintf(buffer, sizeof(buffer) - 1, | ||
450 | " (Quota: %10u)", | ||
451 | tomoyo_quota_for_savename); | ||
452 | else | ||
453 | buffer[0] = '\0'; | ||
454 | tomoyo_io_printf(head, "Shared: %10u%s\n", shared, buffer); | ||
455 | if (tomoyo_quota_for_elements) | ||
456 | snprintf(buffer, sizeof(buffer) - 1, | 333 | snprintf(buffer, sizeof(buffer) - 1, |
457 | " (Quota: %10u)", | 334 | " (Quota: %10u)", |
458 | tomoyo_quota_for_elements); | 335 | tomoyo_quota_for_policy); |
459 | else | 336 | else |
460 | buffer[0] = '\0'; | 337 | buffer[0] = '\0'; |
461 | tomoyo_io_printf(head, "Private: %10u%s\n", private, buffer); | 338 | tomoyo_io_printf(head, "Policy: %10u%s\n", policy, buffer); |
462 | tomoyo_io_printf(head, "Dynamic: %10u\n", dynamic); | 339 | tomoyo_io_printf(head, "Total: %10u\n", policy); |
463 | tomoyo_io_printf(head, "Total: %10u\n", | ||
464 | shared + private + dynamic); | ||
465 | head->read_eof = true; | 340 | head->read_eof = true; |
466 | } | 341 | } |
467 | return 0; | 342 | return 0; |
@@ -479,9 +354,7 @@ int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head) | |||
479 | char *data = head->write_buf; | 354 | char *data = head->write_buf; |
480 | unsigned int size; | 355 | unsigned int size; |
481 | 356 | ||
482 | if (sscanf(data, "Shared: %u", &size) == 1) | 357 | if (sscanf(data, "Policy: %u", &size) == 1) |
483 | tomoyo_quota_for_savename = size; | 358 | tomoyo_quota_for_policy = size; |
484 | else if (sscanf(data, "Private: %u", &size) == 1) | ||
485 | tomoyo_quota_for_elements = size; | ||
486 | return 0; | 359 | return 0; |
487 | } | 360 | } |