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    [W:4.054 / U:0.128 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site