Skip to content

Commit

Permalink
doc: trd: storage permissions
Browse files Browse the repository at this point in the history
  • Loading branch information
bradjc committed Jun 6, 2024
1 parent 7d05810 commit fcb5c80
Showing 1 changed file with 174 additions and 0 deletions.
174 changes: 174 additions & 0 deletions doc/reference/trd-storage-permissions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
Application Persistent Data Storage Permissions
===============================================

**TRD:** <br/>
**Working Group:** Kernel<br/>
**Type:** Documentary<br/>
**Status:** Draft <br/>
**Author:** Brad Campbell<br/>
**Draft-Created:** 2024/06/06<br/>
**Draft-Modified:** 2024/06/06<br/>
**Draft-Version:** 1<br/>
**Draft-Discuss:** [email protected]<br/>


Abstract
-------------------------------

Tock supports storing persistent state for applications, and all persistent
state in Tock is identified based on the application that stored it. Tock
supports permissions for persistent state, allowing for the kernel to restrict
which applications can store state and which applications can read stored state.
This TRD describes the permissions architecture for persistent state in Tock.
This document is in full compliance with [TRD1][TRD1].


1 Introduction
-------------------------------

Tock applications need to be able to store persistent state. Additionally,
applications need to be able to keep data private from other applications. The
kernel should also be able to allow specific applications to read and modify
state from other applications.

This requires a method for assigning applications persistent identifiers,
a mechanism for granting storage permissions to specific applications,
and kernel abstractions for implementing storage capsules that respect
the storage permissions.


2 Scope
-------------------------------

This document only describes the permission architecture in Tock for supporting
application persistent storage. This document does not include specific types of
persistent storage (e.g., flash, FRAM, etc.) or storage access abstractions
(e.g., block-access, byte-access, etc.).


3 Permissions
-------------------------------

All persistent application data is labeled based on the application which wrote
the data. By default, applications can always read and modify data they wrote.
Applications can read and modify data from other applications with suitable
permissions.

There are three types of permissions:

1. **Write**: The application can write data.
1. **Read**: The application can read other applications' data.
1. **Modify**: The application can modify other applications' data.

Each permission type is independent. For example, an application can be given
read permission for specific data but not be able to write new data itself.


4 Requirements
-------------------------------

The Tock storage model imposes the following requirements:

1. Applications are given separate write, read, and modify permissions.
2. The label stored with the persistent data when the data are written is the
application's short AppID.
3. Applications without a `ShortId::Fixed` cannot access (i.e.,
read/write/modify) any persistent storage.
4. How permissions are mapped to applications must be customizable for different
Tock kernels.
5. Applications have read and modify permissions for data they wrote by default.
If an application should not be able to read and/or modify state it wrote,
the permission mechanism must make this explicit.

Additionally, the kernel itself can be given permission to store state.

### 4.1 Stored State Identifiers

All shared persistent storage implementations must store a 32 bit identifier
with each stored object to mark the application that created the stored object.

When applications write data, their ShortId must be used as the identifier. When
the kernel writes data, the identifier must be 0.

### 4.2 ShortId Implications

As all persistent state written by applications is marked with the writing
application's ShortId, the assignment mechanism for ShortIds is tightly coupled
with the access policies for persistent state. This coupling is intentional as
AppIDs are unique to specific applications. However, as ShortIds are only 32
bits, it is not possible to assign a globally unique ShortId to all
applications. Therefore, board authors should be intentional with how ShortIds
are assigned when persistent storage is accessible to userspace.

In particular, two potentially problematic cases can arise:

1. A ShortId is re-used for different applications. This might happen if one
application is discontinued and a new application is assigned the same
ShortId. The new application would then have unconditional access to any
state the old application stored.
2. A new ShortId is used for the same application. This might happen if the
ShortId assignment algorithm changes. The same application then would lose
access to data it previously stored.


5 Kernel Enforcement
-------------------------------

It is not feasible to implement all persistent storage APIs through the core
kernel (i.e., in trusted code). Instead, the kernel provides an API to retrieve
the storage permissions for a specific process. Capsules then use these
permissions to enforce restrictions on storage access.

Storage permissions are objects that implement the `StoragePermissions` trait.
The trait allows for storage implementations (e.g. capsules) to check
per-application permissions for read and modify operations on stored state, as
well as if the application has permission to write new state.

```rust
/// Interface for checking permissions to access persistent storage.
trait StoragePermissions {
/// Check if these storage permissions grant read access to the stored state
/// marked with identifier `stored_id`.
fn check_read_permission(&self, stored_id: u32) -> bool;

/// Check if these storage permissions grant modify access to the stored
/// state marked with identifier `stored_id`.
fn check_modify_permission(&self, stored_id: u32) -> bool;

/// Retrieve the identifier to use when storing state, if the application
/// has permission to write. Returns `None` if the application cannot write.
fn get_write_id(&self) -> Option<u32>;
}
```


6 Specifying Permissions
-------------------------------

Different users and different kernels will use different methods for determining
the persistent storage access permissions for different applications (and by
extensions the running process for that application). The following are some
examples of how storage permissions may be specified.

1. In TBF headers. The `StoragePermissions` TBF header allows a developer to
specify storage permissions when the app is compiled. Using this method
assumes the kernel can trust the application's headers, perhaps because the
kernel only runs apps signed by a trusted party that has verified the TBF
headers.
2. Within the kernel. The kernel can maintain a data structure of permissions
for known applications. This should be coupled with the AppID mechanism to
consistently assign storage permissions to applications based on their
persistent identifier.
3. With a generic policy. The kernel may permit all applications with a fixed
ShortId to use persistent storage. This method can isolate applications by
only permitting read and modify access to state stored by the same
application.


7 Authors' Addresses
===============================
```
Brad Campbell <[email protected]>
```

[TRD1]: trd1-trds.md "Tock Reference Document (TRD) Structure and Keywords"

0 comments on commit fcb5c80

Please sign in to comment.