acm_policy.c

来自「xen 3.2.2 源码」· C语言 代码 · 共 883 行 · 第 1/2 页

C
883
字号
        break;    case ACMHOOK_authorization:        ret = acm_authorization(ssidref1, ssidref2);        break;    default:        /* deny */        break;    }    read_unlock(&acm_bin_pol_rwlock);    printkd("%s: ssid1=%x, ssid2=%x, decision=%s.\n",            __func__, ssidref1, ssidref2,            (ret == ACM_ACCESS_PERMITTED) ? "GRANTED" : "DENIED");    return ret;}/*   Check if an ssidref of the current policy type is being used by any   domain. */static intacm_check_used_ssidref(uint32_t policy_type, uint32_t search_ssidref,                       struct acm_sized_buffer *errors){    int rc = 0;    struct acm_ssid_domain *rawssid;    read_lock(&ssid_list_rwlock);    for_each_acmssid( rawssid )    {        ssidref_t ssidref;        void *s = GET_SSIDP(policy_type, rawssid);        if ( policy_type == ACM_CHINESE_WALL_POLICY )        {            ssidref = ((struct chwall_ssid *)s)->chwall_ssidref;        } else {            ssidref = ((struct ste_ssid *)s)->ste_ssidref;        }        gdprintk(XENLOG_INFO,"domid=%d: search ssidref=%d, ssidref=%d\n",                 rawssid->domainid,search_ssidref,ssidref);        if ( ssidref == search_ssidref )        {            /* one is enough */            acm_array_append_tuple(errors, ACM_SSIDREF_IN_USE, search_ssidref);            rc = 1;            break;        }    }    read_unlock(&ssid_list_rwlock);    return rc;}/* * Translate a current ssidref into its future representation under * the new policy. * The map provides translation of ssidrefs from old to new in tuples * of (old ssidref, new ssidref). */static ssidref_toldssid_to_newssid(const struct acm_ssid_domain *rawssid,                   const struct acm_sized_buffer *map){    uint i;    if ( rawssid != NULL )    {        ssidref_t ssid = rawssid->ssidref & 0xffff;        for ( i = 0; i + 1 < map->num_items; i += 2 )        {            if ( map->array[i] == ssid )            {                return (map->array[i+1] << 16 | map->array[i+1]);            }        }    }    return ACM_INVALID_SSIDREF;}/* * Assign an ssidref to the CHWALL policy component of the domain */static voidacm_pri_policy_assign_ssidref(struct acm_ssid_domain *rawssid,                              ssidref_t new_ssid){    struct chwall_ssid *chwall = (struct chwall_ssid *)rawssid->primary_ssid;    chwall->chwall_ssidref = new_ssid;}/* * Assign an ssidref to the STE policy component of the domain */static voidacm_sec_policy_assign_ssidref(struct acm_ssid_domain *rawssid,                              ssidref_t new_ssid){    struct ste_ssid *ste = (struct ste_ssid *)rawssid->secondary_ssid;    ste->ste_ssidref = new_ssid;}/*   Change the ssidrefs on each domain using a passed translation function; */static voidacm_doms_change_ssidref(ssidref_t (*translator_fn)                          (const struct acm_ssid_domain *,                           const struct acm_sized_buffer *),                        struct acm_sized_buffer *translation_map){    struct acm_ssid_domain *rawssid;    write_lock(&ssid_list_rwlock);    for_each_acmssid( rawssid )    {        ssidref_t new_ssid;        rawssid->old_ssidref = rawssid->ssidref;        new_ssid = translator_fn(rawssid, translation_map);        if ( new_ssid == ACM_INVALID_SSIDREF )        {            /* means no mapping found, so no change -- old = new */            continue;        }        acm_pri_policy_assign_ssidref(rawssid, ACM_PRIMARY  (new_ssid) );        acm_sec_policy_assign_ssidref(rawssid, ACM_SECONDARY(new_ssid) );        rawssid->ssidref = new_ssid;    }    write_unlock(&ssid_list_rwlock);}/* * Restore the previous ssidref values on all domains */static voidacm_doms_restore_ssidref(void){    struct acm_ssid_domain *rawssid;    write_lock(&ssid_list_rwlock);    for_each_acmssid( rawssid )    {        ssidref_t old_ssid;        if ( rawssid->old_ssidref == rawssid->ssidref )            continue;        old_ssid = rawssid->old_ssidref & 0xffff;        rawssid->ssidref = rawssid->old_ssidref;        acm_pri_policy_assign_ssidref(rawssid, old_ssid);        acm_sec_policy_assign_ssidref(rawssid, old_ssid);    }    write_unlock(&ssid_list_rwlock);}/*   Check the list of domains whether either one of them uses a   to-be-deleted ssidref. */static intacm_check_deleted_ssidrefs(struct acm_sized_buffer *dels,                           struct acm_sized_buffer *errors){    int rc = 0;    uint idx;    /* check for running domains that should not be there anymore */    for ( idx = 0; idx < dels->num_items; idx++ )    {        if ( acm_check_used_ssidref(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,                                    dels->array[idx],                                    errors) > 0 ||             acm_check_used_ssidref(ACM_CHINESE_WALL_POLICY,                                    dels->array[idx],                                    errors) > 0)        {            rc = ACM_ERROR;            break;        }    }    return rc;}/* * Change the policy of the system. */intacm_change_policy(struct acm_change_policy *chgpolicy){    int rc = 0;    u8 *binpolicy = NULL;    struct acm_sized_buffer dels =    {        .array = NULL,    };    struct acm_sized_buffer ssidmap =    {        .array = NULL,    };    struct acm_sized_buffer errors =    {        .array = NULL,    };    gdprintk(XENLOG_INFO, "change policy operation\n");    if ( (chgpolicy->delarray_size > 4096) ||         (chgpolicy->chgarray_size > 4096) ||         (chgpolicy->errarray_size > 4096))    {        return ACM_ERROR;    }    dels.num_items = chgpolicy->delarray_size / sizeof(uint32_t);    if ( dels.num_items > 0 )    {        dels.array = xmalloc_array(uint32_t, dels.num_items);        if ( dels.array == NULL )        {            rc = -ENOMEM;            goto acm_chg_policy_exit;        }    }    ssidmap.num_items = chgpolicy->chgarray_size / sizeof(uint32_t);    if ( ssidmap.num_items > 0 )    {        ssidmap.array = xmalloc_array(uint32_t, ssidmap.num_items);        if ( ssidmap.array == NULL )        {            rc = -ENOMEM;            goto acm_chg_policy_exit;        }    }    errors.num_items = chgpolicy->errarray_size / sizeof(uint32_t);    if ( errors.num_items > 0 )    {        errors.array = xmalloc_array(uint32_t, errors.num_items);        if ( errors.array == NULL )        {            rc = -ENOMEM;            goto acm_chg_policy_exit;        }        memset(errors.array, 0x0, sizeof(uint32_t) * errors.num_items);    }    binpolicy = xmalloc_array(u8,                              chgpolicy->policy_pushcache_size);    if ( binpolicy == NULL )    {        rc = -ENOMEM;        goto acm_chg_policy_exit;    }    if ( copy_from_guest(dels.array,                         chgpolicy->del_array,                         dels.num_items) ||         copy_from_guest(ssidmap.array,                         chgpolicy->chg_array,                         ssidmap.num_items) ||         copy_from_guest(binpolicy,                         chgpolicy->policy_pushcache,                         chgpolicy->policy_pushcache_size ))    {        rc = -EFAULT;        goto acm_chg_policy_exit;    }    rc = do_acm_set_policy(binpolicy,                           chgpolicy->policy_pushcache_size,                           0,                           &dels, &ssidmap, &errors);    if ( (errors.num_items > 0) &&         copy_to_guest(chgpolicy->err_array,                       errors.array,                       errors.num_items ) )    {        rc = -EFAULT;        goto acm_chg_policy_exit;    }acm_chg_policy_exit:    xfree(dels.array);    xfree(ssidmap.array);    xfree(errors.array);    xfree(binpolicy);    return rc;}/* * Lookup the new ssidref given the domain's id. * The translation map provides a list of tuples in the format * (domid, new ssidref). */static ssidref_tdomid_to_newssid(const struct acm_ssid_domain *rawssid,                 const struct acm_sized_buffer *map){    domid_t domid = rawssid->domainid;    uint i;    for ( i = 0; (i+1) < map->num_items; i += 2 )    {        if ( map->array[i] == domid )            return (ssidref_t)map->array[i+1];    }    return ACM_INVALID_SSIDREF;}intdo_acm_relabel_doms(struct acm_sized_buffer *relabel_map,                    struct acm_sized_buffer *errors){    int rc = 0, irc;    write_lock(&acm_bin_pol_rwlock);    acm_doms_change_ssidref(domid_to_newssid, relabel_map);    /* run tests; collect as much error info as possible */    irc =  do_chwall_init_state_curr(errors);    irc += do_ste_init_state_curr(errors);    if ( irc != 0 )    {        rc = -EFAULT;        goto acm_relabel_doms_lock_err_exit;    }    write_unlock(&acm_bin_pol_rwlock);    return rc;acm_relabel_doms_lock_err_exit:    /* revert the new ssidref assignment */    acm_doms_restore_ssidref();    do_chwall_init_state_curr(NULL);    write_unlock(&acm_bin_pol_rwlock);    return rc;}intacm_relabel_domains(struct acm_relabel_doms *relabel){    int rc = ACM_OK;    struct acm_sized_buffer relabels =    {        .array = NULL,    };    struct acm_sized_buffer errors =    {        .array = NULL,    };    if ( relabel->relabel_map_size > 4096 )    {        return ACM_ERROR;    }    relabels.num_items = relabel->relabel_map_size / sizeof(uint32_t);    if ( relabels.num_items > 0 )    {        relabels.array = xmalloc_array(uint32_t, relabels.num_items);        if ( relabels.array == NULL )        {            rc = -ENOMEM;            goto acm_relabel_doms_exit;        }    }    errors.num_items = relabel->errarray_size / sizeof(uint32_t);    if ( errors.num_items > 0 )    {        errors.array = xmalloc_array(uint32_t, errors.num_items);        if ( errors.array == NULL )        {            rc = -ENOMEM;            goto acm_relabel_doms_exit;        }        memset(errors.array, 0x0, sizeof(uint32_t) * errors.num_items);    }    if ( copy_from_guest(relabels.array,                         relabel->relabel_map,                         relabels.num_items) )    {        rc = -EFAULT;        goto acm_relabel_doms_exit;    }    rc = do_acm_relabel_doms(&relabels, &errors);    if ( copy_to_guest(relabel->err_array,                       errors.array,                       errors.num_items ) )        rc = -EFAULT;acm_relabel_doms_exit:    xfree(relabels.array);    xfree(errors.array);    return rc;}/* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */

⌨️ 快捷键说明

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