📄 acm_simple_type_enforcement_hooks.c
字号:
ste_buf->policy_code = be32_to_cpu(ste_buf->policy_code); ste_buf->policy_version = be32_to_cpu(ste_buf->policy_version); ste_buf->ste_max_types = be32_to_cpu(ste_buf->ste_max_types); ste_buf->ste_max_ssidrefs = be32_to_cpu(ste_buf->ste_max_ssidrefs); ste_buf->ste_ssid_offset = be32_to_cpu(ste_buf->ste_ssid_offset); /* policy type and version checks */ if ( (ste_buf->policy_code != ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY) || (ste_buf->policy_version != ACM_STE_VERSION) ) return -EINVAL; /* during boot dom0_chwall_ssidref is set */ if ( is_bootpolicy && (dom0_ste_ssidref >= ste_buf->ste_max_ssidrefs) ) return -EINVAL; return _ste_update_policy(buf, buf_size, 1, errors);}static intste_set_policy(u8 *buf, u32 buf_size){ return _ste_update_policy(buf, buf_size, 0, NULL);}static int ste_dump_stats(u8 *buf, u16 buf_len){ struct acm_ste_stats_buffer stats; /* now send the hook counts to user space */ stats.ec_eval_count = cpu_to_be32(atomic_read(&ste_bin_pol.ec_eval_count)); stats.gt_eval_count = cpu_to_be32(atomic_read(&ste_bin_pol.gt_eval_count)); stats.ec_denied_count = cpu_to_be32(atomic_read(&ste_bin_pol.ec_denied_count)); stats.gt_denied_count = cpu_to_be32(atomic_read(&ste_bin_pol.gt_denied_count)); stats.ec_cachehit_count = cpu_to_be32(atomic_read(&ste_bin_pol.ec_cachehit_count)); stats.gt_cachehit_count = cpu_to_be32(atomic_read(&ste_bin_pol.gt_cachehit_count)); if ( buf_len < sizeof(struct acm_ste_stats_buffer) ) return -ENOMEM; memcpy(buf, &stats, sizeof(struct acm_ste_stats_buffer)); return sizeof(struct acm_ste_stats_buffer);}static intste_dump_ssid_types(ssidref_t ssidref, u8 *buf, u16 len){ int i; /* fill in buffer */ if ( ste_bin_pol.max_types > len ) return -EFAULT; if ( ssidref >= ste_bin_pol.max_ssidrefs ) return -EFAULT; /* read types for chwall ssidref */ for( i = 0; i< ste_bin_pol.max_types; i++ ) { if (ste_bin_pol.ssidrefs[ssidref * ste_bin_pol.max_types + i]) buf[i] = 1; else buf[i] = 0; } return ste_bin_pol.max_types;}/* we need to go through this before calling the hooks, * returns 1 == cache hit */static int inlinecheck_cache(struct domain *dom, domid_t rdom){ struct ste_ssid *ste_ssid; int i; printkd("checking cache: %x --> %x.\n", dom->domain_id, rdom); if (dom->ssid == NULL) return 0; ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, (struct acm_ssid_domain *)(dom->ssid)); for( i = 0; i < ACM_TE_CACHE_SIZE; i++ ) { if ( (ste_ssid->ste_cache[i].valid == ACM_STE_valid) && (ste_ssid->ste_cache[i].id == rdom) ) { printkd("cache hit (entry %x, id= %x!\n", i, ste_ssid->ste_cache[i].id); return 1; } } return 0;}/* we only get here if there is NO entry yet; no duplication check! */static void inlinecache_result(struct domain *subj, struct domain *obj) { struct ste_ssid *ste_ssid; int i; printkd("caching from doms: %x --> %x.\n", subj->domain_id, obj->domain_id); if ( subj->ssid == NULL ) return; ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, (struct acm_ssid_domain *)(subj)->ssid); for( i = 0; i < ACM_TE_CACHE_SIZE; i++ ) if ( ste_ssid->ste_cache[i].valid == ACM_STE_free ) break; if ( i < ACM_TE_CACHE_SIZE ) { ste_ssid->ste_cache[i].valid = ACM_STE_valid; ste_ssid->ste_cache[i].id = obj->domain_id; } else printk ("Cache of dom %x is full!\n", subj->domain_id);}/* deletes entries for domain 'id' from all caches (re-use) */static void inlineclean_id_from_cache(domid_t id) { struct ste_ssid *ste_ssid; int i; struct acm_ssid_domain *rawssid; printkd("deleting cache for dom %x.\n", id); read_lock(&ssid_list_rwlock); /* look through caches of all domains */ for_each_acmssid ( rawssid ) { ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, rawssid); if ( !ste_ssid ) { printk("%s: deleting ID from cache ERROR (no ste_ssid)!\n", __func__); goto out; } for ( i = 0; i < ACM_TE_CACHE_SIZE; i++ ) if ( (ste_ssid->ste_cache[i].valid == ACM_STE_valid) && (ste_ssid->ste_cache[i].id == id) ) ste_ssid->ste_cache[i].valid = ACM_STE_free; } out: read_unlock(&ssid_list_rwlock);}/*************************** * Authorization functions **************************/static int ste_pre_domain_create(void *subject_ssid, ssidref_t ssidref){ /* check for ssidref in range for policy */ ssidref_t ste_ssidref; traceprintk("%s.\n", __func__); read_lock(&acm_bin_pol_rwlock); ste_ssidref = GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref); if ( ste_ssidref >= ste_bin_pol.max_ssidrefs ) { printk("%s: ERROR ste_ssidref > max(%x).\n", __func__, ste_bin_pol.max_ssidrefs-1); read_unlock(&acm_bin_pol_rwlock); return ACM_ACCESS_DENIED; } read_unlock(&acm_bin_pol_rwlock); return ACM_ACCESS_PERMITTED;}static intste_domain_create(void *subject_ssid, ssidref_t ssidref, domid_t domid){ return ste_pre_domain_create(subject_ssid, ssidref);}static void ste_domain_destroy(void *subject_ssid, struct domain *d){ /* clean all cache entries for destroyed domain (might be re-used) */ clean_id_from_cache(d->domain_id);}/* -------- EVENTCHANNEL OPERATIONS -----------*/static intste_pre_eventchannel_unbound(domid_t id1, domid_t id2) { struct domain *subj, *obj; int ret; traceprintk("%s: dom%x-->dom%x.\n", __func__, (id1 == DOMID_SELF) ? current->domain->domain_id : id1, (id2 == DOMID_SELF) ? current->domain->domain_id : id2); if ( id1 == DOMID_SELF ) id1 = current->domain->domain_id; if ( id2 == DOMID_SELF ) id2 = current->domain->domain_id; subj = rcu_lock_domain_by_id(id1); obj = rcu_lock_domain_by_id(id2); if ( (subj == NULL) || (obj == NULL) ) { ret = ACM_ACCESS_DENIED; goto out; } /* cache check late */ if ( check_cache(subj, obj->domain_id) ) { atomic_inc(&ste_bin_pol.ec_cachehit_count); ret = ACM_ACCESS_PERMITTED; goto out; } atomic_inc(&ste_bin_pol.ec_eval_count); if ( share_common_type(subj, obj) ) { cache_result(subj, obj); ret = ACM_ACCESS_PERMITTED; } else { atomic_inc(&ste_bin_pol.ec_denied_count); ret = ACM_ACCESS_DENIED; } out: if ( obj != NULL ) rcu_unlock_domain(obj); if ( subj != NULL ) rcu_unlock_domain(subj); return ret;}static intste_pre_eventchannel_interdomain(domid_t id){ struct domain *subj=NULL, *obj=NULL; int ret; traceprintk("%s: dom%x-->dom%x.\n", __func__, current->domain->domain_id, (id == DOMID_SELF) ? current->domain->domain_id : id); /* following is a bit longer but ensures that we * "put" only domains that we where "find"-ing */ if ( id == DOMID_SELF ) id = current->domain->domain_id; subj = current->domain; obj = rcu_lock_domain_by_id(id); if ( obj == NULL ) { ret = ACM_ACCESS_DENIED; goto out; } /* cache check late, but evtchn is not on performance critical path */ if ( check_cache(subj, obj->domain_id) ) { atomic_inc(&ste_bin_pol.ec_cachehit_count); ret = ACM_ACCESS_PERMITTED; goto out; } atomic_inc(&ste_bin_pol.ec_eval_count); if ( share_common_type(subj, obj) ) { cache_result(subj, obj); ret = ACM_ACCESS_PERMITTED; } else { atomic_inc(&ste_bin_pol.ec_denied_count); ret = ACM_ACCESS_DENIED; } out: if ( obj != NULL ) rcu_unlock_domain(obj); return ret;}/* -------- SHARED MEMORY OPERATIONS -----------*/static intste_pre_grant_map_ref (domid_t id){ struct domain *obj, *subj; int ret; traceprintk("%s: dom%x-->dom%x.\n", __func__, current->domain->domain_id, id); if ( check_cache(current->domain, id) ) { atomic_inc(&ste_bin_pol.gt_cachehit_count); return ACM_ACCESS_PERMITTED; } atomic_inc(&ste_bin_pol.gt_eval_count); subj = current->domain; obj = rcu_lock_domain_by_id(id); if ( share_common_type(subj, obj) ) { cache_result(subj, obj); ret = ACM_ACCESS_PERMITTED; } else { atomic_inc(&ste_bin_pol.gt_denied_count); printkd("%s: ACCESS DENIED!\n", __func__); ret = ACM_ACCESS_DENIED; } if ( obj != NULL ) rcu_unlock_domain(obj); return ret;}/* since setting up grant tables involves some implicit information flow from the creating domain to the domain that is setup, we check types in addition to the general authorization */static intste_pre_grant_setup (domid_t id){ struct domain *obj, *subj; int ret; traceprintk("%s: dom%x-->dom%x.\n", __func__, current->domain->domain_id, id); if ( check_cache(current->domain, id) ) { atomic_inc(&ste_bin_pol.gt_cachehit_count); return ACM_ACCESS_PERMITTED; } atomic_inc(&ste_bin_pol.gt_eval_count); subj = current->domain; obj = rcu_lock_domain_by_id(id); /* a) check authorization (eventually use specific capabilities) */ if ( obj && !IS_PRIV_FOR(current->domain, obj) ) { printk("%s: Grant table management authorization denied ERROR!\n", __func__); rcu_unlock_domain(obj); return ACM_ACCESS_DENIED; } /* b) check types */ if ( share_common_type(subj, obj) ) { cache_result(subj, obj); ret = ACM_ACCESS_PERMITTED; } else { atomic_inc(&ste_bin_pol.gt_denied_count); ret = ACM_ACCESS_DENIED; } if ( obj != NULL ) rcu_unlock_domain(obj); return ret;}/* -------- DOMAIN-Requested Decision hooks -----------*/static intste_sharing(ssidref_t ssidref1, ssidref_t ssidref2){ int hct = have_common_type( GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref1), GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref2)); return (hct ? ACM_ACCESS_PERMITTED : ACM_ACCESS_DENIED);}static intste_authorization(ssidref_t ssidref1, ssidref_t ssidref2){ int iss = is_superset( GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref1), GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref2)); return (iss ? ACM_ACCESS_PERMITTED : ACM_ACCESS_DENIED);}static intste_is_default_policy(void){ const static domaintype_t def_policy[4] = { 0x0, 0x1, 0x1, 0x1}; return ((ste_bin_pol.max_types == 2) && (ste_bin_pol.max_ssidrefs == 2) && (memcmp(ste_bin_pol.ssidrefs, def_policy, sizeof(def_policy)) == 0));}/* now define the hook structure similarly to LSM */struct acm_operations acm_simple_type_enforcement_ops = { /* policy management services */ .init_domain_ssid = ste_init_domain_ssid, .free_domain_ssid = ste_free_domain_ssid, .dump_binary_policy = ste_dump_policy, .test_binary_policy = ste_test_policy, .set_binary_policy = ste_set_policy, .dump_statistics = ste_dump_stats, .dump_ssid_types = ste_dump_ssid_types, /* domain management control hooks */ .domain_create = ste_domain_create, .domain_destroy = ste_domain_destroy, /* event channel control hooks */ .pre_eventchannel_unbound = ste_pre_eventchannel_unbound, .fail_eventchannel_unbound = NULL, .pre_eventchannel_interdomain = ste_pre_eventchannel_interdomain, .fail_eventchannel_interdomain = NULL, /* grant table control hooks */ .pre_grant_map_ref = ste_pre_grant_map_ref, .fail_grant_map_ref = NULL, .pre_grant_setup = ste_pre_grant_setup, .fail_grant_setup = NULL, /* generic domain-requested decision hooks */ .sharing = ste_sharing, .authorization = ste_authorization, .conflictset = NULL, .is_default_policy = ste_is_default_policy,};/* * 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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -