Skip to content

Commit

Permalink
Check labels when operating on channels
Browse files Browse the repository at this point in the history
  • Loading branch information
tiziano88 committed Mar 30, 2020
1 parent a005757 commit f947b30
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 18 deletions.
2 changes: 2 additions & 0 deletions oak/proto/oak_api.proto
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ enum OakStatus {
ERR_TERMINATED = 9;
// Channel has no messages available to read.
ERR_CHANNEL_EMPTY = 10;
// The node does not have sufficient permissions to perform the requested operation.
ERR_PERMISSION_DENIED = 11;
}

// Single byte values used to indicate the read status of a channel on the
Expand Down
2 changes: 1 addition & 1 deletion oak/server/rust/oak_runtime/src/runtime/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ pub struct Channel {
/// This is set at channel creation time and does not change after that.
///
/// See https://github.com/project-oak/oak/blob/master/docs/concepts.md#labels
label: oak_abi::label::Label,
pub label: oak_abi::label::Label,
}

/// A reference to a [`Channel`]. Each [`Handle`] has an implicit direction such that it is only
Expand Down
101 changes: 84 additions & 17 deletions oak/server/rust/oak_runtime/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ struct Node {
/// This is set at node creation time and does not change after that.
///
/// See https://github.com/project-oak/oak/blob/master/docs/concepts.md#labels
// TODO(#630): Remove exception when label tracking is implemented.
#[allow(dead_code)]
label: oak_abi::label::Label,

/// A [`HashSet`] containing all the handles associated with this Node.
Expand Down Expand Up @@ -155,7 +153,7 @@ impl Runtime {
// will prevent additional nodes from starting to wait again, because `wait_on_channels`
// will return immediately with `OakStatus::ErrTerminated`.
let instances: Vec<_> = {
let mut nodes = self.nodes.write().unwrap();
let mut nodes = self.nodes.write().expect("could not acquire lock on nodes");
self.terminating.store(true, SeqCst);

nodes
Expand Down Expand Up @@ -205,10 +203,8 @@ impl Runtime {
return;
}

let nodes = self.nodes.read().unwrap();
let node = nodes
.get(&node_id)
.expect("Invalid node_id passed into track_handles_in_node!");
let nodes = self.nodes.read().expect("could not acquire lock on nodes");
let node = nodes.get(&node_id).expect("invalid node_id");

let mut tracked_handles = node.handles.lock().unwrap();
for handle in handles {
Expand All @@ -223,12 +219,13 @@ impl Runtime {
return Ok(());
}

let nodes = self.nodes.read().unwrap();
let nodes = self.nodes.read().expect("could not acquire lock on nodes");
// Lookup the node_id in the runtime's nodes hashmap
let node = nodes
.get(&node_id)
.expect("Invalid node_id passed into validate_handle_access!");
let tracked_handles = node.handles.lock().unwrap();
let node = nodes.get(&node_id).expect("invalid node_id");
let tracked_handles = node
.handles
.lock()
.expect("could not acquire lock on tracked handles");

// Check the handle exists in the handles associated with a node, otherwise
// return None.
Expand All @@ -255,12 +252,13 @@ impl Runtime {
return Ok(());
}

let nodes = self.nodes.read().unwrap();
let node = nodes
.get(&node_id)
.expect("Invalid node_id passed into filter_optional_handles!");
let nodes = self.nodes.read().expect("could not acquire lock on nodes");
let node = nodes.get(&node_id).expect("invalid node_id");

let tracked_handles = node.handles.lock().unwrap();
let tracked_handles = node
.handles
.lock()
.expect("could not acquire lock on node handles");
for optional_handle in handles {
if let Some(handle) = optional_handle {
// Check handle is accessible by the node.
Expand All @@ -276,6 +274,66 @@ impl Runtime {
Ok(())
}

fn validate_can_read_from_channel(
&self,
node_id: NodeId,
channel_handle: Handle,
) -> Result<(), OakStatus> {
let nodes = self.nodes.read().expect("could not acquire lock on nodes");
let node = nodes.get(&node_id).expect("invalid node_id");
let node_label = &node.label;

let channel_label = self.channels.with_channel(
self.channels.get_reader_channel(channel_handle)?,
|channel| Ok(channel.label.clone()),
)?;

if channel_label.flows_to(node_label) {
Ok(())
} else {
Err(OakStatus::ErrPermissionDenied)
}
}

fn validate_can_read_from_channels<I>(
&self,
node_id: NodeId,
channel_handles: I,
) -> Result<(), OakStatus>
where
I: IntoIterator<Item = Handle>,
{
if channel_handles.into_iter().all(|channel_handle| {
self.validate_can_read_from_channel(node_id, channel_handle)
.is_ok()
}) {
Ok(())
} else {
Err(OakStatus::ErrPermissionDenied)
}
}

fn validate_can_write_to_channel(
&self,
node_id: NodeId,
channel_handle: Handle,
) -> Result<(), OakStatus> {
let nodes = self.nodes.read().expect("could not acquire lock on nodes");
let node = nodes.get(&node_id).expect("invalid node_id");
let node_label = &node.label;

let channel_label = self.channels.with_channel(
self.channels.get_writer_channel(channel_handle)?,
|channel| Ok(channel.label.clone()),
)?;

if node_label.flows_to(&channel_label) {
Ok(())
} else {
Err(OakStatus::ErrPermissionDenied)
}
}

/// Creates a new [`Channel`] and returns a `(writer handle, reader handle)` pair.
pub fn new_channel(&self, node_id: NodeId, label: &oak_abi::label::Label) -> (Handle, Handle) {
let (writer, reader) = self.channels.new_channel(label);
Expand Down Expand Up @@ -321,6 +379,10 @@ impl Runtime {
readers: &[Option<Handle>],
) -> Result<Vec<ChannelReadStatus>, OakStatus> {
self.validate_handles_access(node_id, readers.iter())?;
self.validate_can_read_from_channels(
node_id,
readers.iter().filter_map(|x| x.as_ref()).copied(),
)?;

let thread = thread::current();
while !self.is_terminating() {
Expand Down Expand Up @@ -380,6 +442,7 @@ impl Runtime {
msg: Message,
) -> Result<(), OakStatus> {
self.validate_handle_access(node_id, reference)?;
self.validate_can_write_to_channel(node_id, reference)?;
self.channels.with_channel(self.channels.get_writer_channel(reference)?, |channel|{

if channel.is_orphan() {
Expand Down Expand Up @@ -445,6 +508,7 @@ impl Runtime {
reference: Handle,
) -> Result<Option<Message>, OakStatus> {
self.validate_handle_access(node_id, reference)?;
self.validate_can_read_from_channel(node_id, reference)?;
self.channels
.with_channel(self.channels.get_reader_channel(reference)?, |channel| {
let mut messages = channel.messages.write().unwrap();
Expand Down Expand Up @@ -474,6 +538,7 @@ impl Runtime {
reference: Handle,
) -> Result<ChannelReadStatus, OakStatus> {
self.validate_handle_access(node_id, reference)?;
self.validate_can_read_from_channel(node_id, reference)?;
self.channels
.with_channel(self.channels.get_reader_channel(reference)?, |channel| {
let messages = channel.messages.read().unwrap();
Expand Down Expand Up @@ -502,6 +567,7 @@ impl Runtime {
handles_capacity: usize,
) -> Result<Option<ReadStatus>, OakStatus> {
self.validate_handle_access(node_id, reference)?;
self.validate_can_read_from_channel(node_id, reference)?;
let result = self.channels
.with_channel(self.channels.get_reader_channel(reference)?, |channel| {
let mut messages = channel.messages.write().unwrap();
Expand Down Expand Up @@ -548,6 +614,7 @@ impl Runtime {
reference: Handle,
) -> Result<HandleDirection, OakStatus> {
self.validate_handle_access(node_id, reference)?;
self.validate_can_read_from_channel(node_id, reference)?;
{
let readers = self.channels.readers.read().unwrap();
if readers.contains_key(&reference) {
Expand Down
3 changes: 3 additions & 0 deletions sdk/rust/oak/src/io/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,8 @@ pub fn error_from_nonok_status(status: OakStatus) -> io::Error {
OakStatus::ErrInternal => io::Error::new(io::ErrorKind::Other, "Internal error"),
OakStatus::ErrTerminated => io::Error::new(io::ErrorKind::Other, "Node terminated"),
OakStatus::ErrChannelEmpty => io::Error::new(io::ErrorKind::UnexpectedEof, "Channel empty"),
OakStatus::ErrPermissionDenied => {
io::Error::new(io::ErrorKind::PermissionDenied, "Permission denied")
}
}
}

0 comments on commit f947b30

Please sign in to comment.