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}