⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 acm_simple_type_enforcement_hooks.c

📁 xen虚拟机源代码安装包
💻 C
📖 第 1 页 / 共 2 页
字号:
/**************************************************************** * acm_simple_type_enforcement_hooks.c *  * Copyright (C) 2005 IBM Corporation * * Author: * Reiner Sailer <sailer@watson.ibm.com> * * Contributors: * Stefan Berger <stefanb@watson.ibm.com> *         support for network order binary policies * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, version 2 of the * License. * * sHype Simple Type Enforcement for Xen *     STE allows to control which domains can setup sharing *     (eventchannels right now) with which other domains. Hooks *     are defined and called throughout Xen when domains bind to *     shared resources (setup eventchannels) and a domain is allowed *     to setup sharing with another domain if and only if both domains *     share at least on common type. * */#include <xen/lib.h>#include <asm/types.h>#include <asm/current.h>#include <asm/atomic.h>#include <xsm/acm/acm_hooks.h>#include <xsm/acm/acm_endian.h>#include <xsm/acm/acm_core.h>ssidref_t dom0_ste_ssidref = 0x0001;/* local cache structures for STE policy */struct ste_binary_policy ste_bin_pol;static inline int have_common_type (ssidref_t ref1, ssidref_t ref2){    int i;    if ( ref1 >= 0 && ref1 < ste_bin_pol.max_ssidrefs &&         ref2 >= 0 && ref2 < ste_bin_pol.max_ssidrefs )    {        for( i = 0; i< ste_bin_pol.max_types; i++ )            if ( ste_bin_pol.ssidrefs[ref1 * ste_bin_pol.max_types + i] &&                 ste_bin_pol.ssidrefs[ref2 * ste_bin_pol.max_types + i])            {                printkd("%s: common type #%02x.\n", __func__, i);                return 1;            }    }    return 0;}static inline int is_superset(ssidref_t ref1, ssidref_t ref2){    int i;    if ( ref1 >= 0 && ref1 < ste_bin_pol.max_ssidrefs &&         ref2 >= 0 && ref2 < ste_bin_pol.max_ssidrefs )    {        for( i = 0; i< ste_bin_pol.max_types; i++ )            if (!ste_bin_pol.ssidrefs[ref1 * ste_bin_pol.max_types + i] &&                 ste_bin_pol.ssidrefs[ref2 * ste_bin_pol.max_types + i])            {                return 0;            }    } else {        return 0;    }    return 1;}/* Helper function: return = (subj and obj share a common type) */static int share_common_type(struct domain *subj, struct domain *obj){    ssidref_t ref_s, ref_o;    int ret;    if ( (subj == NULL) || (obj == NULL) ||         (subj->ssid == NULL) || (obj->ssid == NULL) )        return 0;    read_lock(&acm_bin_pol_rwlock);    /* lookup the policy-local ssids */    ref_s = ((struct ste_ssid *)(GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,                       (struct acm_ssid_domain *)subj->ssid)))->ste_ssidref;    ref_o = ((struct ste_ssid *)(GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,                        (struct acm_ssid_domain *)obj->ssid)))->ste_ssidref;    /* check whether subj and obj share a common ste type */    ret = have_common_type(ref_s, ref_o);    read_unlock(&acm_bin_pol_rwlock);    return ret;}/* * Initializing STE policy (will be filled by policy partition * using setpolicy command) */int acm_init_ste_policy(void){    /* minimal startup policy; policy write-locked already */    ste_bin_pol.max_types = 2;    ste_bin_pol.max_ssidrefs = 1 + dom0_ste_ssidref;    ste_bin_pol.ssidrefs =            (domaintype_t *)xmalloc_array(domaintype_t,                                          ste_bin_pol.max_types *                                          ste_bin_pol.max_ssidrefs);    if (ste_bin_pol.ssidrefs == NULL)        return ACM_INIT_SSID_ERROR;    memset(ste_bin_pol.ssidrefs, 0, sizeof(domaintype_t) *                                    ste_bin_pol.max_types *                                    ste_bin_pol.max_ssidrefs);    /* initialize state so that dom0 can start up and communicate with itself */    ste_bin_pol.ssidrefs[ste_bin_pol.max_types - 1 ] = 1;    ste_bin_pol.ssidrefs[ste_bin_pol.max_types * dom0_ste_ssidref] = 1;    ste_bin_pol.ssidrefs[ste_bin_pol.max_types * dom0_ste_ssidref + 1] = 1;    /* init stats */    atomic_set(&(ste_bin_pol.ec_eval_count), 0);    atomic_set(&(ste_bin_pol.ec_denied_count), 0);    atomic_set(&(ste_bin_pol.ec_cachehit_count), 0);    atomic_set(&(ste_bin_pol.gt_eval_count), 0);    atomic_set(&(ste_bin_pol.gt_denied_count), 0);    atomic_set(&(ste_bin_pol.gt_cachehit_count), 0);    return ACM_OK;}/* ste initialization function hooks */static intste_init_domain_ssid(void **ste_ssid, ssidref_t ssidref){    int i;    struct ste_ssid *ste_ssidp = xmalloc(struct ste_ssid);    if ( ste_ssidp == NULL )        return ACM_INIT_SSID_ERROR;    /* get policy-local ssid reference */    ste_ssidp->ste_ssidref = GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,                                         ssidref);    if ( (ste_ssidp->ste_ssidref >= ste_bin_pol.max_ssidrefs) )    {        printkd("%s: ERROR ste_ssidref (%x) undefined or unset (0).\n",                __func__, ste_ssidp->ste_ssidref);        xfree(ste_ssidp);        return ACM_INIT_SSID_ERROR;    }    /* clean ste cache */    for ( i = 0; i < ACM_TE_CACHE_SIZE; i++ )        ste_ssidp->ste_cache[i].valid = ACM_STE_free;    (*ste_ssid) = ste_ssidp;    printkd("%s: determined ste_ssidref to %x.\n",             __func__, ste_ssidp->ste_ssidref);    return ACM_OK;}static voidste_free_domain_ssid(void *ste_ssid){    xfree(ste_ssid);    return;}/* dump type enforcement cache; policy read-locked already */static int ste_dump_policy(u8 *buf, u32 buf_size) {    struct acm_ste_policy_buffer *ste_buf =                                  (struct acm_ste_policy_buffer *)buf;    int ret = 0;    if ( buf_size < sizeof(struct acm_ste_policy_buffer) )        return -EINVAL;    ste_buf->ste_max_types = cpu_to_be32(ste_bin_pol.max_types);    ste_buf->ste_max_ssidrefs = cpu_to_be32(ste_bin_pol.max_ssidrefs);    ste_buf->policy_code = cpu_to_be32(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);    ste_buf->ste_ssid_offset =                           cpu_to_be32(sizeof(struct acm_ste_policy_buffer));    ret = be32_to_cpu(ste_buf->ste_ssid_offset) +        sizeof(domaintype_t)*ste_bin_pol.max_ssidrefs*ste_bin_pol.max_types;    ret = (ret + 7) & ~7;    if (buf_size < ret)        return -EINVAL;    /* now copy buffer over */    arrcpy(buf + be32_to_cpu(ste_buf->ste_ssid_offset),           ste_bin_pol.ssidrefs,           sizeof(domaintype_t),           ste_bin_pol.max_ssidrefs*ste_bin_pol.max_types);    return ret;}/* * ste_init_state is called when a policy is changed to detect violations * (return != 0). from a security point of view, we simulate that all * running domains are re-started and all sharing decisions are replayed * to detect violations or current sharing behavior (right now: * event_channels, future: also grant_tables) */ static intste_init_state(struct acm_sized_buffer *errors){    int violation = 1;    struct ste_ssid *ste_ssid, *ste_rssid;    ssidref_t ste_ssidref, ste_rssidref;    struct domain *d, *rdom;    domid_t rdomid;    struct active_grant_entry *act;    int port, i;    rcu_read_lock(&domlist_read_lock);    read_lock(&ssid_list_rwlock);    /* go through all domains and adjust policy as if this domain was       started now */    for_each_domain ( d )    {        struct evtchn *ports;        unsigned int bucket;        ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,                              (struct acm_ssid_domain *)d->ssid);        ste_ssidref = ste_ssid->ste_ssidref;        traceprintk("%s: validating policy for eventch domain %x (ste-Ref=%x).\n",                    __func__, d->domain_id, ste_ssidref);        /* a) check for event channel conflicts */        for ( bucket = 0; bucket < NR_EVTCHN_BUCKETS; bucket++ )        {            spin_lock(&d->evtchn_lock);            ports = d->evtchn[bucket];            if ( ports == NULL)            {                spin_unlock(&d->evtchn_lock);                break;            }            for ( port = 0; port < EVTCHNS_PER_BUCKET; port++ )            {                if ( ports[port].state == ECS_INTERDOMAIN )                {                    rdom = ports[port].u.interdomain.remote_dom;                    rdomid = rdom->domain_id;                } else {                    continue; /* port unused */                }                /* rdom now has remote domain */                ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,                                      (struct acm_ssid_domain *)(rdom->ssid));                ste_rssidref = ste_rssid->ste_ssidref;                traceprintk("%s: eventch: domain %x (ssidref %x) --> "                            "domain %x (rssidref %x) used (port %x).\n",                            __func__, d->domain_id, ste_ssidref,                            rdom->domain_id, ste_rssidref, port);                /* check whether on subj->ssid, obj->ssid share a common type*/                if ( ! have_common_type(ste_ssidref, ste_rssidref) )                {                    printkd("%s: Policy violation in event channel domain "                            "%x -> domain %x.\n",                            __func__, d->domain_id, rdomid);                    spin_unlock(&d->evtchn_lock);                    acm_array_append_tuple(errors,                                           ACM_EVTCHN_SHARING_VIOLATION,                                           d->domain_id << 16 | rdomid);                    goto out;                }            }            spin_unlock(&d->evtchn_lock);        }         /* b) check for grant table conflicts on shared pages */        spin_lock(&d->grant_table->lock);        for ( i = 0; i < nr_active_grant_frames(d->grant_table); i++ )        {#define APP (PAGE_SIZE / sizeof(struct active_grant_entry))            act = &d->grant_table->active[i/APP][i%APP];            if ( act->pin != 0 ) {                printkd("%s: grant dom (%hu) SHARED (%d) pin (%d)  "                        "dom:(%hu) frame:(%lx)\n",                        __func__, d->domain_id, i, act->pin,                        act->domid, (unsigned long)act->frame);                rdomid = act->domid;                if ( (rdom = rcu_lock_domain_by_id(rdomid)) == NULL )                {                    spin_unlock(&d->grant_table->lock);                    printkd("%s: domain not found ERROR!\n", __func__);                    acm_array_append_tuple(errors,                                           ACM_DOMAIN_LOOKUP,                                           rdomid);                    goto out;                }                /* rdom now has remote domain */                ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,                                      (struct acm_ssid_domain *)(rdom->ssid));                ste_rssidref = ste_rssid->ste_ssidref;                rcu_unlock_domain(rdom);                if ( ! have_common_type(ste_ssidref, ste_rssidref) )                {                    spin_unlock(&d->grant_table->lock);                    printkd("%s: Policy violation in grant table "                            "sharing domain %x -> domain %x.\n",                            __func__, d->domain_id, rdomid);                    acm_array_append_tuple(errors,                                           ACM_GNTTAB_SHARING_VIOLATION,                                           d->domain_id << 16 | rdomid);                    goto out;                }            }        }        spin_unlock(&d->grant_table->lock);    }    violation = 0; out:    read_unlock(&ssid_list_rwlock);    rcu_read_unlock(&domlist_read_lock);    return violation;    /*       returning "violation != 0" means that existing sharing between domains       would not have been allowed if the new policy had been enforced before       the sharing; for ste, this means that there are at least 2 domains       that have established sharing through event-channels or grant-tables       but these two domains don't have no longer a common type in their       typesets referenced by their ssidrefs      */}/* * Call ste_init_state with the current policy. */intdo_ste_init_state_curr(struct acm_sized_buffer *errors){    return ste_init_state(errors);}/* set new policy; policy write-locked already */static int_ste_update_policy(u8 *buf, u32 buf_size, int test_only,                   struct acm_sized_buffer *errors){    int rc = -EFAULT;    struct acm_ste_policy_buffer *ste_buf =                                 (struct acm_ste_policy_buffer *)buf;    void *ssidrefsbuf;    struct ste_ssid *ste_ssid;    struct acm_ssid_domain *rawssid;    int i;    /* 1. create and copy-in new ssidrefs buffer */    ssidrefsbuf = xmalloc_array(u8,                                sizeof(domaintype_t) *                                 ste_buf->ste_max_types *                                 ste_buf->ste_max_ssidrefs);    if ( ssidrefsbuf == NULL ) {        return -ENOMEM;    }    if ( ste_buf->ste_ssid_offset +         sizeof(domaintype_t) *         ste_buf->ste_max_ssidrefs *         ste_buf->ste_max_types > buf_size )        goto error_free;    arrcpy(ssidrefsbuf,            buf + ste_buf->ste_ssid_offset,           sizeof(domaintype_t),           ste_buf->ste_max_ssidrefs*ste_buf->ste_max_types);    /*     * 3. in test mode: re-calculate sharing decisions based on running     *    domains; this can fail if new policy is conflicting with sharing     *    of running domains     *    now: reject violating new policy; future: adjust sharing through     *    revoking sharing     */    if ( test_only ) {        /* temporarily replace old policy with new one for the testing */        struct ste_binary_policy orig_ste_bin_pol = ste_bin_pol;        ste_bin_pol.max_types = ste_buf->ste_max_types;        ste_bin_pol.max_ssidrefs = ste_buf->ste_max_ssidrefs;        ste_bin_pol.ssidrefs = (domaintype_t *)ssidrefsbuf;        if ( ste_init_state(errors) )        {            /* new policy conflicts with sharing of running domains */            printk("%s: New policy conflicts with running domains. "                   "Policy load aborted.\n", __func__);        } else {            rc = ACM_OK;        }        /* revert changes, no matter whether testing was successful or not */        ste_bin_pol = orig_ste_bin_pol;        goto error_free;    }    /* 3. replace old policy (activate new policy) */    ste_bin_pol.max_types = ste_buf->ste_max_types;    ste_bin_pol.max_ssidrefs = ste_buf->ste_max_ssidrefs;    xfree(ste_bin_pol.ssidrefs);    ste_bin_pol.ssidrefs = (domaintype_t *)ssidrefsbuf;    /* clear all ste caches */    read_lock(&ssid_list_rwlock);    for_each_acmssid( rawssid )    {        ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, rawssid);        for ( i = 0; i < ACM_TE_CACHE_SIZE; i++ )            ste_ssid->ste_cache[i].valid = ACM_STE_free;    }    read_unlock(&ssid_list_rwlock);    return ACM_OK; error_free:    if ( !test_only )        printk("%s: ERROR setting policy.\n", __func__);    xfree(ssidrefsbuf);    return rc;}static intste_test_policy(u8 *buf, u32 buf_size, int is_bootpolicy,                struct acm_sized_buffer *errors){    struct acm_ste_policy_buffer *ste_buf =             (struct acm_ste_policy_buffer *)buf;    if ( buf_size < sizeof(struct acm_ste_policy_buffer) )        return -EINVAL;    /* Convert endianess of policy */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -