Skip to content

Commit

Permalink
Check the execution permission in the execution engine before running.
Browse files Browse the repository at this point in the history
  • Loading branch information
ShaleXIONG committed Nov 2, 2023
1 parent b683b8b commit 32bd148
Show file tree
Hide file tree
Showing 8 changed files with 38 additions and 66 deletions.
2 changes: 1 addition & 1 deletion crates/execution-engine/src/engines/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
//! information on licensing and copyright.

use anyhow::Result;
use std::vec::Vec;
use std::path::Path;

////////////////////////////////////////////////////////////////////////////////
// The strategy trait.
Expand Down
8 changes: 4 additions & 4 deletions crates/execution-engine/src/engines/wasmtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::{
use anyhow::Result;
use log::info;
use std::{
vec::Vec,
path::Path,
fs::{create_dir_all, File},
};
use wasmtime::{Config, Engine, Linker, Module, Store};
Expand Down Expand Up @@ -70,7 +70,7 @@ impl ExecutionEngine for WasmtimeRuntimeState {
/// program, along with a host state capturing the result of the program's
/// execution.
#[inline]
fn invoke_entry_point(&mut self, program: Vec<u8>) -> Result<u32> {
fn serve(&mut self, input: &Path) -> Result<()> {
info!("Initialize a wasmtime engine.");

let mut config = Config::default();
Expand Down Expand Up @@ -98,7 +98,7 @@ impl ExecutionEngine for WasmtimeRuntimeState {

let wasi = wasm_build.build();
let mut store = Store::new(&engine, wasi);
let module = Module::new(&engine, program)?;
let module = Module::from_file(&engine, input)?;
linker.module(&mut store, "", &module)?;

info!("Engine readies.");
Expand All @@ -114,6 +114,6 @@ impl ExecutionEngine for WasmtimeRuntimeState {

info!("Execution returns.");

Ok(0)
Ok(())
}
}
7 changes: 4 additions & 3 deletions crates/execution-engine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,10 @@ pub struct Environment {
/// such as `freestanding-execution-engine` and `runtime-manager` can rely on.
pub fn execute(
strategy: &ExecutionStrategy,
permissions: &PrincipalPermission,
caller_permissions: &PrincipalPermission,
execution_permissions: &PrincipalPermission,
pipeline: Box<Expr>,
env: &Environment,
) -> anyhow::Result<u32> {
Ok(pipeline::execute_pipeline(strategy, permissions, pipeline, env)?)
) -> anyhow::Result<()> {
pipeline::execute_pipeline(strategy, caller_permissions, execution_permissions, pipeline, env)
}
1 change: 0 additions & 1 deletion crates/execution-engine/src/native_modules/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
use anyhow::Result;
use crate::{
native_modules::{echo::EchoService, postcard::PostcardService, aes::AesCounterModeService}

};
use std::{fs::{create_dir_all, remove_file}, sync::Once, path::{Path, PathBuf}, thread::{spawn, JoinHandle}};
use log::info;
Expand Down
45 changes: 21 additions & 24 deletions crates/execution-engine/src/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ use anyhow::{anyhow, Result};
use log::info;
use policy_utils::{
pipeline::Expr,
principal::{PrincipalPermission, ExecutionStrategy, NativeModule, NativeModuleType},
principal::{PrincipalPermission, FilePermissions, ExecutionStrategy, NativeModule, NativeModuleType, check_permission},
};
use std::{boxed::Box, path::{Path, PathBuf}, fs};
use std::{boxed::Box, path::{Path, PathBuf}};

/// Returns whether the given path corresponds to a WASM binary.
fn is_wasm_binary(path_string: &String) -> bool {
Expand All @@ -41,21 +41,23 @@ fn is_wasm_binary(path_string: &String) -> bool {
/// The function will return the error code.
pub fn execute_pipeline(
strategy: &ExecutionStrategy,
caller_permissions: &PrincipalPermission,
execution_permissions: &PrincipalPermission,
pipeline: Box<Expr>,
env: &Environment,
) -> Result<u32> {
) -> Result<()> {
use policy_utils::pipeline::Expr::*;
match *pipeline {
Literal(path) => {
info!("Literal {:?}", path);
// checker permission
if !check_permission(&caller_permissions, path.clone(), &FilePermissions{read: false, write: false, execute: true}) {
return Err(anyhow!("Permission denies"));
}
if is_wasm_binary(&path) {
info!("Read wasm binary: {}", path);
// Read and call execute_WASM program
let binary = fs::read(path)?;
let return_code =
execute_program(strategy, execution_permissions, binary, env)?;
Ok(return_code)
execute_program(strategy, execution_permissions, &Path::new(&path), env)
} else {
info!("Invoke native binary: {}", path);
// Treat program as a provisioned native module
Expand All @@ -73,32 +75,27 @@ pub fn execute_pipeline(
NativeModuleManager::new(native_module);
native_module_manager
.execute(vec![])
.map(|_| 0)
.map(|_| ())
.map_err(|err| anyhow!(err))
}
}
Seq(vec) => {
info!("Seq {:?}", vec);
for expr in vec {
let return_code = execute_pipeline(strategy, execution_permissions, expr, env)?;

// An error occurs
if return_code != 0 {
return Ok(return_code);
}
execute_pipeline(strategy, caller_permissions, execution_permissions, expr, env)?;
}

// default return_code is zero.
Ok(0)
Ok(())
}
IfElse(cond, true_branch, false_branch) => {
info!("IfElse {:?} true -> {:?} false -> {:?}", cond, true_branch, false_branch);
let return_code = if Path::new(&cond).exists() {
execute_pipeline(strategy, execution_permissions, true_branch, env)?
execute_pipeline(strategy, caller_permissions, execution_permissions, true_branch, env)?
} else {
match false_branch {
Some(f) => execute_pipeline(strategy, execution_permissions, f, env)?,
None => 0,
Some(f) => execute_pipeline(strategy, caller_permissions, execution_permissions, f, env)?,
None => (),
}
};
Ok(return_code)
Expand All @@ -109,11 +106,11 @@ pub fn execute_pipeline(
/// Execute the `program`. All I/O operations in the program are through at `filesystem`.
fn execute_program(
strategy: &ExecutionStrategy,
permissions: &PrincipalPermission,
program: Vec<u8>,
execution_permissions: &PrincipalPermission,
program_path: &Path,
env: &Environment,
) -> Result<u32> {
info!("Execute program with permissions {:?}", permissions);
) -> Result<()> {
info!("Execute program with permissions {:?}", execution_permissions);
initial_service();
let mut engine: Box<dyn ExecutionEngine> = match strategy {
ExecutionStrategy::Interpretation => {
Expand All @@ -123,7 +120,7 @@ fn execute_program(
cfg_if::cfg_if! {
if #[cfg(any(feature = "std", feature = "nitro"))] {
info!("JIT engine initialising");
Box::new(WasmtimeRuntimeState::new(permissions.clone(), env.clone())?)
Box::new(WasmtimeRuntimeState::new(execution_permissions.clone(), env.clone())?)

} else {
return Err(anyhow!("No JIT enine."));
Expand All @@ -132,5 +129,5 @@ fn execute_program(
}
};
info!("engine call");
engine.invoke_entry_point(program)
engine.serve(program_path)
}
1 change: 1 addition & 0 deletions crates/freestanding-execution-engine/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ fn main() -> Result<(), Box<dyn Error>> {
let return_code = execute(
&cmdline.execution_strategy,
&permission,
&permission,
cmdline.pipeline.clone(),
&env,
)?;
Expand Down
30 changes: 1 addition & 29 deletions crates/policy-utils/src/policy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
use super::{
error::PolicyError,
expiry::Timepoint,
principal::{PrincipalPermission, FilePermissions, ExecutionStrategy, FileHash, Identity, NativeModule, Pipeline, Principal, Program},
principal::{PrincipalPermission, ExecutionStrategy, FileHash, Identity, NativeModule, Pipeline, Principal, Program},
Platform,
};
use anyhow::{anyhow, Result};
Expand Down Expand Up @@ -367,38 +367,10 @@ impl Policy {
Ok(table)
}

/// Return the program input table, mapping program filenames to their expected input filenames.
pub fn get_input_table(&self) -> Result<HashMap<String, Vec<PathBuf>>> {
let mut table = HashMap::new();
for program in &self.programs {
let program_file_name = program.program_file_name();
let file_rights_map = program.file_rights_map();
table.insert(
program_file_name.to_string(),
Self::get_required_inputs(&file_rights_map),
);
}
Ok(table)
}

/// Return the pipeline of `pipeline_id`
pub fn get_pipeline(&self, pipeline_id: usize) -> Result<&Pipeline> {
self.pipelines
.get(pipeline_id)
.ok_or(anyhow!("Failed to find pipeline {}", pipeline_id))
}

/// Extract the input filenames from a right_map. If a program has rights call
/// fd_read and path_open, it is considered as an input file.
fn get_required_inputs(right_map: &HashMap<PathBuf, FilePermissions>) -> Vec<PathBuf> {
right_map
.iter()
.filter_map(|(k,v)| {
if v.read {
Some(k.clone())
} else {
None
}
}).collect()
}
}
10 changes: 6 additions & 4 deletions crates/runtime-manager/src/managers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,16 +233,18 @@ impl ProtocolState {
..Default::default()
};

let permission = self.global_policy.get_permission(execution_principal)?;
let caller_permission = self.global_policy.get_permission(caller_principal)?;
let execution_permission = self.global_policy.get_permission(execution_principal)?;

let return_code = execute(
execute(
&execution_strategy,
&permission,
&caller_permission,
&execution_permission,
pipeline,
&env,
)?;

let response = Self::response_error_code_returned(return_code);
let response = Self::response_error_code_returned(0);
Ok(Some(response))
}

Expand Down

0 comments on commit 32bd148

Please sign in to comment.