diff --git a/data/expected_cil/associate.cil b/data/expected_cil/associate.cil index c100a79..bd88597 100644 --- a/data/expected_cil/associate.cil +++ b/data/expected_cil/associate.cil @@ -132,11 +132,20 @@ (typeattribute resource) (typeattribute bin) (typeattributeset resource (bin)) +(typeattribute dom_with_mix) +(typeattributeset domain (dom_with_mix)) +(type dom_with_mix-mix) +(roletype object_r dom_with_mix-mix) +(typeattributeset resource (dom_with_mix-mix)) +(typeattribute dom_with_mix_2) +(typeattributeset domain (dom_with_mix_2)) (typeattribute foo) (typeattributeset domain (foo)) (type kernel_sid) (roletype system_r kernel_sid) (typeattributeset domain (kernel_sid)) +(typeattribute mix) +(typeattributeset resource (mix)) (typeattribute nest_parent) (typeattributeset domain (nest_parent)) (typeattribute nest_parent-nest_resource) @@ -170,6 +179,14 @@ (typeattribute diamond2) (typeattributeset foo (diamond2)) (typeattributeset domain (diamond2)) +(typeattribute dom_with_mix_2-mix) +(typeattributeset mix (dom_with_mix_2-mix)) +(typeattributeset resource (dom_with_mix_2-mix)) +(type dom_with_mix_3) +(roletype system_r dom_with_mix_3) +(typeattributeset dom_with_mix (dom_with_mix_3)) +(typeattributeset dom_with_mix_2 (dom_with_mix_3)) +(typeattributeset domain (dom_with_mix_3)) (typeattribute foo-tmp) (typeattributeset tmp (foo-tmp)) (typeattributeset resource (foo-tmp)) @@ -223,6 +240,10 @@ (typeattributeset diamond1 (diamond3)) (typeattributeset diamond2 (diamond3)) (typeattributeset domain (diamond3)) +(type dom_with_mix_3-mix) +(roletype object_r dom_with_mix_3-mix) +(typeattributeset dom_with_mix_2-mix (dom_with_mix_3-mix)) +(typeattributeset resource (dom_with_mix_3-mix)) (type baz-tmp) (roletype object_r baz-tmp) (typeattributeset bar-tmp (baz-tmp)) diff --git a/data/policies/associate.cas b/data/policies/associate.cas index 5286cab..47c485c 100644 --- a/data/policies/associate.cas +++ b/data/policies/associate.cas @@ -116,3 +116,15 @@ virtual domain diamond2 inherits foo {} // Gets two copies of associated resources via multiple inheritance, but they should collapse to one domain diamond3 inherits diamond1, diamond2 {} + + +virtual resource mix {} + +virtual domain dom_with_mix { + resource mix {} +} + +@associate([mix]) +virtual domain dom_with_mix_2 {} + +domain dom_with_mix_3 inherits dom_with_mix, dom_with_mix_2 {} diff --git a/src/compile.rs b/src/compile.rs index c36530d..c539d2a 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -1528,11 +1528,17 @@ fn generate_type_no_parent_errors(missed_types: Vec<&TypeInfo>, types: &TypeMap) ret } -fn get_synthetic_resource_name( +pub fn get_synthetic_resource_name( dom_name: &CascadeString, associated_resource: &CascadeString, ) -> CascadeString { - format!("{}.{}", dom_name, associated_resource).into() + let cs_name = format!("{}.{}", dom_name, associated_resource); + // We keep the range of the *resource* part specifically, which should always be where this + // resource was defined + match associated_resource.get_range() { + Some(range) => CascadeString::new(cs_name, range), + None => CascadeString::from(cs_name) + } } fn create_synthetic_resource( @@ -1562,10 +1568,8 @@ fn create_synthetic_resource( let res_name = get_synthetic_resource_name(&dom_info.name, class_string); if types.get(res_name.as_ref()).is_some() { // A synthetic type with this name already exists, due to a nested association - // TODO: I don't think it's an accurate assumption that dom_info is definitely the child in - // this case. It's just whichever one happens to be done via annotation return Err( - match make_duplicate_associate_error(types, dom_info, &res_name) { + match make_duplicate_associate_error(types, dom_info, &class_string) { Some(e) => e.into(), None => ErrorItem::Internal(InternalError::new()), }, @@ -1684,7 +1688,7 @@ fn interpret_associate( let potential_resources: BTreeMap<_, _> = associate .resources .iter() - .map(|r| (r.name.as_ref(), (r, false))) + .map(|r| (r.name().as_ref(), (r, false))) .collect(); for (_, (res, _)) in potential_resources.iter().filter(|(_, (_, seen))| !seen) { diff --git a/src/internal_rep.rs b/src/internal_rep.rs index 8a9852d..51cff44 100644 --- a/src/internal_rep.rs +++ b/src/internal_rep.rs @@ -33,9 +33,9 @@ pub type TypeMap = AliasMap; #[derive(Clone, Debug, Eq, PartialEq)] pub struct AssociatedResource { - pub name: CascadeString, - pub doms: BTreeSet>, - pub ranges: BTreeMap>, + name: CascadeString, + doms: BTreeSet>, + ranges: BTreeMap>, } impl AssociatedResource { @@ -46,6 +46,10 @@ impl AssociatedResource { self.ranges.get(resource_name).cloned() } + pub fn name(&self) -> &CascadeString { + &self.name + } + pub fn get_class_names(&self) -> Vec { self.doms .iter() @@ -564,6 +568,10 @@ impl TypeInfo { self.is_resource(types) && self.name.as_ref().contains('.') } + pub fn get_associated_dom_name(&self) -> Option<&str> { + self.name.as_ref().split_once('.').map(|split| split.0) + } + // Returns false if this type is explicitly declared in source code, and true otherwise pub fn is_synthetic(&self) -> bool { self.name.get_range().is_none() @@ -610,18 +618,50 @@ impl TypeInfo { // specifically associations specifically in source, rather than somehow derived by the // compiler pub fn explicitly_associates(&self, associate_name: &str) -> Option> { + use crate::compile::get_synthetic_resource_name; + for ann in &self.annotations { - if let AnnotationInfo::Associate(associations) = ann { + if let AnnotationInfo::Associate(associations) | AnnotationInfo::NestAssociate(associations) = ann { for res in &associations.resources { if res.string_is_instance(&CascadeString::from(associate_name)) && res.get_range(associate_name).is_some() { + // I think the issue is that this get_range() is returning None + // In other news, I'm an idiot. We are in a block for an if .is_some() on + // the exact same thing return res.get_range(associate_name); } } } } - None + let ar_range = self.associated_resources + .iter() + .find(|a| a.string_is_instance(&associate_name.into())) + .and_then(|ar| { + ar.get_range( + get_synthetic_resource_name(&self.name, &associate_name.into()) + .as_ref(), + ) + }); + + if ar_range.is_some() { + return ar_range; + } + + // If the resource is foo.bar, and we are foo, we need to check bar as well. If the reason + // is bar and we are foo, we need to check foo.bar as well + match associate_name.split_once('.') { + Some((dom_name, res_name)) => { + if dom_name == self.name { + self.explicitly_associates(res_name) + } else { + None + } + } + None => { + self.explicitly_associates(get_synthetic_resource_name(&self.name, &associate_name.into()).as_ref()) + } + } } pub fn get_aliases(&self) -> BTreeSet<&CascadeString> {