gaol/
profile.rs

1// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! Sandbox profiles—lists of permitted operations.
12
13use platform;
14
15use std::path::PathBuf;
16
17/// A sandbox profile, which specifies the set of operations that this process is allowed to
18/// perform. Operations not in the list are implicitly prohibited.
19///
20/// If the process attempts to perform an operation in the list that this platform can prohibit
21/// after the sandbox is entered via `activate()`, the operation will either fail or the process
22/// will be immediately terminated. You can check whether an operation can be prohibited on this
23/// platform with `Operation::prohibition_support()`.
24///
25/// All profiles implicitly prohibit *at least* the following operations. Future versions of `gaol`
26/// may add operations to selectively allow these.
27///
28///    * Opening any file for writing.
29///
30///    * Creating new processes.
31///
32///    * Opening named pipes or System V IPC resources.
33///
34///    * Accessing System V semaphores.
35///
36///    * Sending signals to other processes.
37///
38///    * Tracing other processes.
39///
40///    * Accepting inbound network connections.
41///
42///    * Any operation that requires superuser privileges on the current operating system.
43///
44/// All profiles implicitly *allow* the following operations:
45///
46///    * All pure computation (user-mode CPU instructions that do not cause a context switch to
47///      supervisor mode).
48///
49///    * Memory allocation (for example, via `brk` or anonymous `mmap` on Unix).
50///
51///    * Use of synchronization primitives (mutexes, condition variables).
52///
53///    * Changing memory protection and use policies: for example, marking pages non-writable or
54///      informing the kernel that memory pages may be discarded. (It may be possible to restrict
55///      this in future versions.)
56///
57///    * Spawning new threads.
58///
59///    * Responding to signals (e.g. `signal`, `sigaltstack`).
60///
61///    * Read, write, and memory map of already-opened file descriptors or handles.
62///
63///    * Determining how much has been sent on a file descriptor.
64///
65///    * Sending or receiving on already-opened sockets, including control messages on Unix.
66///
67///    * I/O multiplexing on already-opened sockets and/or file descriptors (`select`/`poll`).
68///
69///    * Opening and closing file descriptors and sockets (but not necessarily connecting them
70///      to anything).
71///
72///    * Determining the user ID.
73///
74///    * Querying and altering thread scheduling options such as CPU affinity.
75///
76///    * Exiting the process.
77///
78/// Because of platform limitations, patterns within one profile are not permitted to overlap; the
79/// behavior is undefined if they do. For example, you may not allow metadata reads of the subpath
80/// rooted at `/dev` while allowing full reads of `/dev/null`; you must instead allow full reads of
81/// `/dev` or make the profile more restrictive.
82#[derive(Clone, Debug)]
83pub struct Profile {
84    allowed_operations: Vec<Operation>,
85}
86
87/// An operation that this process is allowed to perform.
88#[derive(Clone, Debug)]
89pub enum Operation {
90    /// All file-related reading operations may be performed on this file.
91    FileReadAll(PathPattern),
92    /// Metadata (for example, `stat` or `readlink`) of this file may be read.
93    FileReadMetadata(PathPattern),
94    /// Outbound network connections to the given address may be initiated.
95    NetworkOutbound(AddressPattern),
96    /// System information may be read (via `sysctl` on Unix).
97    SystemInfoRead,
98    /// Platform-specific operations.
99    PlatformSpecific(platform::Operation),
100}
101
102/// Describes a path or paths on the filesystem.
103#[derive(Clone, Debug)]
104pub enum PathPattern {
105    /// One specific path.
106    Literal(PathBuf),
107    /// A directory and all of its contents, recursively.
108    Subpath(PathBuf),
109}
110
111/// Describes a network address.
112#[derive(Clone, Debug)]
113pub enum AddressPattern {
114    /// All network addresses.
115    All,
116    /// TCP connections on the given port.
117    Tcp(u16),
118    /// A local socket at the given path (for example, a Unix socket).
119    LocalSocket(PathBuf),
120}
121
122impl Profile {
123    /// Creates a new profile with the given set of allowed operations.
124    ///
125    /// If the operations cannot be allowed precisely on this platform, this returns an error. You
126    /// can then inspect the operations via `OperationSupport::support()` to see which ones cannot
127    /// be allowed and modify the set of allowed operations as necessary. We are deliberately
128    /// strict here to reduce the probability of applications accidentally allowing operations due
129    /// to platform limitations.
130    pub fn new(allowed_operations: Vec<Operation>) -> Result<Profile,()> {
131        if allowed_operations.iter().all(|operation| {
132            match operation.support() {
133                OperationSupportLevel::NeverAllowed | OperationSupportLevel::CanBeAllowed => true,
134                OperationSupportLevel::CannotBeAllowedPrecisely |
135                OperationSupportLevel::AlwaysAllowed => false,
136            }
137        }) {
138            Ok(Profile {
139                allowed_operations: allowed_operations,
140            })
141        } else {
142            Err(())
143        }
144    }
145
146    /// Returns the list of allowed operations.
147    pub fn allowed_operations(&self) -> &[Operation] {
148        self.allowed_operations.as_slice()
149    }
150}
151
152/// How precisely an operation can be allowed on this platform.
153#[derive(Copy, Clone, Debug, PartialEq)]
154pub enum OperationSupportLevel {
155    /// This operation is never allowed on this platform.
156    NeverAllowed,
157    /// This operation can be precisely allowed on this platform.
158    CanBeAllowed,
159    /// This operation cannot be allowed precisely on this platform, but another set of operations
160    /// allows it to be allowed on a more coarse-grained level. For example, on Linux, it is not
161    /// possible to allow access to specific ports, but it is possible to allow network access
162    /// entirely.
163    CannotBeAllowedPrecisely,
164    /// This operation is always allowed on this platform.
165    AlwaysAllowed,
166}
167
168/// Allows operations to be queried to determine how precisely they can be allowed on this
169/// platform.
170pub trait OperationSupport {
171    /// Returns an `OperationSupportLevel` describing how well this operation can be allowed on
172    /// this platform.
173    fn support(&self) -> OperationSupportLevel;
174}
175