capsec_core/permission.rs
1//! The [`Permission`] trait and all built-in permission types.
2//!
3//! Permissions are zero-sized marker types that encode what kind of I/O a
4//! capability token grants. Built-in permissions cover filesystem, network,
5//! environment, and process operations. Library authors can define custom
6//! permissions using `#[capsec::permission]`.
7//!
8//! # Built-in permissions
9//!
10//! | Type | Category | What it grants |
11//! |------|----------|----------------|
12//! | [`FsRead`] | Filesystem | Read files, list directories, check metadata |
13//! | [`FsWrite`] | Filesystem | Write, create, delete files and directories |
14//! | [`FsAll`] | Filesystem | All filesystem operations (subsumes `FsRead` + `FsWrite`) |
15//! | [`NetConnect`] | Network | Open outbound TCP/UDP connections |
16//! | [`NetBind`] | Network | Bind listeners and sockets to local ports |
17//! | [`NetAll`] | Network | All network operations (subsumes `NetConnect` + `NetBind`) |
18//! | [`EnvRead`] | Environment | Read environment variables |
19//! | [`EnvWrite`] | Environment | Modify or remove environment variables |
20//! | [`Spawn`] | Process | Execute subprocesses |
21//! | [`Ambient`] | Everything | Full ambient authority — the "god token" |
22//!
23//! # Custom permissions
24//!
25//! Use `#[capsec::permission]` to define domain-specific permissions:
26//!
27//! ```rust,ignore
28//! #[capsec::permission]
29//! pub struct DbRead;
30//!
31//! #[capsec::permission(subsumes = [DbRead])]
32//! pub struct DbAll;
33//! ```
34//!
35//! # Tuples
36//!
37//! Two permissions can be bundled via a tuple: `(FsRead, NetConnect)` is itself
38//! a `Permission`, and `Cap<(FsRead, NetConnect)>` satisfies both `Has<FsRead>`
39//! and `Has<NetConnect>`. All 2-tuple combinations of built-in permissions are
40//! supported.
41//!
42//! # Subsumption
43//!
44//! Some permissions imply others. [`FsAll`] subsumes both [`FsRead`] and [`FsWrite`],
45//! meaning a `Cap<FsAll>` can be used anywhere a `Cap<FsRead>` is required.
46//! [`Ambient`] subsumes everything.
47
48/// Marker trait for all capability permissions.
49///
50/// Every permission type is a zero-sized struct that implements this trait.
51/// Built-in permissions are defined in this module. Custom permissions can be
52/// defined using the `#[capsec::permission]` derive macro, which generates the
53/// required seal token.
54///
55/// # Direct implementation
56///
57/// Do not implement this trait manually. Use `#[capsec::permission]` instead.
58/// The `__CapsecSeal` associated type is `#[doc(hidden)]` and may change
59/// without notice.
60pub trait Permission: 'static {
61 /// Seal token preventing manual implementation. Do not use directly.
62 #[doc(hidden)]
63 type __CapsecSeal: __private::SealToken;
64}
65
66// Filesystem
67
68/// Permission to read files, list directories, and check metadata.
69pub struct FsRead;
70
71/// Permission to write, create, rename, and delete files and directories.
72pub struct FsWrite;
73
74/// Permission for all filesystem operations. Subsumes [`FsRead`] and [`FsWrite`].
75pub struct FsAll;
76
77// Network
78
79/// Permission to open outbound TCP and UDP connections.
80pub struct NetConnect;
81
82/// Permission to bind TCP listeners and UDP sockets to local ports.
83pub struct NetBind;
84
85/// Permission for all network operations. Subsumes [`NetConnect`] and [`NetBind`].
86pub struct NetAll;
87
88// Environment
89
90/// Permission to read environment variables.
91pub struct EnvRead;
92
93/// Permission to modify or remove environment variables.
94pub struct EnvWrite;
95
96// Process
97
98/// Permission to spawn and execute subprocesses via `std::process::Command`.
99pub struct Spawn;
100
101// Ambient
102
103/// Full ambient authority — grants every permission.
104///
105/// This is the "god token." A `Cap<Ambient>` satisfies any `Has<P>` bound.
106/// Use sparingly and only at the capability root.
107pub struct Ambient;
108
109// Permission impls
110
111impl Permission for FsRead {
112 type __CapsecSeal = __private::SealProof;
113}
114impl Permission for FsWrite {
115 type __CapsecSeal = __private::SealProof;
116}
117impl Permission for FsAll {
118 type __CapsecSeal = __private::SealProof;
119}
120impl Permission for NetConnect {
121 type __CapsecSeal = __private::SealProof;
122}
123impl Permission for NetBind {
124 type __CapsecSeal = __private::SealProof;
125}
126impl Permission for NetAll {
127 type __CapsecSeal = __private::SealProof;
128}
129impl Permission for EnvRead {
130 type __CapsecSeal = __private::SealProof;
131}
132impl Permission for EnvWrite {
133 type __CapsecSeal = __private::SealProof;
134}
135impl Permission for Spawn {
136 type __CapsecSeal = __private::SealProof;
137}
138impl Permission for Ambient {
139 type __CapsecSeal = __private::SealProof;
140}
141
142// Tuple permissions
143
144impl<A: Permission, B: Permission> Permission for (A, B) {
145 type __CapsecSeal = __private::SealProof;
146}
147
148// Subsumption
149
150/// Indicates that `Self` implies permission `P`.
151///
152/// When `Super: Subsumes<Sub>`, a `Cap<Super>` can satisfy `Has<Sub>`.
153/// For example, `FsAll: Subsumes<FsRead>` means `Cap<FsAll>` works
154/// anywhere `Has<FsRead>` is required.
155pub trait Subsumes<P: Permission>: Permission {}
156
157impl Subsumes<FsRead> for FsAll {}
158impl Subsumes<FsWrite> for FsAll {}
159impl Subsumes<NetConnect> for NetAll {}
160impl Subsumes<NetBind> for NetAll {}
161impl<P: Permission> Subsumes<P> for Ambient {}
162
163// Seal token — prevents manual Permission implementation.
164// The #[capsec::permission] macro generates the correct seal.
165// The private field on SealProof prevents external construction —
166// only `__capsec_seal()` can create one, and it's #[doc(hidden)].
167
168#[doc(hidden)]
169pub mod __private {
170 /// Proof token that a permission was registered via the capsec derive macro.
171 ///
172 /// Has a private field — cannot be constructed outside this module.
173 /// Use `__capsec_seal()` (generated by `#[capsec::permission]`) instead.
174 pub struct SealProof(());
175
176 /// Trait bound for the seal associated type.
177 pub trait SealToken {}
178 impl SealToken for SealProof {}
179
180 /// Creates a seal proof. Only called by `#[capsec::permission]` generated code.
181 #[doc(hidden)]
182 pub const fn __capsec_seal() -> SealProof {
183 SealProof(())
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190 use std::mem::size_of;
191
192 #[test]
193 fn all_permissions_are_zst() {
194 assert_eq!(size_of::<FsRead>(), 0);
195 assert_eq!(size_of::<FsWrite>(), 0);
196 assert_eq!(size_of::<FsAll>(), 0);
197 assert_eq!(size_of::<NetConnect>(), 0);
198 assert_eq!(size_of::<NetBind>(), 0);
199 assert_eq!(size_of::<NetAll>(), 0);
200 assert_eq!(size_of::<EnvRead>(), 0);
201 assert_eq!(size_of::<EnvWrite>(), 0);
202 assert_eq!(size_of::<Spawn>(), 0);
203 assert_eq!(size_of::<Ambient>(), 0);
204 }
205
206 // Compile-time proof that subsumption relationships hold:
207 fn _assert_subsumes<Super: Subsumes<Sub>, Sub: Permission>() {}
208
209 #[test]
210 fn tuple_permission_is_zst() {
211 assert_eq!(size_of::<(FsRead, NetConnect)>(), 0);
212 }
213
214 #[test]
215 fn subsumption_relationships() {
216 _assert_subsumes::<FsAll, FsRead>();
217 _assert_subsumes::<FsAll, FsWrite>();
218 _assert_subsumes::<NetAll, NetConnect>();
219 _assert_subsumes::<NetAll, NetBind>();
220 _assert_subsumes::<Ambient, FsRead>();
221 _assert_subsumes::<Ambient, NetConnect>();
222 _assert_subsumes::<Ambient, Spawn>();
223 }
224}