kernel/storage_permissions.rs
1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Mechanism for managing storage read & write permissions.
6//!
7//! These permissions are intended for userspace applications so the kernel can
8//! restrict which stored elements the apps have access to.
9
10use crate::capabilities::ApplicationStorageCapability;
11use crate::capabilities::KerneluserStorageCapability;
12
13/// Permissions for accessing persistent storage.
14///
15/// This is a general type capable of representing permissions in different
16/// ways. Users of storage permissions do not need to understand the different
17/// ways permissions are stored internally. Instead, layers that need to enforce
18/// permissions only use the following API:
19///
20/// ```rust,ignore
21/// fn StoragePermissions::check_read_permission(&self, stored_id: u32) -> bool;
22/// fn StoragePermissions::check_modify_permission(&self, stored_id: u32) -> bool;
23/// fn StoragePermissions::get_write_id(&self) -> Option<u32>;
24/// ```
25#[derive(Clone, Copy)]
26pub struct StoragePermissions(StoragePermissionsPrivate);
27
28/// Inner enum type for types of permissions.
29///
30/// Private so permissions can only be created with capability-restricted
31/// constructors.
32#[derive(Clone, Copy)]
33enum StoragePermissionsPrivate {
34 /// This permission grants an application full access to its own stored
35 /// state. The application may write state, and read and modify anything it
36 /// has written.
37 ///
38 /// The `NonZeroU32` is the `ShortId::Fixed` of the application.
39 SelfOnly(core::num::NonZeroU32),
40
41 /// This permission supports setting whether an application can write and
42 /// supports setting up to eight storage identifiers the application can
43 /// read and eight storage identifiers the application can modify. This
44 /// permission also includes a flag allowing an application to read and
45 /// modify its own state.
46 FixedSize(FixedSizePermissions),
47
48 /// This permission supports setting whether an application can write and
49 /// supports storing references to static buffers that contain an arbitrary
50 /// list of storage identifiers the application can read and modify. This
51 /// permission also includes a flag allowing an application to read and
52 /// modify its own state.
53 Listed(ListedPermissions),
54
55 /// This permission is designed for only the kernel use, and allows the
56 /// kernel to store and read/modify its own state. Note, this permission
57 /// does not give the kernel access to application state.
58 Kernel,
59
60 /// This permission grants an application no access to any persistent
61 /// storage.
62 Null,
63}
64
65/// `StoragePermissions` with a fixed size number of read and modify
66/// permissions.
67///
68/// For simplicity, a we store to eight read and eight write permissions. The
69/// first `X_count` `u32` values in `X_permissions` are valid.
70#[derive(Clone, Copy)]
71pub struct FixedSizePermissions {
72 /// The `ShortId::Fixed` of the application these permissions belong to.
73 app_id: core::num::NonZeroU32,
74 /// Whether this permission grants write access.
75 write_permission: bool,
76 /// If true, these permissions grant read and modify access to any stored
77 /// state where this AppId matches the storage identifier.
78 read_modify_self: bool,
79 /// How many entries in the `read_permissions` slice are valid, starting at
80 /// index 0.
81 read_count: usize,
82 /// Up to eight 32 bit identifiers of storage items the process has read
83 /// access to.
84 read_permissions: [u32; 8],
85 /// How many entries in the `modify_permissions` slice are valid, starting
86 /// at index 0.
87 modify_count: usize,
88 /// Up to eight 32 bit identifiers of storage items the process has modify
89 /// (update) access to.
90 modify_permissions: [u32; 8],
91}
92
93/// `StoragePermissions` with arbitrary static arrays holding read and modify
94/// permissions.
95#[derive(Clone, Copy)]
96pub struct ListedPermissions {
97 /// The `ShortId::Fixed` of the application these permissions belong to.
98 app_id: core::num::NonZeroU32,
99 /// Whether this permission grants write access.
100 write_permission: bool,
101 /// If true, these permissions grant read and modify access to any stored
102 /// state where this AppId matches the storage identifier.
103 read_modify_self: bool,
104 /// The 32 bit identifiers of storage items the process can read.
105 read_permissions: &'static [u32],
106 /// The 32 bit identifiers of storage items the process can modify
107 modify_permissions: &'static [u32],
108}
109
110impl StoragePermissions {
111 pub fn new_self_only(
112 short_id_fixed: core::num::NonZeroU32,
113 _cap: &dyn ApplicationStorageCapability,
114 ) -> Self {
115 Self(StoragePermissionsPrivate::SelfOnly(short_id_fixed))
116 }
117
118 pub fn new_fixed_size(
119 app_id: core::num::NonZeroU32,
120 write_permission: bool,
121 read_modify_self: bool,
122 read_count: usize,
123 read_permissions: [u32; 8],
124 modify_count: usize,
125 modify_permissions: [u32; 8],
126 _cap: &dyn ApplicationStorageCapability,
127 ) -> Self {
128 Self(StoragePermissionsPrivate::FixedSize(FixedSizePermissions {
129 app_id,
130 write_permission,
131 read_modify_self,
132 read_count,
133 read_permissions,
134 modify_count,
135 modify_permissions,
136 }))
137 }
138
139 pub fn new_listed(
140 app_id: core::num::NonZeroU32,
141 write_permission: bool,
142 read_modify_self: bool,
143 read_permissions: &'static [u32],
144 modify_permissions: &'static [u32],
145 _cap: &dyn ApplicationStorageCapability,
146 ) -> Self {
147 Self(StoragePermissionsPrivate::Listed(ListedPermissions {
148 app_id,
149 write_permission,
150 read_modify_self,
151 read_permissions,
152 modify_permissions,
153 }))
154 }
155
156 pub fn new_kernel(_cap: &dyn KerneluserStorageCapability) -> Self {
157 Self(StoragePermissionsPrivate::Kernel)
158 }
159
160 pub fn new_null() -> Self {
161 Self(StoragePermissionsPrivate::Null)
162 }
163
164 /// Check if these storage permissions grant read access to the stored state
165 /// marked with identifier `stored_id`.
166 pub fn check_read_permission(&self, stored_id: u32) -> bool {
167 match self.0 {
168 StoragePermissionsPrivate::SelfOnly(id) => stored_id == id.into(),
169 StoragePermissionsPrivate::FixedSize(p) => {
170 (stored_id == p.app_id.into() && p.read_modify_self)
171 || (stored_id != 0
172 && p.read_permissions
173 .get(0..p.read_count)
174 .unwrap_or(&[])
175 .contains(&stored_id))
176 }
177 StoragePermissionsPrivate::Listed(p) => {
178 (stored_id == p.app_id.into() && p.read_modify_self)
179 || (stored_id != 0 && p.read_permissions.contains(&stored_id))
180 }
181 StoragePermissionsPrivate::Kernel => stored_id == 0,
182 StoragePermissionsPrivate::Null => false,
183 }
184 }
185
186 /// Check if these storage permissions grant modify access to the stored
187 /// state marked with identifier `stored_id`.
188 pub fn check_modify_permission(&self, stored_id: u32) -> bool {
189 match self.0 {
190 StoragePermissionsPrivate::SelfOnly(id) => stored_id == id.into(),
191 StoragePermissionsPrivate::FixedSize(p) => {
192 (stored_id == p.app_id.into() && p.read_modify_self)
193 || (stored_id != 0
194 && p.modify_permissions
195 .get(0..p.modify_count)
196 .unwrap_or(&[])
197 .contains(&stored_id))
198 }
199 StoragePermissionsPrivate::Listed(p) => {
200 (stored_id == p.app_id.into() && p.read_modify_self)
201 || (stored_id != 0 && p.modify_permissions.contains(&stored_id))
202 }
203 StoragePermissionsPrivate::Kernel => stored_id == 0,
204 StoragePermissionsPrivate::Null => false,
205 }
206 }
207
208 /// Retrieve the identifier to use when storing state, if the application
209 /// has permission to write. Returns `None` if the application cannot write.
210 pub fn get_write_id(&self) -> Option<u32> {
211 match self.0 {
212 StoragePermissionsPrivate::SelfOnly(id) => Some(id.into()),
213 StoragePermissionsPrivate::FixedSize(p) => {
214 p.write_permission.then_some(p.app_id.into())
215 }
216 StoragePermissionsPrivate::Listed(p) => p.write_permission.then_some(p.app_id.into()),
217 StoragePermissionsPrivate::Kernel => Some(0),
218 StoragePermissionsPrivate::Null => None,
219 }
220 }
221}