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