acm_policy.c
来自「xen 3.2.2 源码」· C语言 代码 · 共 883 行 · 第 1/2 页
C
883 行
/**************************************************************** * acm_policy.c * * Copyright (C) 2005-2007 IBM Corporation * * Author: * Reiner Sailer <sailer@watson.ibm.com> * * Contributors: * Stefan Berger <stefanb@watson.ibm.com> * * 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 access control policy management for Xen. * This interface allows policy tools in authorized * domains to interact with the Xen access control module * */#include <xen/config.h>#include <xen/errno.h>#include <xen/types.h>#include <xen/lib.h>#include <xen/delay.h>#include <xen/sched.h>#include <xen/guest_access.h>#include <public/xen.h>#include <xsm/acm/acm_core.h>#include <public/xsm/acm_ops.h>#include <xsm/acm/acm_hooks.h>#include <xsm/acm/acm_endian.h>#include <asm/current.h>static int acm_check_deleted_ssidrefs(struct acm_sized_buffer *dels, struct acm_sized_buffer *errors);static void acm_doms_change_ssidref(ssidref_t (*translator) (const struct acm_ssid_domain *, const struct acm_sized_buffer *), struct acm_sized_buffer *translation_map);static void acm_doms_restore_ssidref(void);static ssidref_t oldssid_to_newssid(const struct acm_ssid_domain *, const struct acm_sized_buffer *map);intacm_set_policy(XEN_GUEST_HANDLE_64(void) buf, u32 buf_size){ u8 *policy_buffer = NULL; int ret = -EFAULT; if ( buf_size < sizeof(struct acm_policy_buffer) ) return -EFAULT; /* copy buffer from guest domain */ if ( (policy_buffer = xmalloc_array(u8, buf_size)) == NULL ) return -ENOMEM; if ( copy_from_guest(policy_buffer, buf, buf_size) ) { printk("%s: Error copying!\n",__func__); goto error_free; } ret = do_acm_set_policy(policy_buffer, buf_size, 0, NULL, NULL, NULL); error_free: xfree(policy_buffer); return ret;}/* * Update the policy of the running system by: * - deleting ssidrefs that are not in the new policy anymore * -> no running domain may use such an ssidref * - assign new ssidrefs to domains based on their old ssidrefs * */static int_acm_update_policy(void *buf, u32 buf_size, int is_bootpolicy, struct acm_policy_buffer *pol, struct acm_sized_buffer *deletions, struct acm_sized_buffer *ssidchanges, struct acm_sized_buffer *errors){ uint32_t offset, length; static int require_update = 0; write_lock(&acm_bin_pol_rwlock); if ( require_update != 0 && ( deletions == NULL || ssidchanges == NULL ) ) goto error_lock_free; require_update = 1; /* first some tests to check compatibility of new policy with current state of system/domains */ /* if ssidrefs are to be deleted, make sure no domain is using them */ if ( deletions != NULL ) if ( acm_check_deleted_ssidrefs(deletions, errors) ) goto error_lock_free_nossidchange; if ( (ssidchanges != NULL) && (ssidchanges->num_items > 0) ) /* assign all running domains new ssidrefs as requested */ acm_doms_change_ssidref(oldssid_to_newssid, ssidchanges); /* test primary policy data with the new ssidrefs */ offset = be32_to_cpu(pol->primary_buffer_offset); length = be32_to_cpu(pol->secondary_buffer_offset) - offset; if ( (offset + length) > buf_size || acm_primary_ops->test_binary_policy(buf + offset, length, is_bootpolicy, errors)) goto error_lock_free; /* test secondary policy data with the new ssidrefs */ offset = be32_to_cpu(pol->secondary_buffer_offset); length = be32_to_cpu(pol->len) - offset; if ( (offset + length) > buf_size || acm_secondary_ops->test_binary_policy(buf + offset, length, is_bootpolicy, errors)) goto error_lock_free; /* end of testing --- now real updates */ offset = be32_to_cpu(pol->policy_reference_offset); length = be32_to_cpu(pol->primary_buffer_offset) - offset; /* set label reference name */ if ( (offset + length) > buf_size || acm_set_policy_reference(buf + offset, length) ) goto error_lock_free; /* set primary policy data */ offset = be32_to_cpu(pol->primary_buffer_offset); length = be32_to_cpu(pol->secondary_buffer_offset) - offset; if ( acm_primary_ops->set_binary_policy(buf + offset, length) ) goto error_lock_free; /* set secondary policy data */ offset = be32_to_cpu(pol->secondary_buffer_offset); length = be32_to_cpu(pol->len) - offset; if ( acm_secondary_ops->set_binary_policy(buf + offset, length) ) goto error_lock_free; memcpy(&acm_bin_pol.xml_pol_version, &pol->xml_pol_version, sizeof(acm_bin_pol.xml_pol_version)); if ( acm_primary_ops->is_default_policy() && acm_secondary_ops->is_default_policy() ) require_update = 0; write_unlock(&acm_bin_pol_rwlock); return ACM_OK;error_lock_free: if ( (ssidchanges != NULL) && (ssidchanges->num_items > 0) ) { acm_doms_restore_ssidref(); }error_lock_free_nossidchange: do_chwall_init_state_curr(NULL); write_unlock(&acm_bin_pol_rwlock); return -EFAULT;}intdo_acm_set_policy(void *buf, u32 buf_size, int is_bootpolicy, struct acm_sized_buffer *deletions, struct acm_sized_buffer *ssidchanges, struct acm_sized_buffer *errors){ struct acm_policy_buffer *pol = (struct acm_policy_buffer *)buf; /* some sanity checking */ if ( (be32_to_cpu(pol->magic) != ACM_MAGIC) || (buf_size != be32_to_cpu(pol->len)) || (be32_to_cpu(pol->policy_version) != ACM_POLICY_VERSION) ) { printk("%s: ERROR in Magic, Version, or buf size.\n", __func__); goto error_free; } if ( acm_active_security_policy == ACM_POLICY_UNDEFINED ) { /* setup the policy with the boot policy */ if ( acm_init_binary_policy( (be32_to_cpu(pol->secondary_policy_code) << 4) | be32_to_cpu(pol->primary_policy_code)) ) { goto error_free; } acm_active_security_policy = (acm_bin_pol.secondary_policy_code << 4) | acm_bin_pol.primary_policy_code; } /* once acm_active_security_policy is set, it cannot be changed */ if ( (be32_to_cpu(pol->primary_policy_code) != acm_bin_pol.primary_policy_code) || (be32_to_cpu(pol->secondary_policy_code) != acm_bin_pol.secondary_policy_code) ) { printkd("%s: Wrong policy type in boot policy!\n", __func__); goto error_free; } return _acm_update_policy(buf, buf_size, is_bootpolicy, pol, deletions, ssidchanges, errors); error_free: printk("%s: Error setting policy.\n", __func__); return -EFAULT;}intacm_get_policy(XEN_GUEST_HANDLE_64(void) buf, u32 buf_size){ u8 *policy_buffer; int ret; struct acm_policy_buffer *bin_pol; if ( buf_size < sizeof(struct acm_policy_buffer) ) return -EFAULT; if ( (policy_buffer = xmalloc_array(u8, buf_size)) == NULL ) return -ENOMEM; read_lock(&acm_bin_pol_rwlock); bin_pol = (struct acm_policy_buffer *)policy_buffer; bin_pol->magic = cpu_to_be32(ACM_MAGIC); bin_pol->primary_policy_code = cpu_to_be32(acm_bin_pol.primary_policy_code); bin_pol->secondary_policy_code = cpu_to_be32(acm_bin_pol.secondary_policy_code); bin_pol->len = cpu_to_be32(sizeof(struct acm_policy_buffer)); bin_pol->policy_reference_offset = cpu_to_be32(be32_to_cpu(bin_pol->len)); bin_pol->primary_buffer_offset = cpu_to_be32(be32_to_cpu(bin_pol->len)); bin_pol->secondary_buffer_offset = cpu_to_be32(be32_to_cpu(bin_pol->len)); memcpy(&bin_pol->xml_pol_version, &acm_bin_pol.xml_pol_version, sizeof(struct acm_policy_version)); ret = acm_dump_policy_reference( policy_buffer + be32_to_cpu(bin_pol->policy_reference_offset), buf_size - be32_to_cpu(bin_pol->policy_reference_offset)); if ( ret < 0 ) goto error_free_unlock; bin_pol->len = cpu_to_be32(be32_to_cpu(bin_pol->len) + ret); bin_pol->primary_buffer_offset = cpu_to_be32(be32_to_cpu(bin_pol->len)); ret = acm_primary_ops->dump_binary_policy( policy_buffer + be32_to_cpu(bin_pol->primary_buffer_offset), buf_size - be32_to_cpu(bin_pol->primary_buffer_offset)); if ( ret < 0 ) goto error_free_unlock; bin_pol->len = cpu_to_be32(be32_to_cpu(bin_pol->len) + ret); bin_pol->secondary_buffer_offset = cpu_to_be32(be32_to_cpu(bin_pol->len)); ret = acm_secondary_ops->dump_binary_policy( policy_buffer + be32_to_cpu(bin_pol->secondary_buffer_offset), buf_size - be32_to_cpu(bin_pol->secondary_buffer_offset)); if ( ret < 0 ) goto error_free_unlock; bin_pol->len = cpu_to_be32(be32_to_cpu(bin_pol->len) + ret); if ( copy_to_guest(buf, policy_buffer, be32_to_cpu(bin_pol->len)) ) goto error_free_unlock; read_unlock(&acm_bin_pol_rwlock); xfree(policy_buffer); return ACM_OK; error_free_unlock: read_unlock(&acm_bin_pol_rwlock); printk("%s: Error getting policy.\n", __func__); xfree(policy_buffer); return -EFAULT;}intacm_dump_statistics(XEN_GUEST_HANDLE_64(void) buf, u16 buf_size){ /* send stats to user space */ u8 *stats_buffer; int len1, len2; struct acm_stats_buffer acm_stats; if ( (stats_buffer = xmalloc_array(u8, buf_size)) == NULL ) return -ENOMEM; read_lock(&acm_bin_pol_rwlock); len1 = acm_primary_ops->dump_statistics( stats_buffer + sizeof(struct acm_stats_buffer), buf_size - sizeof(struct acm_stats_buffer)); if ( len1 < 0 ) goto error_lock_free; len2 = acm_secondary_ops->dump_statistics( stats_buffer + sizeof(struct acm_stats_buffer) + len1, buf_size - sizeof(struct acm_stats_buffer) - len1); if ( len2 < 0 ) goto error_lock_free; acm_stats.magic = cpu_to_be32(ACM_MAGIC); acm_stats.primary_policy_code = cpu_to_be32(acm_bin_pol.primary_policy_code); acm_stats.secondary_policy_code = cpu_to_be32(acm_bin_pol.secondary_policy_code); acm_stats.primary_stats_offset = cpu_to_be32(sizeof(struct acm_stats_buffer)); acm_stats.secondary_stats_offset = cpu_to_be32(sizeof(struct acm_stats_buffer) + len1); acm_stats.len = cpu_to_be32(sizeof(struct acm_stats_buffer) + len1 + len2); memcpy(stats_buffer, &acm_stats, sizeof(struct acm_stats_buffer)); if ( copy_to_guest(buf, stats_buffer, sizeof(struct acm_stats_buffer) + len1 + len2) ) goto error_lock_free; read_unlock(&acm_bin_pol_rwlock); xfree(stats_buffer); return ACM_OK; error_lock_free: read_unlock(&acm_bin_pol_rwlock); xfree(stats_buffer); return -EFAULT;}intacm_get_ssid(ssidref_t ssidref, XEN_GUEST_HANDLE_64(void) buf, u16 buf_size){ /* send stats to user space */ u8 *ssid_buffer; int ret; struct acm_ssid_buffer *acm_ssid; if ( buf_size < sizeof(struct acm_ssid_buffer) ) return -EFAULT; if ( (ssid_buffer = xmalloc_array(u8, buf_size)) == NULL ) return -ENOMEM; read_lock(&acm_bin_pol_rwlock); acm_ssid = (struct acm_ssid_buffer *)ssid_buffer; acm_ssid->len = sizeof(struct acm_ssid_buffer); acm_ssid->ssidref = ssidref; acm_ssid->primary_policy_code = acm_bin_pol.primary_policy_code; acm_ssid->secondary_policy_code = acm_bin_pol.secondary_policy_code; acm_ssid->policy_reference_offset = acm_ssid->len; ret = acm_dump_policy_reference( ssid_buffer + acm_ssid->policy_reference_offset, buf_size - acm_ssid->policy_reference_offset); if ( ret < 0 ) goto error_free_unlock; acm_ssid->len += ret; acm_ssid->primary_types_offset = acm_ssid->len; /* ret >= 0 --> ret == max_types */ ret = acm_primary_ops->dump_ssid_types( ACM_PRIMARY(ssidref), ssid_buffer + acm_ssid->primary_types_offset, buf_size - acm_ssid->primary_types_offset); if ( ret < 0 ) goto error_free_unlock; acm_ssid->len += ret; acm_ssid->primary_max_types = ret; acm_ssid->secondary_types_offset = acm_ssid->len; ret = acm_secondary_ops->dump_ssid_types( ACM_SECONDARY(ssidref), ssid_buffer + acm_ssid->secondary_types_offset, buf_size - acm_ssid->secondary_types_offset); if ( ret < 0 ) goto error_free_unlock; acm_ssid->len += ret; acm_ssid->secondary_max_types = ret; if ( copy_to_guest(buf, ssid_buffer, acm_ssid->len) ) goto error_free_unlock; read_unlock(&acm_bin_pol_rwlock); xfree(ssid_buffer); return ACM_OK; error_free_unlock: read_unlock(&acm_bin_pol_rwlock); printk("%s: Error getting ssid.\n", __func__); xfree(ssid_buffer); return -ENOMEM;}intacm_get_decision(ssidref_t ssidref1, ssidref_t ssidref2, u32 hook){ int ret = ACM_ACCESS_DENIED; read_lock(&acm_bin_pol_rwlock); switch ( hook ) { case ACMHOOK_sharing: /* Sharing hook restricts access in STE policy only */ ret = acm_sharing(ssidref1, ssidref2);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?