lkml.org 
[lkml]   [2008]   [Apr]   [4]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[TOMOYO #7 21/30] Capability restriction part.
TOMOYO Linux uses per-a-domain capability, an approach that associate
capabilities with each domain, and assign a domain for each process.
The advantages of this approach are that

(1) Minimum capabilities required for a process is directly given
compared to setting/clearing/inheriting bit fields of a process's
capability value.

(2) It can support as many types of capabilities as you want.
Regarding per-a-task capability, you need to allocate memory for
individual "task_struct". Thus, the number of supportable capabilities
is bound by the width of variable in bits (i.e. 32 or 64).
Regarding per-a-domain capability, you need to allocate memory for
individual domains. But you can allocate memory dynamically.
Thus, the number of supportable capabilities is not bounded to 32 or 64.

I can support up to 65536 types of capability,
but currently there are not so many capability hooks inserted.
Adding more capability hooks is a future work.

Signed-off-by: Kentaro Takeda <takedakn@nttdata.co.jp>
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: Toshiharu Harada <haradats@nttdata.co.jp>
---
fs/tomoyo_capability.c | 223 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 223 insertions(+)
--- /dev/null
+++ linux-2.6.25-rc8-mm1/fs/tomoyo_capability.c
@@ -0,0 +1,223 @@
+/*
+ * fs/tomoyo_capability.c
+ *
+ * Implementation of the Domain-Based Mandatory Access Control.
+ *
+ * Copyright (C) 2005-2008 NTT DATA CORPORATION
+ *
+ * Version: 1.6.0 2008/04/01
+ *
+ */
+
+#include <linux/ccs_common.h>
+#include <linux/tomoyo.h>
+#include <linux/realpath.h>
+
+/**
+ * cap_operation2name - Convert capability operation to capability message.
+ *
+ * @operation: Type of operation.
+ *
+ * Returns the name of capability.
+ */
+static const char *cap_operation2name(const u8 operation)
+{
+ static const char *capability_name[TOMOYO_MAX_CAPABILITY_INDEX] = {
+ [TOMOYO_INET_STREAM_SOCKET_CREATE] =
+ "socket(PF_INET, SOCK_STREAM)",
+ [TOMOYO_INET_STREAM_SOCKET_LISTEN] =
+ "listen(PF_INET, SOCK_STREAM)",
+ [TOMOYO_INET_STREAM_SOCKET_CONNECT] =
+ "connect(PF_INET, SOCK_STREAM)",
+ [TOMOYO_USE_INET_DGRAM_SOCKET] =
+ "socket(PF_INET, SOCK_DGRAM)",
+ [TOMOYO_USE_INET_RAW_SOCKET] =
+ "socket(PF_INET, SOCK_RAW)",
+ [TOMOYO_USE_ROUTE_SOCKET] = "socket(PF_ROUTE)",
+ [TOMOYO_USE_PACKET_SOCKET] = "socket(PF_PACKET)",
+ [TOMOYO_SYS_MOUNT] = "sys_mount()",
+ [TOMOYO_SYS_UMOUNT] = "sys_umount()",
+ [TOMOYO_SYS_REBOOT] = "sys_reboot()",
+ [TOMOYO_SYS_CHROOT] = "sys_chroot()",
+ [TOMOYO_SYS_KILL] = "sys_kill()",
+ [TOMOYO_SYS_VHANGUP] = "sys_vhangup()",
+ [TOMOYO_SYS_SETTIME] = "sys_settimeofday()",
+ [TOMOYO_SYS_NICE] = "sys_nice()",
+ [TOMOYO_SYS_SETHOSTNAME] = "sys_sethostname()",
+ [TOMOYO_USE_KERNEL_MODULE] = "kernel_module",
+ [TOMOYO_CREATE_FIFO] = "mknod(FIFO)",
+ [TOMOYO_CREATE_BLOCK_DEV] = "mknod(BDEV)",
+ [TOMOYO_CREATE_CHAR_DEV] = "mknod(CDEV)",
+ [TOMOYO_CREATE_UNIX_SOCKET] = "mknod(SOCKET)",
+ [TOMOYO_SYS_LINK] = "sys_link()",
+ [TOMOYO_SYS_SYMLINK] = "sys_symlink()",
+ [TOMOYO_SYS_RENAME] = "sys_rename()",
+ [TOMOYO_SYS_UNLINK] = "sys_unlink()",
+ [TOMOYO_SYS_CHMOD] = "sys_chmod()",
+ [TOMOYO_SYS_CHOWN] = "sys_chown()",
+ [TOMOYO_SYS_IOCTL] = "sys_ioctl()",
+ [TOMOYO_SYS_KEXEC_LOAD] = "sys_kexec_load()",
+ [TOMOYO_SYS_PIVOT_ROOT] = "sys_pivot_root()",
+ [TOMOYO_SYS_PTRACE] = "sys_ptrace()",
+ };
+ if (operation < TOMOYO_MAX_CAPABILITY_INDEX)
+ return capability_name[operation];
+ return NULL;
+}
+
+/**
+ * audit_capability_log - Audit capability log.
+ *
+ * @operation: Type of operation.
+ * @is_granted: True if this is a granted log.
+ * @profile: Profile number used.
+ * @mode: Access control mode used.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int audit_capability_log(const u8 operation, const bool is_granted,
+ const u8 profile, const u8 mode)
+{
+ char *buf;
+ int len = 64;
+ int len2;
+ if (ccs_can_save_audit_log(is_granted) < 0)
+ return -ENOMEM;
+ buf = ccs_init_audit_log(&len, profile, mode, NULL);
+ if (!buf)
+ return -ENOMEM;
+ len2 = strlen(buf);
+ snprintf(buf + len2, len - len2 - 1, KEYWORD_ALLOW_CAPABILITY "%s\n",
+ ccs_cap2keyword(operation));
+ return ccs_write_audit_log(buf, is_granted);
+}
+
+/**
+ * update_capability_acl - Update "struct capability_acl_record" list.
+ *
+ * @operation: Type of operation.
+ * @domain: Pointer to "struct domain_info".
+ * @condition: Pointer to "struct condition_list". May be NULL.
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int update_capability_acl(const u8 operation, struct domain_info *domain,
+ const struct condition_list *condition,
+ const bool is_delete)
+{
+ struct acl_info *ptr;
+ struct capability_acl_record *acl;
+ int error = -ENOMEM;
+ if (!domain)
+ return -EINVAL;
+ mutex_lock(&domain_acl_lock);
+ if (is_delete)
+ goto delete;
+ list1_for_each_entry(ptr, &domain->acl_info_list, list) {
+ if (ccs_acl_type1(ptr) != TYPE_CAPABILITY_ACL)
+ continue;
+ if (ccs_get_condition_part(ptr) != condition)
+ continue;
+ acl = container_of(ptr, struct capability_acl_record, head);
+ if (acl->operation != operation)
+ continue;
+ error = ccs_add_domain_acl(NULL, ptr);
+ goto out;
+ }
+ /* Not found. Append it to the tail. */
+ acl = ccs_alloc_acl_element(TYPE_CAPABILITY_ACL, condition);
+ if (!acl)
+ goto out;
+ acl->operation = operation;
+ error = ccs_add_domain_acl(domain, &acl->head);
+ goto out;
+ delete:
+ error = -ENOENT;
+ list1_for_each_entry(ptr, &domain->acl_info_list, list) {
+ if (ccs_acl_type2(ptr) != TYPE_CAPABILITY_ACL)
+ continue;
+ if (ccs_get_condition_part(ptr) != condition)
+ continue;
+ acl = container_of(ptr, struct capability_acl_record, head);
+ if (acl->operation != operation)
+ continue;
+ error = ccs_del_domain_acl(ptr);
+ break;
+ }
+ out:
+ mutex_unlock(&domain_acl_lock);
+ return error;
+}
+
+/**
+ * ccs_capable - Check permission for capability.
+ *
+ * @operation: Type of operation.
+ *
+ * Returns true on success, false otherwise.
+ */
+bool ccs_capable(const u8 operation)
+{
+ struct domain_info * const domain = current->domain_info;
+ struct acl_info *ptr;
+ const u8 profile = current->domain_info->profile;
+ const u8 mode = ccs_check_capability_flags(operation);
+ const bool is_enforce = (mode == 3);
+ bool found = false;
+ if (!mode)
+ return true;
+ list1_for_each_entry(ptr, &domain->acl_info_list, list) {
+ struct capability_acl_record *acl;
+ if (ccs_acl_type2(ptr) != TYPE_CAPABILITY_ACL)
+ continue;
+ acl = container_of(ptr, struct capability_acl_record, head);
+ if (acl->operation != operation ||
+ !ccs_check_condition(ptr, NULL))
+ continue;
+ ccs_update_condition(ptr);
+ found = true;
+ break;
+ }
+ audit_capability_log(operation, found, profile, mode);
+ if (found)
+ return true;
+ if (ccs_verbose_mode())
+ printk(KERN_WARNING "TOMOYO-%s: %s denied for %s\n",
+ ccs_get_msg(is_enforce), cap_operation2name(operation),
+ ccs_get_last_name(domain));
+ if (is_enforce)
+ return !ccs_check_supervisor("%s\n"
+ KEYWORD_ALLOW_CAPABILITY "%s\n",
+ domain->domainname->name,
+ ccs_cap2keyword(operation));
+ if (mode == 1 && ccs_check_domain_quota(domain))
+ update_capability_acl(operation, domain, NULL, false);
+ return true;
+}
+EXPORT_SYMBOL(ccs_capable); /* for net/unix/af_unix.c */
+
+/**
+ * ccs_write_capability_policy - Write "struct capability_acl_record" list.
+ *
+ * @data: String to parse.
+ * @domain: Pointer to "struct domain_info".
+ * @condition: Pointer to "struct condition_list". May be NULL.
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int ccs_write_capability_policy(char *data, struct domain_info *domain,
+ const struct condition_list *condition,
+ const bool is_delete)
+{
+ u8 capability;
+ for (capability = 0; capability < TOMOYO_MAX_CAPABILITY_INDEX;
+ capability++) {
+ if (strcmp(data, ccs_cap2keyword(capability)))
+ continue;
+ return update_capability_acl(capability, domain, condition,
+ is_delete);
+ }
+ return -EINVAL;
+}
--


\
 
 \ /
  Last update: 2008-04-04 14:59    [from the cache]
©2003-2011 Jasper Spaans