lkml.org 
[lkml]   [2009]   [Oct]   [4]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[TOMOYO #16 12/25] TOMOYO: Memory management support.
This patch contains memory management code for TOMOYO.

Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
security/tomoyo/memory.c | 391 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 391 insertions(+)

--- /dev/null
+++ security-testing-2.6/security/tomoyo/memory.c
@@ -0,0 +1,391 @@
+/*
+ * security/tomoyo/memory.c
+ *
+ * Copyright (C) 2005-2009 NTT DATA CORPORATION
+ */
+#include "internal.h"
+
+void tomoyo_warn_oom(const char *function)
+{
+ /* Reduce error messages. */
+ static pid_t tomoyo_last_pid;
+ const pid_t pid = current->pid;
+ if (tomoyo_last_pid != pid) {
+ printk(KERN_WARNING "ERROR: Out of memory at %s.\n",
+ function);
+ tomoyo_last_pid = pid;
+ }
+ if (!tomoyo_policy_loaded)
+ panic("MAC Initialization failed.\n");
+}
+
+static atomic_t tomoyo_policy_memory_size;
+static unsigned int tomoyo_quota_for_policy;
+
+/**
+ * tomoyo_memory_ok - Check memory quota.
+ *
+ * @ptr: Pointer to allocated memory.
+ * @size: Size in byte.
+ *
+ * Returns true if @ptr is not NULL and quota not exceeded, false otehrwise.
+ */
+bool tomoyo_memory_ok(const void *ptr, const unsigned int size)
+{
+ size_t s = tomoyo_round2(size);
+ atomic_add(s, &tomoyo_policy_memory_size);
+ if (ptr && (!tomoyo_quota_for_policy ||
+ atomic_read(&tomoyo_policy_memory_size)
+ <= tomoyo_quota_for_policy))
+ return true;
+ atomic_sub(s, &tomoyo_policy_memory_size);
+ tomoyo_warn_oom(__func__);
+ return false;
+}
+
+/**
+ * tomoyo_commit_ok - Check memory quota.
+ *
+ * @ptr: Pointer to allocated memory.
+ * @data: Data to copy from.
+ * @size: Size in byte.
+ *
+ * Returns true if @ptr is not NULL and quota not exceeded, false otehrwise.
+ */
+bool tomoyo_commit_ok(void *ptr, void *data, const unsigned int size)
+{
+ if (tomoyo_memory_ok(ptr, size)) {
+ memmove(ptr, data, size);
+ memset(data, 0, size);
+ return true;
+ }
+ return false;
+}
+
+
+/**
+ * tomoyo_memory_free - Free memory for elements.
+ *
+ * @ptr: Pointer to allocated memory.
+ * @size: Size in byte.
+ */
+void tomoyo_memory_free(const void *ptr, size_t size)
+{
+ atomic_sub(tomoyo_round2(size), &tomoyo_policy_memory_size);
+ kfree(ptr);
+}
+
+static LIST_HEAD(tomoyo_address_list);
+
+/**
+ * tomoyo_get_ipv6_address - Keep the given IPv6 address on the RAM.
+ *
+ * @addr: Pointer to "struct in6_addr".
+ *
+ * Returns pointer to "struct in6_addr" on success, NULL otherwise.
+ *
+ * The RAM is shared, so NEVER try to modify or kfree() the returned address.
+ */
+const struct in6_addr *tomoyo_get_ipv6_address(const struct in6_addr *addr)
+{
+ struct tomoyo_ipv6addr_entry *entry;
+ struct tomoyo_ipv6addr_entry *ptr;
+ int error = -ENOMEM;
+ if (!addr)
+ return NULL;
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ mutex_lock(&tomoyo_policy_lock);
+ list_for_each_entry(ptr, &tomoyo_address_list, list) {
+ if (memcmp(&ptr->addr, addr, sizeof(*addr)))
+ continue;
+ atomic_inc(&ptr->users);
+ error = 0;
+ break;
+ }
+ if (error && tomoyo_memory_ok(entry, sizeof(*entry))) {
+ ptr = entry;
+ ptr->addr = *addr;
+ atomic_set(&ptr->users, 1);
+ list_add_tail(&ptr->list, &tomoyo_address_list);
+ entry = NULL;
+ }
+ mutex_unlock(&tomoyo_policy_lock);
+ kfree(entry);
+ return ptr ? &ptr->addr : NULL;
+}
+
+/**
+ * tomoyo_put_ipv6_address - Delete the given IPv6 address on the RAM.
+ *
+ * @addr: Pointer to "struct in6_addr".
+ */
+void tomoyo_put_ipv6_address(const struct in6_addr *addr)
+{
+ struct tomoyo_ipv6addr_entry *ptr;
+ bool can_delete = false;
+ if (!addr)
+ return;
+ ptr = container_of(addr, struct tomoyo_ipv6addr_entry, addr);
+ mutex_lock(&tomoyo_policy_lock);
+ if (atomic_dec_and_test(&ptr->users)) {
+ list_del(&ptr->list);
+ can_delete = true;
+ }
+ mutex_unlock(&tomoyo_policy_lock);
+ if (can_delete)
+ tomoyo_memory_free(ptr, sizeof(*ptr));
+}
+
+/**
+ * tomoyo_put_condition - Delete memory for "struct tomoyo_condition".
+ *
+ * @cond: Pointer to "struct tomoyo_condition".
+ */
+void tomoyo_put_condition(struct tomoyo_condition *cond)
+{
+ const struct tomoyo_condition_element *condp;
+ struct tomoyo_number_union *numbers_p;
+ struct tomoyo_name_union *names_p;
+ const struct tomoyo_argv_entry *argv;
+ const struct tomoyo_envp_entry *envp;
+ u16 condc;
+ u16 numbers_count;
+ u16 names_count;
+ u16 argc;
+ u16 envc;
+ u16 i;
+ bool can_delete = false;
+ if (!cond)
+ return;
+ BUG_ON(atomic_read(&cond->users) <= 0);
+ mutex_lock(&tomoyo_policy_lock);
+ if (atomic_dec_and_test(&cond->users)) {
+ list_del(&cond->list);
+ can_delete = true;
+ }
+ mutex_unlock(&tomoyo_policy_lock);
+ if (!can_delete)
+ return;
+ condc = cond->condc;
+ numbers_count = cond->numbers_count;
+ names_count = cond->names_count;
+ argc = cond->argc;
+ envc = cond->envc;
+ condp = (const struct tomoyo_condition_element *) (cond + 1);
+ numbers_p = (struct tomoyo_number_union *) (condp + condc);
+ names_p = (struct tomoyo_name_union *) (numbers_p + numbers_count);
+ argv = (const struct tomoyo_argv_entry *) (names_p + names_count);
+ envp = (const struct tomoyo_envp_entry *) (argv + argc);
+ for (i = 0; i < numbers_count; i++)
+ tomoyo_put_number_union(numbers_p++);
+ for (i = 0; i < names_count; i++)
+ tomoyo_put_name_union(names_p++);
+ for (i = 0; i < argc; argv++, i++)
+ tomoyo_put_name(argv->value);
+ for (i = 0; i < envc; envp++, i++) {
+ tomoyo_put_name(envp->name);
+ tomoyo_put_name(envp->value);
+ }
+ tomoyo_memory_free(cond, cond->size);
+}
+
+/*
+ * TOMOYO uses this hash only when appending a string into the string
+ * table. Frequency of appending strings is very low. So we don't need
+ * large (e.g. 64k) hash size. 256 will be sufficient.
+ */
+#define TOMOYO_MAX_HASH 256
+
+/*
+ * tomoyo_name_entry is a structure which is used for linking
+ * "struct tomoyo_path_info" into tomoyo_name_list .
+ */
+struct tomoyo_name_entry {
+ struct list_head list;
+ atomic_t users;
+ int size;
+ struct tomoyo_path_info entry;
+};
+
+/*
+ * tomoyo_name_list is used for holding string data used by TOMOYO.
+ * Since same string data is likely used for multiple times (e.g.
+ * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of
+ * "const struct tomoyo_path_info *".
+ */
+static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
+static DEFINE_MUTEX(tomoyo_name_list_lock);
+
+/**
+ * tomoyo_get_name - Allocate memory for string data.
+ *
+ * @name: The string to store into the permernent memory.
+ *
+ * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
+ */
+const struct tomoyo_path_info *tomoyo_get_name(const char *name)
+{
+ struct tomoyo_name_entry *ptr;
+ unsigned int hash;
+ int len;
+ int allocated_len;
+
+ if (!name)
+ return NULL;
+ len = strlen(name) + 1;
+ hash = full_name_hash((const unsigned char *) name, len - 1);
+ mutex_lock(&tomoyo_name_list_lock);
+ list_for_each_entry(ptr, &tomoyo_name_list[hash % TOMOYO_MAX_HASH],
+ list) {
+ if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
+ continue;
+ atomic_inc(&ptr->users);
+ goto out;
+ }
+ allocated_len = tomoyo_round2(sizeof(*ptr) + len);
+ ptr = kzalloc(allocated_len, GFP_KERNEL);
+ if (!ptr || (tomoyo_quota_for_policy &&
+ atomic_read(&tomoyo_policy_memory_size) + allocated_len
+ > tomoyo_quota_for_policy)) {
+ kfree(ptr);
+ ptr = NULL;
+ tomoyo_warn_oom(__func__);
+ goto out;
+ }
+ atomic_add(allocated_len, &tomoyo_policy_memory_size);
+ ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
+ memmove((char *) ptr->entry.name, name, len);
+ atomic_set(&ptr->users, 1);
+ tomoyo_fill_path_info(&ptr->entry);
+ ptr->size = allocated_len;
+ list_add_tail(&ptr->list, &tomoyo_name_list[hash % TOMOYO_MAX_HASH]);
+ out:
+ mutex_unlock(&tomoyo_name_list_lock);
+ return ptr ? &ptr->entry : NULL;
+}
+
+/**
+ * tomoyo_put_name - Delete shared memory for string data.
+ *
+ * @name: Pointer to "struct tomoyo_path_info".
+ */
+void tomoyo_put_name(const struct tomoyo_path_info *name)
+{
+ struct tomoyo_name_entry *ptr;
+ bool can_delete = false;
+ if (!name)
+ return;
+ ptr = container_of(name, struct tomoyo_name_entry, entry);
+ mutex_lock(&tomoyo_name_list_lock);
+ if (atomic_dec_and_test(&ptr->users)) {
+ list_del(&ptr->list);
+ can_delete = true;
+ }
+ mutex_unlock(&tomoyo_name_list_lock);
+ if (can_delete) {
+ atomic_sub(ptr->size, &tomoyo_policy_memory_size);
+ kfree(ptr);
+ }
+}
+
+/**
+ * tomoyo_mm_init - Initialize mm code.
+ *
+ * Returns 0.
+ */
+static int __init tomoyo_mm_init(void)
+{
+ int i;
+ if (!tomoyo_registered)
+ return 0;
+ for (i = 0; i < TOMOYO_MAX_HASH; i++)
+ INIT_LIST_HEAD(&tomoyo_name_list[i]);
+ INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list);
+ tomoyo_kernel_domain.domainname = tomoyo_get_name(ROOT_NAME);
+ list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
+ if (tomoyo_find_domain(ROOT_NAME) != &tomoyo_kernel_domain)
+ panic("Can't register tomoyo_kernel_domain");
+#ifdef CONFIG_SECURITY_TOMOYO_BUILTIN_INITIALIZERS
+ {
+ /* Load built-in policy. */
+ static char tomoyo_builtin_initializers[] __initdata
+ = CONFIG_SECURITY_TOMOYO_BUILTIN_INITIALIZERS;
+ char *cp = tomoyo_builtin_initializers;
+ tomoyo_normalize_line(cp);
+ while (cp && *cp) {
+ char *cp2 = strchr(cp, ' ');
+ if (cp2)
+ *cp2++ = '\0';
+ tomoyo_write_domain_initializer_policy(cp, false,
+ false);
+ cp = cp2;
+ }
+ }
+#endif
+ return 0;
+}
+core_initcall(tomoyo_mm_init);
+
+unsigned int tomoyo_audit_log_memory_size;
+unsigned int tomoyo_quota_for_audit_log;
+
+unsigned int tomoyo_query_memory_size;
+unsigned int tomoyo_quota_for_query;
+
+/**
+ * tomoyo_read_memory_counter - Check for memory usage.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ */
+void tomoyo_read_memory_counter(struct tomoyo_io_buffer *head)
+{
+ const unsigned int usage[3] = {
+ atomic_read(&tomoyo_policy_memory_size),
+ tomoyo_audit_log_memory_size,
+ tomoyo_query_memory_size
+ };
+ const unsigned int quota[3] = {
+ tomoyo_quota_for_policy,
+ tomoyo_quota_for_audit_log,
+ tomoyo_quota_for_query
+ };
+ static const char *header[4] = {
+ "Policy: ",
+ "Audit logs: ",
+ "Query lists:",
+ "Total: "
+ };
+ unsigned int total = 0;
+ int i;
+ if (head->read_eof)
+ return;
+ for (i = 0; i < 3; i++) {
+ total += usage[i];
+ tomoyo_io_printf(head, "%s %10u", header[i], usage[i]);
+ if (quota[i])
+ tomoyo_io_printf(head, " (Quota: %10u)", quota[i]);
+ tomoyo_io_printf(head, "\n");
+ }
+ tomoyo_io_printf(head, "%s %10u\n", header[3], total);
+ head->read_eof = true;
+}
+
+/**
+ * tomoyo_write_memory_quota - Set memory quota.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0.
+ */
+int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head)
+{
+ char *data = head->write_buf;
+ unsigned int size;
+ if (sscanf(data, "Policy: %u", &size) == 1)
+ tomoyo_quota_for_policy = size;
+ else if (sscanf(data, "Audit logs: %u", &size) == 1)
+ tomoyo_quota_for_audit_log = size;
+ else if (sscanf(data, "Query lists: %u", &size) == 1)
+ tomoyo_quota_for_query = size;
+ return 0;
+}
--


\
 
 \ /
  Last update: 2009-10-04 15:01    [W:0.588 / U:0.820 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site