Skip to content

Commit

Permalink
Support declassification of tags
Browse files Browse the repository at this point in the history
  • Loading branch information
tiziano88 committed May 13, 2020
1 parent 38522c9 commit d7bb404
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 61 deletions.
13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions docs/concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,12 +230,28 @@ allowed (via two uni-directional Channels) if
`(L_a ⊑ L_b) ∧ (L_b ⊑ L_a) ⇒ L_a = L_b`, i.e. if `a` and `b` have identical
secrecy and integrity.

#### Downgrades

A Node may have the ability to remove one or more secrecy tags
(**declassification**) or add one or more integrity tags (**endorsement**). Both
of these operations are instances of **downgrade** operations (which is a more
general concept).

The set of tags that can be downgraded by a Node is determined by the Oak
Runtime based on the initial or current state of the Node. For instance, the Oak
Runtime grants the capability to declassify user tags to each instance of gRPC
Server Node, which is trusted to only use it in order to declassify data for the
user that is in fact currently authenticated over a gRPC connection.

#### References

More details on Information Flow Control may be found in the following
references:

- [Information Flow Control for Standard OS Abstractions](https://pdos.csail.mit.edu/papers/flume-sosp07.pdf)
- [Flow-Limited Authorization](https://www.cs.cornell.edu/andru/papers/flam/flam-csf15.pdf)
- [Integrity Considerations for Secure Computer Systems](http://seclab.cs.ucdavis.edu/projects/history/papers/biba75.pdf)
- [Protecting Privacy using the Decentralized Label Model](https://www.cs.cornell.edu/andru/papers/iflow-tosem.pdf)

### gRPC and user labels

Expand Down
1 change: 1 addition & 0 deletions oak/server/rust/oak_runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ prost = "*"
prost-types = "*"
rand = "*"
regex = { version = "1", optional = true }
sha2 = "*"
tokio = { version = "*", features = ["io-driver", "rt-core", "macros"] }
# Using an old version that is supported by `cargo-raze`:
# https://github.com/google/cargo-raze/issues/41#issuecomment-592274128
Expand Down
138 changes: 87 additions & 51 deletions oak/server/rust/oak_runtime/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@ use crate::{
use core::sync::atomic::{AtomicBool, AtomicU64, Ordering::SeqCst};
use itertools::Itertools;
use log::{debug, error, info, trace, warn};
use oak_abi::{label::Label, ChannelReadStatus, OakStatus};
use oak_abi::{
label::{Label, Tag},
ChannelReadStatus, OakStatus,
};
use rand::RngCore;
use std::{
collections::HashMap,
collections::{HashMap, HashSet},
fmt::Write,
string::String,
sync::{Arc, Mutex, RwLock},
Expand Down Expand Up @@ -65,6 +68,14 @@ struct NodeInfo {
/// See https://github.com/project-oak/oak/blob/master/docs/concepts.md#labels
label: Label,

/// Tags that may be downgraded by the Node; either:
///
/// - tags that may be declassified (removed from the secrecy component of a label)
/// - tags that may be endorsed (added to the integrity component of a label)
///
/// See https://github.com/project-oak/oak/blob/master/docs/concepts.md#downgrades
can_downgrade_tags: HashSet<Tag>,

/// Map of ABI handles to channels.
abi_handles: HashMap<oak_abi::Handle, ChannelHalf>,

Expand Down Expand Up @@ -295,6 +306,7 @@ impl RuntimeProxy {
proxy.node_id,
"implicit.initial",
&Label::public_trusted(),
&[],
);
proxy
}
Expand Down Expand Up @@ -679,6 +691,34 @@ impl Runtime {
node_info.label.clone()
}

fn get_node_downgraded_label(&self, node_id: NodeId) -> Label {
let node_label = self.get_node_label(node_id);
let node_can_downgrade_tags = self.get_node_can_downgrade_tags(node_id);
Label {
secrecy_tags: node_label
.secrecy_tags
.iter()
.filter(|t| !node_can_downgrade_tags.contains(t))
.cloned()
.collect(),
integrity_tags: node_label
.integrity_tags
.iter()
.chain(node_can_downgrade_tags.iter())
.cloned()
.collect(),
}
}

fn get_node_can_downgrade_tags(&self, node_id: NodeId) -> HashSet<Tag> {
let node_infos = self
.node_infos
.read()
.expect("could not acquire lock on node_infos");
let node_info = node_infos.get(&node_id).expect("invalid node_id");
node_info.can_downgrade_tags.clone()
}

/// Returns a clone of the [`Label`] associated with the provided reader `channel_half`.
///
/// Returns an error if `channel_half` is not a valid read half.
Expand All @@ -693,62 +733,66 @@ impl Runtime {
with_writer_channel(channel_half, |channel| Ok(channel.label.clone()))
}

/// Returns whether the given Node is allowed to read from the provided channel, according to
/// their respective [`Label`]s.
/// Returns whether the given Node is allowed to read from the provided channel read half,
/// according to their respective [`Label`]s.
fn validate_can_read_from_channel(
&self,
node_id: NodeId,
channel_half: &ChannelHalf,
) -> Result<(), OakStatus> {
trace!(
"{:?}: validating readability of {:?}",
node_id,
channel_half
);

let node_label = self.get_node_label(node_id);
let channel_label = self.get_reader_channel_label(&channel_half)?;
self.validate_can_read_from_label(node_id, &channel_label)
}

/// Returns whether the given Node is allowed to read from an entity with the provided
/// [`Label`], taking into account any dowgrades it may be capable of.
fn validate_can_read_from_label(
&self,
node_id: NodeId,
label: &Label,
) -> Result<(), OakStatus> {
let downgraded_node_label = self.get_node_downgraded_label(node_id);
trace!(
"{:?}: node_label={:?}, channel_label={:?}",
"{:?}: can {:?} read from {:?}?",
node_id,
node_label,
channel_label
downgraded_node_label,
label
);
if channel_label.flows_to(&node_label) {
trace!("{:?}: can read from channel {:?}", node_id, channel_half);
if label.flows_to(&downgraded_node_label) {
trace!("{:?}: can read from {:?}", node_id, label);
Ok(())
} else {
debug!("{:?}: cannot read from channel {:?}", node_id, channel_half);
debug!("{:?}: cannot read from {:?}", node_id, label);
Err(OakStatus::ErrPermissionDenied)
}
}

/// Returns whether the given Node is allowed to write to the provided channel, according to
/// their respective [`Label`]s.
/// Returns whether the given Node is allowed to write to the provided channel write half,
/// according to their respective [`Label`]s.
fn validate_can_write_to_channel(
&self,
node_id: NodeId,
channel_half: &ChannelHalf,
) -> Result<(), OakStatus> {
trace!(
"{:?}: validating writability of {:?}",
node_id,
channel_half
);

let node_label = self.get_node_label(node_id);
let channel_label = self.get_writer_channel_label(&channel_half)?;
self.validate_can_write_to_label(node_id, &channel_label)
}

/// Returns whether the given Node is allowed to write to an entity with the provided [`Label`],
/// taking into account any dowgrades it may be capable of.
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);
trace!(
"{:?}: node_label={:?}, channel_label={:?}",
"{:?}: can {:?} write to {:?}?",
node_id,
node_label,
channel_label
downgraded_node_label,
label
);
if node_label.flows_to(&channel_label) {
trace!("{:?}: can write to channel {:?}", node_id, channel_half);
if downgraded_node_label.flows_to(&label) {
trace!("{:?}: can write to {:?}", node_id, label);
Ok(())
} else {
debug!("{:?}: cannot write to channel {:?}", node_id, channel_half);
debug!("{:?}: cannot write to {:?}", node_id, label);
Err(OakStatus::ErrPermissionDenied)
}
}
Expand All @@ -761,14 +805,7 @@ impl Runtime {
node_id: NodeId,
label: &Label,
) -> Result<(oak_abi::Handle, oak_abi::Handle), OakStatus> {
let node_label = self.get_node_label(node_id);
if !node_label.flows_to(label) {
warn!(
"channel_create: label {:?} does not flow to label {:?}",
node_label, label
);
return Err(OakStatus::ErrPermissionDenied);
}
self.validate_can_write_to_label(node_id, label)?;
// First get a pair of `ChannelHalf` objects.
let channel_id = self.next_channel_id.fetch_add(1, SeqCst);
let channel = Channel::new(channel_id, label);
Expand Down Expand Up @@ -1144,18 +1181,10 @@ impl Runtime {
if self.is_terminating() {
return Err(OakStatus::ErrTerminated);
}
self.validate_can_write_to_label(node_id, label)?;

let reader = self.abi_to_read_half(node_id, initial_handle)?;

let node_label = self.get_node_label(node_id);
if !node_label.flows_to(label) {
warn!(
"node_create: label {:?} does not flow to label {:?}",
node_label, label
);
return Err(OakStatus::ErrPermissionDenied);
}

let config = self
.configuration
.nodes
Expand All @@ -1170,7 +1199,7 @@ impl Runtime {
config.node_subname(entrypoint),
new_node_id.0
);
self.node_configure_instance(new_node_id, &new_node_name, label);
self.node_configure_instance(new_node_id, &new_node_name, label, &[]);
let initial_handle = new_node_proxy
.runtime
.new_abi_handle(new_node_proxy.node_id, reader.clone());
Expand Down Expand Up @@ -1232,12 +1261,19 @@ impl Runtime {
}

/// Configure data structures for a Node instance.
fn node_configure_instance(&self, node_id: NodeId, node_name: &str, label: &Label) {
fn node_configure_instance(
&self,
node_id: NodeId,
node_name: &str,
label: &Label,
can_downgrade_tags: &[Tag],
) {
self.add_node_info(
node_id,
NodeInfo {
name: node_name.to_string(),
label: label.clone(),
can_downgrade_tags: can_downgrade_tags.iter().cloned().collect(),
abi_handles: HashMap::new(),
join_handle: None,
},
Expand Down
Loading

0 comments on commit d7bb404

Please sign in to comment.