diff options
author | kfraser@localhost.localdomain <kfraser@localhost.localdomain> | 2007-03-29 19:26:13 +0100 |
---|---|---|
committer | kfraser@localhost.localdomain <kfraser@localhost.localdomain> | 2007-03-29 19:26:13 +0100 |
commit | 7f6d8fe5c9edca501420059a857116e42cd409ee (patch) | |
tree | 675e369c9728c656bb291c3c7dbeed3504cd2e09 | |
parent | 61e7893dafdfa84717d362986c8328effd1a2320 (diff) | |
download | xen-7f6d8fe5c9edca501420059a857116e42cd409ee.tar.gz xen-7f6d8fe5c9edca501420059a857116e42cd409ee.tar.bz2 xen-7f6d8fe5c9edca501420059a857116e42cd409ee.zip |
acm: Provide the possibility to choose the VM label of domain-0 in the
kernel line in grub.conf. The format is
ssidref=<ssidref>:sHype:<policy name>:<vm label>. The name of the
policy specified here must be the same name as the in the policy
provided as a module during boot, otherwise the policy will not be
accepted and the system then starts without a policy. The user tool
for 'xm dumppolicy' has been adapted to show which entry in the binary
policy is used by domain-0.
Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
-rw-r--r-- | tools/security/secpol_tool.c | 59 | ||||
-rw-r--r-- | tools/security/secpol_xml2bin.c | 3 | ||||
-rw-r--r-- | xen/acm/acm_chinesewall_hooks.c | 13 | ||||
-rw-r--r-- | xen/acm/acm_core.c | 65 | ||||
-rw-r--r-- | xen/acm/acm_null_hooks.c | 2 | ||||
-rw-r--r-- | xen/acm/acm_policy.c | 10 | ||||
-rw-r--r-- | xen/acm/acm_simple_type_enforcement_hooks.c | 26 | ||||
-rw-r--r-- | xen/include/acm/acm_core.h | 9 | ||||
-rw-r--r-- | xen/include/acm/acm_hooks.h | 12 |
9 files changed, 163 insertions, 36 deletions
diff --git a/tools/security/secpol_tool.c b/tools/security/secpol_tool.c index 0b9c3e4acd..a4a782c754 100644 --- a/tools/security/secpol_tool.c +++ b/tools/security/secpol_tool.c @@ -57,7 +57,7 @@ void usage(char *progname) /*************************** DUMPS *******************************/ -void acm_dump_chinesewall_buffer(void *buf, int buflen) +void acm_dump_chinesewall_buffer(void *buf, int buflen, uint16_t chwall_ref) { struct acm_chwall_policy_buffer *cwbuf = @@ -91,6 +91,8 @@ void acm_dump_chinesewall_buffer(void *buf, int buflen) for (j = 0; j < ntohl(cwbuf->chwall_max_types); j++) printf("%02x ", ntohs(ssids[i * ntohl(cwbuf->chwall_max_types) + j])); + if (i == chwall_ref) + printf(" <-- Domain-0"); } printf("\n\nConfict Sets:\n"); conflicts = @@ -131,7 +133,7 @@ void acm_dump_chinesewall_buffer(void *buf, int buflen) } } -void acm_dump_ste_buffer(void *buf, int buflen) +void acm_dump_ste_buffer(void *buf, int buflen, uint16_t ste_ref) { struct acm_ste_policy_buffer *stebuf = @@ -158,11 +160,14 @@ void acm_dump_ste_buffer(void *buf, int buflen) for (j = 0; j < ntohl(stebuf->ste_max_types); j++) printf("%02x ", ntohs(ssids[i * ntohl(stebuf->ste_max_types) + j])); + if (i == ste_ref) + printf(" <-- Domain-0"); } printf("\n\n"); } -void acm_dump_policy_buffer(void *buf, int buflen) +void acm_dump_policy_buffer(void *buf, int buflen, + uint16_t chwall_ref, uint16_t ste_ref) { struct acm_policy_buffer *pol = (struct acm_policy_buffer *) buf; char *policy_reference_name = @@ -190,13 +195,15 @@ void acm_dump_policy_buffer(void *buf, int buflen) acm_dump_chinesewall_buffer(ALIGN8(buf + ntohl(pol->primary_buffer_offset)), ntohl(pol->len) - - ntohl(pol->primary_buffer_offset)); + ntohl(pol->primary_buffer_offset), + chwall_ref); break; case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY: acm_dump_ste_buffer(ALIGN8(buf + ntohl(pol->primary_buffer_offset)), ntohl(pol->len) - - ntohl(pol->primary_buffer_offset)); + ntohl(pol->primary_buffer_offset), + ste_ref); break; case ACM_NULL_POLICY: @@ -212,13 +219,15 @@ void acm_dump_policy_buffer(void *buf, int buflen) acm_dump_chinesewall_buffer(ALIGN8(buf + ntohl(pol->secondary_buffer_offset)), ntohl(pol->len) - - ntohl(pol->secondary_buffer_offset)); + ntohl(pol->secondary_buffer_offset), + chwall_ref); break; case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY: acm_dump_ste_buffer(ALIGN8(buf + ntohl(pol->secondary_buffer_offset)), ntohl(pol->len) - - ntohl(pol->secondary_buffer_offset)); + ntohl(pol->secondary_buffer_offset), + ste_ref); break; case ACM_NULL_POLICY: @@ -230,6 +239,27 @@ void acm_dump_policy_buffer(void *buf, int buflen) } } +/************************** get dom0 ssidref *****************************/ +int acm_get_ssidref(int xc_handle, int domid, uint16_t *chwall_ref, + uint16_t *ste_ref) +{ + int ret; + struct acm_getssid getssid; + char buf[4096]; + struct acm_ssid_buffer *ssid = (struct acm_ssid_buffer *)buf; + getssid.interface_version = ACM_INTERFACE_VERSION; + set_xen_guest_handle(getssid.ssidbuf, buf); + getssid.ssidbuf_size = sizeof(buf); + getssid.get_ssid_by = ACM_GETBY_domainid; + getssid.id.domainid = domid; + ret = xc_acm_op(xc_handle, ACMOP_getssid, &getssid, sizeof(getssid)); + if (ret == 0) { + *chwall_ref = ssid->ssidref & 0xffff; + *ste_ref = ssid->ssidref >> 16; + } + return ret; +} + /******************************* get policy ******************************/ #define PULL_CACHE_SIZE 8192 @@ -239,12 +269,16 @@ int acm_domain_getpolicy(int xc_handle) { struct acm_getpolicy getpolicy; int ret; + uint16_t chwall_ref, ste_ref; memset(pull_buffer, 0x00, sizeof(pull_buffer)); getpolicy.interface_version = ACM_INTERFACE_VERSION; set_xen_guest_handle(getpolicy.pullcache, pull_buffer); getpolicy.pullcache_size = sizeof(pull_buffer); ret = xc_acm_op(xc_handle, ACMOP_getpolicy, &getpolicy, sizeof(getpolicy)); + if (ret >= 0) { + ret = acm_get_ssidref(xc_handle, 0, &chwall_ref, &ste_ref); + } if (ret < 0) { printf("ACM operation failed: errno=%d\n", errno); @@ -254,7 +288,9 @@ int acm_domain_getpolicy(int xc_handle) } /* dump policy */ - acm_dump_policy_buffer(pull_buffer, sizeof(pull_buffer)); + acm_dump_policy_buffer(pull_buffer, sizeof(pull_buffer), + chwall_ref, ste_ref); + return ret; } @@ -266,6 +302,7 @@ int acm_domain_loadpolicy(int xc_handle, const char *filename) int ret, fd; off_t len; uint8_t *buffer; + uint16_t chwall_ssidref, ste_ssidref; if ((ret = stat(filename, &mystat))) { printf("File %s not found.\n", filename); @@ -282,10 +319,14 @@ int acm_domain_loadpolicy(int xc_handle, const char *filename) printf("File %s not found.\n", filename); goto free_out; } + ret =acm_get_ssidref(xc_handle, 0, &chwall_ssidref, &ste_ssidref); + if (ret < 0) { + goto free_out; + } if (len == read(fd, buffer, len)) { struct acm_setpolicy setpolicy; /* dump it and then push it down into xen/acm */ - acm_dump_policy_buffer(buffer, len); + acm_dump_policy_buffer(buffer, len, chwall_ssidref, ste_ssidref); setpolicy.interface_version = ACM_INTERFACE_VERSION; set_xen_guest_handle(setpolicy.pushcache, buffer); setpolicy.pushcache_size = len; diff --git a/tools/security/secpol_xml2bin.c b/tools/security/secpol_xml2bin.c index 581ede1b64..4b8f1dc7cd 100644 --- a/tools/security/secpol_xml2bin.c +++ b/tools/security/secpol_xml2bin.c @@ -1163,7 +1163,8 @@ int write_binary(char *filename) u_int32_t len_ste = 0, len_chwall = 0, len_pr = 0; /* length of policy components */ - sscanf(policy_version_string,"%d.%d", &major, &minor); + if (policy_version_string) + sscanf(policy_version_string,"%d.%d", &major, &minor); /* open binary file */ if ((fd = diff --git a/xen/acm/acm_chinesewall_hooks.c b/xen/acm/acm_chinesewall_hooks.c index 05f95256d0..c3797e90fc 100644 --- a/xen/acm/acm_chinesewall_hooks.c +++ b/xen/acm/acm_chinesewall_hooks.c @@ -41,6 +41,9 @@ #include <acm/acm_core.h> #include <acm/acm_hooks.h> #include <acm/acm_endian.h> +#include <acm/acm_core.h> + +ssidref_t dom0_chwall_ssidref = 0x0001; /* local cache structures for chinese wall policy */ struct chwall_binary_policy chwall_bin_pol; @@ -53,7 +56,7 @@ int acm_init_chwall_policy(void) { /* minimal startup policy; policy write-locked already */ chwall_bin_pol.max_types = 1; - chwall_bin_pol.max_ssidrefs = 2; + chwall_bin_pol.max_ssidrefs = 1 + dom0_chwall_ssidref; chwall_bin_pol.max_conflictsets = 1; chwall_bin_pol.ssidrefs = (domaintype_t *) xmalloc_array(domaintype_t, @@ -254,7 +257,7 @@ chwall_init_state(struct acm_chwall_policy_buffer *chwall_buf, * more than one type is currently running */ } -static int chwall_set_policy(u8 * buf, u32 buf_size) +static int chwall_set_policy(u8 * buf, u32 buf_size, int is_bootpolicy) { /* policy write-locked already */ struct acm_chwall_policy_buffer *chwall_buf = @@ -286,6 +289,12 @@ static int chwall_set_policy(u8 * buf, u32 buf_size) (chwall_buf->policy_version != ACM_CHWALL_VERSION)) return -EINVAL; + /* during boot dom0_chwall_ssidref is set */ + if (is_bootpolicy && + (dom0_chwall_ssidref >= chwall_buf->chwall_max_ssidrefs)) { + goto error_free; + } + /* 1. allocate new buffers */ ssids = xmalloc_array(domaintype_t, diff --git a/xen/acm/acm_core.c b/xen/acm/acm_core.c index d7becf3510..57db1369f5 100644 --- a/xen/acm/acm_core.c +++ b/xen/acm/acm_core.c @@ -62,18 +62,63 @@ struct acm_binary_policy acm_bin_pol; /* acm binary policy lock */ DEFINE_RWLOCK(acm_bin_pol_rwlock); +/* ACM's only accepted policy name */ +char polname[80]; +char *acm_accepted_boot_policy_name = NULL; + +static void __init set_dom0_ssidref(const char *val) +{ + /* expected format: + ssidref=<hex number>:<policy name> + Policy name must not have a 'space'. + */ + const char *c; + int lo, hi; + int i; + int dom0_ssidref = simple_strtoull(val, &c, 0); + + if (!strncmp(&c[0],":sHype:", 7)) { + lo = dom0_ssidref & 0xffff; + if (lo < ACM_MAX_NUM_TYPES && lo >= 1) + dom0_chwall_ssidref = lo; + hi = dom0_ssidref >> 16; + if (hi < ACM_MAX_NUM_TYPES && hi >= 1) + dom0_ste_ssidref = hi; + for (i = 0; i < sizeof(polname); i++) { + polname[i] = c[7+i]; + if (polname[i] == '\0' || polname[i] == '\t' || + polname[i] == '\n' || polname[i] == ' ' || + polname[i] == ':') { + break; + } + } + polname[i] = 0; + acm_accepted_boot_policy_name = polname; + } +} + +custom_param("ssidref", set_dom0_ssidref); + int acm_set_policy_reference(u8 *buf, u32 buf_size) { + char *name = (char *)(buf + sizeof(struct acm_policy_reference_buffer)); struct acm_policy_reference_buffer *pr = (struct acm_policy_reference_buffer *)buf; + + if (acm_accepted_boot_policy_name != NULL) { + if (strcmp(acm_accepted_boot_policy_name, name)) { + printk("Policy's name '%s' is not the expected one '%s'.\n", + name, acm_accepted_boot_policy_name); + return ACM_ERROR; + } + } + acm_bin_pol.policy_reference_name = (char *)xmalloc_array(u8, be32_to_cpu(pr->len)); if (!acm_bin_pol.policy_reference_name) return -ENOMEM; + strlcpy(acm_bin_pol.policy_reference_name, name, be32_to_cpu(pr->len)); - strlcpy(acm_bin_pol.policy_reference_name, - (char *)(buf + sizeof(struct acm_policy_reference_buffer)), - be32_to_cpu(pr->len)); printk("%s: Activating policy %s\n", __func__, acm_bin_pol.policy_reference_name); return 0; @@ -190,7 +235,8 @@ acm_is_policy(char *buf, unsigned long len) static int acm_setup(char *policy_start, - unsigned long policy_len) + unsigned long policy_len, + int is_bootpolicy) { int rc = ACM_OK; struct acm_policy_buffer *pol; @@ -202,7 +248,8 @@ acm_setup(char *policy_start, if (be32_to_cpu(pol->magic) != ACM_MAGIC) return rc; - rc = do_acm_set_policy((void *)policy_start, (u32)policy_len); + rc = do_acm_set_policy((void *)policy_start, (u32)policy_len, + is_bootpolicy); if (rc == ACM_OK) { printkd("Policy len 0x%lx, start at %p.\n",policy_len,policy_start); @@ -224,7 +271,10 @@ acm_init(char *policy_start, int ret = ACM_OK; /* first try to load the boot policy (uses its own locks) */ - acm_setup(policy_start, policy_len); + acm_setup(policy_start, policy_len, 1); + + /* a user-provided policy may have any name; only matched during boot */ + acm_accepted_boot_policy_name = NULL; if (acm_active_security_policy != ACM_POLICY_UNDEFINED) { @@ -236,6 +286,9 @@ acm_init(char *policy_start, printk("%s: Loading default policy (%s).\n", __func__, ACM_POLICY_NAME(ACM_DEFAULT_SECURITY_POLICY)); + /* (re-)set dom-0 ssidref to default */ + dom0_ste_ssidref = dom0_chwall_ssidref = 0x0001; + if (acm_init_binary_policy(ACM_DEFAULT_SECURITY_POLICY)) { ret = -EINVAL; goto out; diff --git a/xen/acm/acm_null_hooks.c b/xen/acm/acm_null_hooks.c index 27d949378f..f481b71ed4 100644 --- a/xen/acm/acm_null_hooks.c +++ b/xen/acm/acm_null_hooks.c @@ -33,7 +33,7 @@ null_dump_binary_policy(u8 *buf, u32 buf_size) } static int -null_set_binary_policy(u8 *buf, u32 buf_size) +null_set_binary_policy(u8 *buf, u32 buf_size, int is_bootpolicy) { return ACM_OK; } diff --git a/xen/acm/acm_policy.c b/xen/acm/acm_policy.c index 694bd9daa1..96186895c7 100644 --- a/xen/acm/acm_policy.c +++ b/xen/acm/acm_policy.c @@ -50,7 +50,7 @@ acm_set_policy(XEN_GUEST_HANDLE(void) buf, u32 buf_size) printk("%s: Error copying!\n",__func__); goto error_free; } - ret = do_acm_set_policy(policy_buffer, buf_size); + ret = do_acm_set_policy(policy_buffer, buf_size, 0); error_free: xfree(policy_buffer); @@ -59,7 +59,7 @@ acm_set_policy(XEN_GUEST_HANDLE(void) buf, u32 buf_size) int -do_acm_set_policy(void *buf, u32 buf_size) +do_acm_set_policy(void *buf, u32 buf_size, int is_bootpolicy) { struct acm_policy_buffer *pol = (struct acm_policy_buffer *)buf; uint32_t offset, length; @@ -106,14 +106,16 @@ do_acm_set_policy(void *buf, u32 buf_size) length = be32_to_cpu(pol->secondary_buffer_offset) - offset; if ( (offset + length) > buf_size || - acm_primary_ops->set_binary_policy(buf + offset, length)) + acm_primary_ops->set_binary_policy(buf + offset, length, + is_bootpolicy)) goto error_lock_free; /* set secondary policy data */ offset = be32_to_cpu(pol->secondary_buffer_offset); length = be32_to_cpu(pol->len) - offset; if ( (offset + length) > buf_size || - acm_secondary_ops->set_binary_policy(buf + offset, length)) + acm_secondary_ops->set_binary_policy(buf + offset, length, + is_bootpolicy)) goto error_lock_free; memcpy(&acm_bin_pol.xml_pol_version, diff --git a/xen/acm/acm_simple_type_enforcement_hooks.c b/xen/acm/acm_simple_type_enforcement_hooks.c index f5793a22d8..e87d0a25c1 100644 --- a/xen/acm/acm_simple_type_enforcement_hooks.c +++ b/xen/acm/acm_simple_type_enforcement_hooks.c @@ -31,6 +31,9 @@ #include <acm/acm_hooks.h> #include <asm/atomic.h> #include <acm/acm_endian.h> +#include <acm/acm_core.h> + +ssidref_t dom0_ste_ssidref = 0x0001; /* local cache structures for STE policy */ struct ste_binary_policy ste_bin_pol; @@ -74,15 +77,21 @@ int acm_init_ste_policy(void) { /* minimal startup policy; policy write-locked already */ ste_bin_pol.max_types = 1; - ste_bin_pol.max_ssidrefs = 2; - ste_bin_pol.ssidrefs = (domaintype_t *)xmalloc_array(domaintype_t, 2); - memset(ste_bin_pol.ssidrefs, 0, 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; - /* initialize state so that dom0 can start up and communicate with itself */ - ste_bin_pol.ssidrefs[1] = 1; + 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 * dom0_ste_ssidref] = 1; /* init stats */ atomic_set(&(ste_bin_pol.ec_eval_count), 0); @@ -274,7 +283,7 @@ ste_init_state(struct acm_ste_policy_buffer *ste_buf, domaintype_t *ssidrefs) /* set new policy; policy write-locked already */ static int -ste_set_policy(u8 *buf, u32 buf_size) +ste_set_policy(u8 *buf, u32 buf_size, int is_bootpolicy) { struct acm_ste_policy_buffer *ste_buf = (struct acm_ste_policy_buffer *)buf; void *ssidrefsbuf; @@ -305,6 +314,11 @@ ste_set_policy(u8 *buf, u32 buf_size) if (ste_buf->ste_ssid_offset + sizeof(domaintype_t) * ste_buf->ste_max_ssidrefs*ste_buf->ste_max_types > buf_size) goto error_free; + /* during boot dom0_chwall_ssidref is set */ + if (is_bootpolicy && (dom0_ste_ssidref >= ste_buf->ste_max_ssidrefs)) { + goto error_free; + } + arrcpy(ssidrefsbuf, buf + ste_buf->ste_ssid_offset, sizeof(domaintype_t), diff --git a/xen/include/acm/acm_core.h b/xen/include/acm/acm_core.h index 033a1fd418..a09294cfc9 100644 --- a/xen/include/acm/acm_core.h +++ b/xen/include/acm/acm_core.h @@ -123,13 +123,20 @@ int acm_init_domain_ssid(domid_t id, ssidref_t ssidref); void acm_free_domain_ssid(struct acm_ssid_domain *ssid); int acm_init_binary_policy(u32 policy_code); int acm_set_policy(XEN_GUEST_HANDLE(void) buf, u32 buf_size); -int do_acm_set_policy(void *buf, u32 buf_size); +int do_acm_set_policy(void *buf, u32 buf_size, int is_bootpolicy); int acm_get_policy(XEN_GUEST_HANDLE(void) buf, u32 buf_size); int acm_dump_statistics(XEN_GUEST_HANDLE(void) buf, u16 buf_size); int acm_get_ssid(ssidref_t ssidref, XEN_GUEST_HANDLE(void) buf, u16 buf_size); int acm_get_decision(ssidref_t ssidref1, ssidref_t ssidref2, u32 hook); int acm_set_policy_reference(u8 * buf, u32 buf_size); int acm_dump_policy_reference(u8 *buf, u32 buf_size); + + +/* variables */ +extern ssidref_t dom0_chwall_ssidref; +extern ssidref_t dom0_ste_ssidref; +#define ACM_MAX_NUM_TYPES (256) + #endif /* diff --git a/xen/include/acm/acm_hooks.h b/xen/include/acm/acm_hooks.h index 2ac8a4ab44..0a771dd794 100644 --- a/xen/include/acm/acm_hooks.h +++ b/xen/include/acm/acm_hooks.h @@ -91,7 +91,8 @@ struct acm_operations { int (*init_domain_ssid) (void **ssid, ssidref_t ssidref); void (*free_domain_ssid) (void *ssid); int (*dump_binary_policy) (u8 *buffer, u32 buf_size); - int (*set_binary_policy) (u8 *buffer, u32 buf_size); + int (*set_binary_policy) (u8 *buffer, u32 buf_size, + int is_bootpolicy); int (*dump_statistics) (u8 *buffer, u16 buf_size); int (*dump_ssid_types) (ssidref_t ssidref, u8 *buffer, u16 buf_size); /* domain management control hooks (can be NULL) */ @@ -347,14 +348,13 @@ static inline int acm_pre_grant_setup(domid_t id) } } -/* predefined ssidref for DOM0 used by xen when creating DOM0 */ -#define ACM_DOM0_SSIDREF 0x00010001 - static inline void acm_post_domain0_create(domid_t domid) { /* initialialize shared sHype security labels for new domain */ - acm_init_domain_ssid(domid, ACM_DOM0_SSIDREF); - acm_post_domain_create(domid, ACM_DOM0_SSIDREF); + int dom0_ssidref = dom0_ste_ssidref << 16 | dom0_chwall_ssidref; + + acm_init_domain_ssid(domid, dom0_ssidref); + acm_post_domain_create(domid, dom0_ssidref); } static inline int acm_sharing(ssidref_t ssidref1, ssidref_t ssidref2) |