diff --git a/oak/server/rust/oak_runtime/src/runtime/mod.rs b/oak/server/rust/oak_runtime/src/runtime/mod.rs index c84cd8e1f9e..e4032c38f1c 100644 --- a/oak/server/rust/oak_runtime/src/runtime/mod.rs +++ b/oak/server/rust/oak_runtime/src/runtime/mod.rs @@ -501,16 +501,14 @@ impl Runtime { } /// Returns the least restrictive (i.e. least confidential, most trusted) label that this Node - /// may downgrade to. This takes into account all the [downgrade privilege](NodeInfo::privilege) - /// that the node possesses. - fn get_node_downgraded_label(&self, node_id: NodeId) -> Label { - // Original (static) Node label. - let node_label = self.get_node_label(node_id); + /// may downgrade `initial_label` to. This takes into account all the [downgrade + /// privilege](NodeInfo::privilege) that the node possesses. + fn get_node_downgraded_label(&self, node_id: NodeId, initial_label: &Label) -> Label { // Retrieve the set of tags that the node may downgrade. let node_privilege = self.get_node_privilege(node_id); Label { // Remove all the confidentiality tags that the Node may declassify. - confidentiality_tags: node_label + confidentiality_tags: initial_label .confidentiality_tags .iter() .filter(|t| { @@ -521,7 +519,7 @@ impl Runtime { .cloned() .collect(), // Add all the integrity tags that the Node may endorse. - integrity_tags: node_label + integrity_tags: initial_label .integrity_tags .iter() .chain(node_privilege.can_endorse_integrity_tags.iter()) @@ -571,20 +569,25 @@ impl Runtime { fn validate_can_read_from_label( &self, node_id: NodeId, - label: &Label, + source_label: &Label, ) -> Result<(), OakStatus> { - let downgraded_node_label = self.get_node_downgraded_label(node_id); + // When reading from a Channel, we downgrade the Label of the Channel from which the Node is + // reading: the thing being downgraded is the data being read into the Node (protected by + // the Channel Label). + let downgraded_source_label = self.get_node_downgraded_label(node_id, source_label); + let target_label = self.get_node_label(node_id); + trace!("{:?}: original source label: {:?}?", node_id, source_label); trace!( - "{:?}: can {:?} read from {:?}?", + "{:?}: downgraded source label: {:?}?", node_id, - downgraded_node_label, - label + downgraded_source_label ); - if label.flows_to(&downgraded_node_label) { - trace!("{:?}: can read from {:?}", node_id, label); + trace!("{:?}: target label: {:?}?", node_id, target_label); + if downgraded_source_label.flows_to(&target_label) { + trace!("{:?}: can read from {:?}", node_id, source_label); Ok(()) } else { - debug!("{:?}: cannot read from {:?}", node_id, label); + debug!("{:?}: cannot read from {:?}", node_id, source_label); Err(OakStatus::ErrPermissionDenied) } } @@ -602,19 +605,27 @@ impl Runtime { /// Returns whether the given Node is allowed to write to an entity with the provided [`Label`], /// taking into account all the [downgrade privilege](NodeInfo::privilege) the Node possesses. - fn validate_can_write_to_label(&self, node_id: NodeId, label: &Label) -> Result<(), OakStatus> { - let downgraded_node_label = self.get_node_downgraded_label(node_id); + fn validate_can_write_to_label( + &self, + node_id: NodeId, + target_label: &Label, + ) -> Result<(), OakStatus> { + // When writing to a Channel, we downgrade the Label of the Node itself: the thing being + // downgraded is the data inside the Node (protected by the Node Label). + let source_label = self.get_node_label(node_id); + let downgraded_source_label = self.get_node_downgraded_label(node_id, &source_label); + trace!("{:?}: original source label: {:?}?", node_id, source_label); trace!( - "{:?}: can {:?} write to {:?}?", + "{:?}: downgraded source label: {:?}?", node_id, - downgraded_node_label, - label + downgraded_source_label ); - if downgraded_node_label.flows_to(&label) { - trace!("{:?}: can write to {:?}", node_id, label); + trace!("{:?}: target label: {:?}?", node_id, target_label); + if downgraded_source_label.flows_to(&target_label) { + trace!("{:?}: can write to {:?}", node_id, target_label); Ok(()) } else { - debug!("{:?}: cannot write to {:?}", node_id, label); + debug!("{:?}: cannot write to {:?}", node_id, target_label); Err(OakStatus::ErrPermissionDenied) } } diff --git a/oak/server/rust/oak_runtime/src/runtime/tests.rs b/oak/server/rust/oak_runtime/src/runtime/tests.rs index 1f5f92bcdbc..3015182e2b6 100644 --- a/oak/server/rust/oak_runtime/src/runtime/tests.rs +++ b/oak/server/rust/oak_runtime/src/runtime/tests.rs @@ -226,7 +226,11 @@ fn create_channel_less_confidential_label_no_privilege_err() { ); } -/// Create a test Node that creates a Channel with a more confidential label and succeeds. +/// Create a test Node with no privilege that: +/// +/// - creates a Channel with a more confidential label and succeeds +/// - writes to the newly created channel and succeeds +/// - reads from the newly created channel and fails /// /// Data is always allowed to flow to more confidential labels. #[test] @@ -247,6 +251,76 @@ fn create_channel_more_confidential_label_ok() { Box::new(move |runtime| { let result = runtime.channel_create(&more_confidential_label); assert_eq!(true, result.is_ok()); + + let (write_handle, read_handle) = result.unwrap(); + + { + // Writing to a more confidential Channel is allowed. + let message = NodeMessage { + data: vec![14, 12, 88], + handles: vec![], + }; + let result = runtime.channel_write(write_handle, message); + assert_eq!(true, result.is_ok()); + } + + { + // Reading from a more confidential Channel is not allowed. + let result = runtime.channel_read(read_handle); + assert_eq!(false, result.is_ok()); + } + + Ok(()) + }), + ); +} + +/// Create a test Node with downgrading privilege that: +/// +/// - creates a Channel with a more confidential label and succeeds (same as previous test case) +/// - writes to the newly created channel and succeeds (same as previous test case) +/// - reads from the newly created channel and succeeds (different from previous test case, thanks +/// to the newly added privilege) +#[test] +fn create_channel_more_confidential_label_privilege_ok() { + let tag_0 = oak_abi::label::authorization_bearer_token_hmac_tag(&[1, 1, 1]); + let tag_1 = oak_abi::label::authorization_bearer_token_hmac_tag(&[2, 2, 2]); + let initial_label = Label { + confidentiality_tags: vec![tag_0.clone()], + integrity_tags: vec![], + }; + let more_confidential_label = Label { + confidentiality_tags: vec![tag_0, tag_1.clone()], + integrity_tags: vec![], + }; + run_node_body( + &initial_label, + &NodePrivilege { + can_declassify_confidentiality_tags: hashset! { tag_1 }, + can_endorse_integrity_tags: hashset! {}, + }, + Box::new(move |runtime| { + let result = runtime.channel_create(&more_confidential_label); + assert_eq!(true, result.is_ok()); + + let (write_handle, read_handle) = result.unwrap(); + + { + // Writing to a more confidential Channel is allowed. + let message = NodeMessage { + data: vec![14, 12, 88], + handles: vec![], + }; + let result = runtime.channel_write(write_handle, message); + assert_eq!(true, result.is_ok()); + } + + { + // Reading from a more confidential Channel is allowed because of the privilege. + let result = runtime.channel_read(read_handle); + assert_eq!(true, result.is_ok()); + } + Ok(()) }), );