Skip to main content

executable/
lib.rs

1#![no_std]
2
3extern crate alloc;
4
5#[cfg(feature = "building")]
6mod building;
7mod error;
8mod standard;
9mod traits;
10
11#[cfg(feature = "building")]
12pub use building::*;
13pub use error::*;
14pub use file_system as exported_file_system;
15pub use standard::*;
16pub use task as exported_task;
17pub use traits::*;
18pub use virtual_file_system as exported_virtual_file_system;
19
20use alloc::{string::String, vec::Vec};
21use file_system::{AccessFlags, Path, Permission, Statistics};
22use task::{JoinHandle, SpawnerIdentifier, TaskIdentifier};
23use users::UserIdentifier;
24use virtual_file_system::File;
25
26async fn is_execute_allowed(statistics: &Statistics, user: UserIdentifier) -> bool {
27    if statistics
28        .permissions
29        .get_others()
30        .contains(Permission::Execute)
31    {
32        return true;
33    }
34
35    let is_user_allowed = user == UserIdentifier::ROOT || user == statistics.user;
36    if is_user_allowed
37        && statistics
38            .permissions
39            .get_user()
40            .contains(Permission::Execute)
41    {
42        return true;
43    }
44
45    let is_in_group = users::get_instance()
46        .is_in_group(user, statistics.group)
47        .await
48        || user == UserIdentifier::ROOT;
49    if (is_in_group)
50        && statistics
51            .permissions
52            .get_group()
53            .contains(Permission::Execute)
54    {
55        return true;
56    }
57
58    false
59}
60
61async fn get_overridden_user(
62    statistics: &Statistics,
63    task: TaskIdentifier,
64) -> Result<Option<UserIdentifier>> {
65    if !statistics
66        .permissions
67        .get_special()
68        .get_set_user_identifier()
69    {
70        return Ok(None);
71    }
72
73    let current_user = task::get_instance().get_user(task).await?;
74
75    let new_user = statistics.user;
76
77    if current_user != users::UserIdentifier::ROOT || new_user != current_user {
78        return Err(Error::PermissionDenied);
79    }
80
81    Ok(Some(new_user))
82}
83
84pub async fn execute(
85    path: impl AsRef<Path>,
86    inputs: Vec<String>,
87    standard: Standard,
88    spawner: Option<SpawnerIdentifier>,
89) -> Result<JoinHandle<isize>> {
90    let task_instance = task::get_instance();
91
92    let task = task_instance.get_current_task_identifier().await;
93
94    let virtual_file_system = virtual_file_system::get_instance();
95
96    let statistics = virtual_file_system.get_statistics(&path.as_ref()).await?;
97
98    // - Check the executable bit
99    if !is_execute_allowed(&statistics, task_instance.get_user(task).await?).await {
100        return Err(Error::PermissionDenied);
101    }
102
103    let mut file = File::open(virtual_file_system, task, &path, AccessFlags::Read.into()).await?;
104
105    // - Check if the user can override the user identifier
106    let new_user = get_overridden_user(&statistics, task).await?;
107
108    let file_name = path
109        .as_ref()
110        .get_file_name()
111        .ok_or(virtual_file_system::Error::InvalidPath)?;
112
113    let main_function: MainFunction = file.control(GET_MAIN_FUNCTION, &()).await?;
114
115    let main = main_function.ok_or(Error::FailedToGetMainFunction)?;
116
117    let (join_handle, _) = task_instance
118        .spawn(task, file_name, spawner, async move |task| {
119            if let Some(new_user) = new_user {
120                task::get_instance().set_user(task, new_user).await.unwrap();
121            }
122
123            match main(standard, inputs).await {
124                Ok(_) => 0_isize,
125                Err(error) => -(error.get() as isize),
126            }
127        })
128        .await?;
129
130    Ok(join_handle)
131}
132
133#[cfg(test)]
134mod tests {
135    extern crate std;
136
137    use file_system::{Permissions, Time};
138
139    use task::test;
140    use users::GroupIdentifier;
141
142    use super::*;
143
144    fn get_statistics_with_permissions(permissions: Permissions) -> Statistics {
145        Statistics::new(
146            0,
147            1,
148            0,
149            Time::new(0),
150            Time::new(0),
151            Time::new(0),
152            Time::new(0),
153            file_system::Kind::File,
154            permissions,
155            UserIdentifier::ROOT,
156            GroupIdentifier::ROOT,
157        )
158    }
159
160    #[test]
161    async fn test_is_execute_allowed() {
162        users::initialize();
163
164        let statistics = get_statistics_with_permissions(Permissions::ALL_FULL);
165        assert!(is_execute_allowed(&statistics, UserIdentifier::ROOT).await);
166
167        let statistics = get_statistics_with_permissions(Permissions::EXECUTABLE);
168        assert!(is_execute_allowed(&statistics, UserIdentifier::ROOT).await);
169
170        let statistics = get_statistics_with_permissions(Permissions::from_octal(0o007).unwrap());
171        assert!(is_execute_allowed(&statistics, UserIdentifier::ROOT).await);
172
173        let statistics = get_statistics_with_permissions(Permissions::from_octal(0o070).unwrap());
174        assert!(is_execute_allowed(&statistics, UserIdentifier::ROOT).await);
175
176        let statistics = get_statistics_with_permissions(Permissions::from_octal(0o100).unwrap());
177        assert!(is_execute_allowed(&statistics, UserIdentifier::ROOT).await);
178
179        let statistics = get_statistics_with_permissions(Permissions::USER_READ_WRITE);
180        assert!(!is_execute_allowed(&statistics, UserIdentifier::ROOT).await);
181
182        let statistics = get_statistics_with_permissions(Permissions::NONE);
183        assert!(!is_execute_allowed(&statistics, UserIdentifier::ROOT).await);
184
185        let statistics = get_statistics_with_permissions(Permissions::ALL_READ_WRITE);
186        assert!(!is_execute_allowed(&statistics, UserIdentifier::ROOT).await);
187    }
188}