Skip to content

Commit

Permalink
Assign labels on channel creation
Browse files Browse the repository at this point in the history
Expand `channel_create` host function call to accept a Label parameter,
similar to `node_create`.

Add `Client::new_with_label` method to allow creating a gRPC client
pseudo-node at a specific IFC label. This will act as a
declassification, once more IFC rules are implemented in the Runtime.

Fix aggregator example documentation.

Ref project-oak#972 project-oak#630
  • Loading branch information
tiziano88 committed May 11, 2020
1 parent 32337e5 commit 61180e8
Show file tree
Hide file tree
Showing 16 changed files with 230 additions and 78 deletions.
21 changes: 15 additions & 6 deletions docs/abi.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,13 +160,21 @@ in Fuchsia.

### channel_create

`channel_create: (usize, usize) -> u32` creates a new unidirectional channel and
return the channel handles for its read and write halves.
`channel_create: (usize, usize, usize, usize) -> u32` creates a new
unidirectional channel assigning the label specified by args 2 and 3 to the
newly created Channel, and returns the channel handles for its read and write
halves as output parameters in args 0 and 1.

If creating the specified Channel would violate
[information flow control](/docs/concepts.md#labels), returns
`ERR_PERMISSION_DENIED`.

- arg 0: Address of an 8-byte location that will receive the handle for the
write half of the channel (as a little-endian u64).
- arg 1: Address of an 8-byte location that will receive the handle for the read
half of the channel (as a little-endian u64).
- arg 2: Source buffer holding label
- arg 3: Label size in bytes
- return 0: Status of operation

### channel_close
Expand All @@ -180,11 +188,12 @@ return the channel handles for its read and write halves.

`node_create: (usize, usize, usize, usize, usize, usize, u64) -> u32` creates a
new Node running the Node configuration identified by args 0 and 1, using the
entrypoint specified by args 2 and 3, passing in an initial handle to the read
half of a channel identified by arg 4. The entrypoint name is ignored when
creating non-WebAssembly Nodes.
entrypoint specified by args 2 and 3, assigning the label specified by args 4
and 5 to the newly created Node, passing in an initial handle to the read half
of a channel identified by arg 6. The entrypoint name is ignored when creating
non-WebAssembly Nodes.

If creating the specified node would violate
If creating the specified Node would violate
[information flow control](/docs/concepts.md#labels), returns
`ERR_PERMISSION_DENIED`.

Expand Down
37 changes: 26 additions & 11 deletions examples/abitest/module_0/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,24 +365,39 @@ unsafe fn invalid_raw_offset() -> *mut u64 {
fn channel_create_raw() -> (u64, u64, u32) {
let mut w = 0u64;
let mut r = 0u64;
let result = unsafe { oak_abi::channel_create(&mut w as *mut u64, &mut r as *mut u64) };
let label_bytes = Label::public_trusted().serialize();
let result = unsafe {
oak_abi::channel_create(
&mut w as *mut u64,
&mut r as *mut u64,
label_bytes.as_ptr(),
label_bytes.len(),
)
};
(w, r, result)
}

impl FrontendNode {
fn test_channel_create_raw(&mut self) -> TestResult {
let mut write = 0u64;
let mut read = 0u64;
unsafe {
expect_eq!(
OakStatus::ErrInvalidArgs as u32,
oak_abi::channel_create(invalid_raw_offset(), &mut read as *mut u64)
);
expect_eq!(
OakStatus::ErrInvalidArgs as u32,
oak_abi::channel_create(&mut write as *mut u64, invalid_raw_offset())
);
}
let label_bytes = Label::public_trusted().serialize();
expect_eq!(OakStatus::ErrInvalidArgs as u32, unsafe {
oak_abi::channel_create(
invalid_raw_offset(),
&mut read as *mut u64,
label_bytes.as_ptr(),
label_bytes.len(),
)
});
expect_eq!(OakStatus::ErrInvalidArgs as u32, unsafe {
oak_abi::channel_create(
&mut write as *mut u64,
invalid_raw_offset(),
label_bytes.as_ptr(),
label_bytes.len(),
)
});
Ok(())
}

Expand Down
41 changes: 27 additions & 14 deletions examples/aggregator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,12 @@ output.
Build and run the Backend with the following command:

```bash
export RUST_LOG=info
cargo run --release --package=aggregator_backend
```

Backend code is in the `backend` directory.

### Client

Simple client that connects to the Aggregator and sends a data sample via gRPC.

Build and run the Client with the following command:

```bash
./scripts/build_example -e aggregator
./bazel-client-bin/examples/aggregator/client/client --address=127.0.0.1:8080 --bucket=test --data=1:10,2:20,3:30
```

Client code is in the `client` directory.

### Aggregator

Aggregator example for Project Oak.
Expand All @@ -47,13 +35,38 @@ a Sparse Vector - a dictionary with integer keys.
Build and run the Aggregator with the following command:

```bash
./scripts/build_example -e aggregator
./scripts/build_server -s base
./bazel-bin/oak/server/loader/oak_runner --application=./bazel-client-bin/examples/aggregator/config/config.bin
./bazel-clang-bin/oak/server/loader/oak_runner \
--application=./bazel-client-bin/examples/aggregator/config/config.bin \
--private_key=./examples/certs/local/local.key \
--cert_chain=./examples/certs/local/local.pem
```

Aggregator code is in `common` and `module` directories (where `common` defines
a generic Aggregator data structure).

### Client

Simple client that connects to the Aggregator and sends a data sample via gRPC.

Build and run the Client with the following command:

```bash
./scripts/build_example -e aggregator
./bazel-client-bin/examples/aggregator/client/client \
--address=127.0.0.1:8080 \
--ca_cert=./examples/certs/local/local.pem \
--bucket=test \
--data=1:10,2:20,3:30
```

A common use case is to keep running the client until the aggregation threshold
is reached, at which point the aggregator should release the aggregated data to
the backend over gRPC.

Client code is in the `client` directory.

## Deployment

The Aggregator example contains a `gcp/pod.yaml` file which is a config for
Expand Down
1 change: 1 addition & 0 deletions examples/aggregator/module/rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ aggregator_common = { path = "../../common" }
itertools = "*"
log = "*"
oak = "=0.1.0"
oak_abi = "=0.1.0"
prost = "*"

[dev-dependencies]
Expand Down
19 changes: 18 additions & 1 deletion examples/aggregator/module/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ use aggregator_common::ThresholdAggregator;
use data::SparseVector;
use log::{debug, error};
use oak::grpc;
use oak_abi::label::{tag, Label, Tag, TlsEndpointTag};
use proto::{Aggregator, AggregatorClient, AggregatorDispatcher, Sample};
use std::{collections::HashMap, convert::TryFrom};

Expand Down Expand Up @@ -92,7 +93,23 @@ impl AggregatorNode {
bucket, svec
);

match oak::grpc::client::Client::new("grpc-client", "").map(AggregatorClient) {
// Create a gRPC client Node with a less restrictive label than the current Node.
// In particular, the secrecy component of the current Node label includes the "aggregator"
// WebAssembly hash, which is declassified as part of the gRPC client Node creation. This is
// only allowed if the current Node actually has the appropriate capability (i.e. the
// correct WebAssembly module hash) as specified by the label component being removed, as
// set by the client.
let label = Label {
secrecy_tags: vec![Tag {
tag: Some(tag::Tag::TlsEndpointTag(TlsEndpointTag {
certificate_subject_alternative_name: "google.com".to_string(),
})),
}],
integrity_tags: vec![],
};
match oak::grpc::client::Client::new_with_label("grpc-client", "", &label)
.map(AggregatorClient)
{
Some(grpc_client) => {
let res = grpc_client.submit_sample(Sample {
bucket,
Expand Down
31 changes: 21 additions & 10 deletions oak/server/rust/oak_abi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,15 +109,23 @@ extern "C" {
handle_count: u32,
) -> u32;

/// Create a new unidirectional channel.
/// Create a new unidirectional Channel.
///
/// Returns handles for the the write and read halves of the channel in
/// the spaces given by `write` and `read`.
/// Returns handles for the the write and read halves of the Channel in the spaces given by
/// `write` and `read`.
///
/// The label to assign to the newly created Channel is provided in the memory area given by
/// `label_buf` and `label_len`.
///
/// Returns the status of the operation, as an [`OakStatus`] value.
///
/// [`OakStatus`]: crate::OakStatus
pub fn channel_create(write: *mut u64, read: *mut u64) -> u32;
pub fn channel_create(
write: *mut u64,
read: *mut u64,
label_buf: *const u8,
label_len: usize,
) -> u32;

/// Close a channel.
///
Expand All @@ -128,13 +136,16 @@ extern "C" {
/// [`OakStatus`]: crate::OakStatus
pub fn channel_close(handle: u64) -> u32;

/// Create a new Node instance running code identified by configuration
/// name and entrypoint; the entrypoint is only used when creating a
/// WebAssembly Node; it is ignored when creating a pseudo-Node.
/// Create a new Node instance running code identified by configuration name and entrypoint; the
/// entrypoint is only used when creating a WebAssembly Node; it is ignored when creating a
/// pseudo-Node.
///
/// The configuration name is provided in the memory area given by `config_buf` and
/// `config_len`; the entrypoint name is provided in the memory area given by `entrypoint_buf`
/// and `entrypoint_len`.
///
/// The configuration name is provided in the memory area given by
/// `config_buf` and `config_len`; the entrypoint name is provided in the
/// memory area given by `entrypoint_buf` and `entrypoint_len`.
/// The label to assign to the newly created Node is provided in the memory area given by
/// `label_buf` and `label_len`.
///
/// Returns the status of the operation, as an [`OakStatus`] value.
///
Expand Down
5 changes: 4 additions & 1 deletion oak/server/rust/oak_glue/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,10 @@ pub unsafe extern "C" fn glue_channel_create(node_id: u64, write: *mut u64, read
debug!("{{{}}}: channel_create({:?}, {:?})", node_id, write, read);
let proxy = proxy_for_node(node_id);
let (write_handle, read_handle) =
proxy.channel_create(&oak_abi::label::Label::public_trusted());
match proxy.channel_create(&oak_abi::label::Label::public_trusted()) {
Ok(r) => r,
Err(s) => return s as u32,
};
*write = write_handle;
*read = read_handle;
debug!(
Expand Down
4 changes: 2 additions & 2 deletions oak/server/rust/oak_runtime/src/node/grpc/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,9 +260,9 @@ impl GrpcRequestHandler {
fn handle_grpc_request(&self, request: GrpcRequest) -> Result<oak_abi::Handle, OakStatus> {
// Create a pair of temporary channels to pass the gRPC request and to receive the response.
let (request_writer, request_reader) =
self.runtime.channel_create(&Label::public_trusted());
self.runtime.channel_create(&Label::public_trusted())?;
let (response_writer, response_reader) =
self.runtime.channel_create(&Label::public_trusted());
self.runtime.channel_create(&Label::public_trusted())?;

// Create an invocation message and attach the method-invocation specific channels to it.
//
Expand Down
50 changes: 36 additions & 14 deletions oak/server/rust/oak_runtime/src/node/wasm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,16 +210,18 @@ impl WasmInterface {
self.runtime.channel_close(handle)
}

/// Corresponds to the host ABI function [`channel_create: (usize, usize) ->
/// Corresponds to the host ABI function [`channel_create: (usize, usize, usize, usize) ->
/// u32`](oak_abi::channel_create).
fn channel_create(
&mut self,
write_addr: AbiPointer,
read_addr: AbiPointer,
label_ptr: AbiPointer,
label_length: AbiPointerOffset,
) -> Result<(), OakStatus> {
debug!(
"{}: channel_create({}, {})",
self.pretty_name, write_addr, read_addr
"{}: channel_create({}, {}, {}, {})",
self.pretty_name, write_addr, read_addr, label_ptr, label_length
);

if self.runtime.is_terminating() {
Expand All @@ -230,10 +232,25 @@ impl WasmInterface {
self.validate_ptr(write_addr, 8)?;
self.validate_ptr(read_addr, 8)?;

let (write_handle, read_handle) = self
.runtime
// TODO(#630): Let caller provide this label via the Wasm ABI.
.channel_create(&Label::public_trusted());
let label_bytes = self
.get_memory()
.get(label_ptr, label_length as usize)
.map_err(|err| {
error!(
"{}: channel_create(): Unable to read label from guest memory: {:?}",
self.pretty_name, err
);
OakStatus::ErrInvalidArgs
})?;
let label = Label::deserialize(&label_bytes).ok_or_else(|| {
error!(
"{}: channel_create: could not deserialize label",
self.pretty_name
);
OakStatus::ErrInvalidArgs
})?;

let (write_handle, read_handle) = self.runtime.channel_create(&label)?;

debug!(
"{}: channel_create() -> ({}, {})",
Expand Down Expand Up @@ -501,9 +518,12 @@ impl wasmi::Externals for WasmInterface {
map_host_errors(self.random_get(args.nth_checked(0)?, args.nth_checked(1)?))
}
CHANNEL_CLOSE => map_host_errors(self.channel_close(args.nth_checked(0)?)),
CHANNEL_CREATE => {
map_host_errors(self.channel_create(args.nth_checked(0)?, args.nth_checked(1)?))
}
CHANNEL_CREATE => map_host_errors(self.channel_create(
args.nth_checked(0)?,
args.nth_checked(1)?,
args.nth_checked(2)?,
args.nth_checked(3)?,
)),
CHANNEL_WRITE => map_host_errors(self.channel_write(
args.nth_checked(0)?,
args.nth_checked(1)?,
Expand Down Expand Up @@ -585,8 +605,10 @@ fn oak_resolve_func(
CHANNEL_CREATE,
wasmi::Signature::new(
&[
ABI_USIZE, // write
ABI_USIZE, // read
ABI_USIZE, // write handle (out)
ABI_USIZE, // read handle (out)
ABI_USIZE, // label_buf
ABI_USIZE, // label_len
][..],
Some(ValueType::I32),
),
Expand All @@ -611,10 +633,10 @@ fn oak_resolve_func(
ValueType::I64, // handle
ABI_USIZE, // buf
ABI_USIZE, // size
ABI_USIZE, // actual_size
ABI_USIZE, // actual_size (out)
ABI_USIZE, // handle_buf
ValueType::I32, // handle_count
ABI_USIZE, // actual_handle_count
ABI_USIZE, // actual_handle_count (out)
][..],
Some(ValueType::I32),
),
Expand Down
2 changes: 1 addition & 1 deletion oak/server/rust/oak_runtime/src/node/wasm/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fn start_node<S: AsRef<[u8]>>(buffer: S, entrypoint: &str) -> Result<(), OakStat
},
);
let proxy = RuntimeProxy::create_runtime(configuration);
let (_write_handle, read_handle) = proxy.channel_create(&Label::public_trusted());
let (_write_handle, read_handle) = proxy.channel_create(&Label::public_trusted())?;

let result = proxy.node_create(
"test_module",
Expand Down
Loading

0 comments on commit 61180e8

Please sign in to comment.