From 7a22df9b7641274b2a83ce53845215d17cfda2c8 Mon Sep 17 00:00:00 2001 From: Nayeem Rahman Date: Wed, 13 Oct 2021 18:04:44 +0100 Subject: fix(runtime/ops/worker_host): move permission arg parsing to Rust (#12297) --- runtime/ops/permissions.rs | 7 +- runtime/ops/worker_host.rs | 391 ++------------------------------------------- 2 files changed, 14 insertions(+), 384 deletions(-) (limited to 'runtime/ops') diff --git a/runtime/ops/permissions.rs b/runtime/ops/permissions.rs index d9f341633..05f4b75d7 100644 --- a/runtime/ops/permissions.rs +++ b/runtime/ops/permissions.rs @@ -28,7 +28,6 @@ pub struct PermissionArgs { host: Option, variable: Option, command: Option, - library: Option, } pub fn op_query_permission( @@ -50,7 +49,7 @@ pub fn op_query_permission( ), "env" => permissions.env.query(args.variable.as_deref()), "run" => permissions.run.query(args.command.as_deref()), - "ffi" => permissions.ffi.query(args.library.as_deref()), + "ffi" => permissions.ffi.query(args.path.as_deref().map(Path::new)), "hrtime" => permissions.hrtime.query(), n => { return Err(custom_error( @@ -81,7 +80,7 @@ pub fn op_revoke_permission( ), "env" => permissions.env.revoke(args.variable.as_deref()), "run" => permissions.run.revoke(args.command.as_deref()), - "ffi" => permissions.ffi.revoke(args.library.as_deref()), + "ffi" => permissions.ffi.revoke(args.path.as_deref().map(Path::new)), "hrtime" => permissions.hrtime.revoke(), n => { return Err(custom_error( @@ -112,7 +111,7 @@ pub fn op_request_permission( ), "env" => permissions.env.request(args.variable.as_deref()), "run" => permissions.run.request(args.command.as_deref()), - "ffi" => permissions.ffi.request(args.library.as_deref()), + "ffi" => permissions.ffi.request(args.path.as_deref().map(Path::new)), "hrtime" => permissions.hrtime.request(), n => { return Err(custom_error( diff --git a/runtime/ops/worker_host.rs b/runtime/ops/worker_host.rs index c1ce782da..e9eb380e0 100644 --- a/runtime/ops/worker_host.rs +++ b/runtime/ops/worker_host.rs @@ -1,18 +1,9 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. use crate::ops::TestingFeaturesEnabled; -use crate::permissions::resolve_read_allowlist; -use crate::permissions::resolve_write_allowlist; -use crate::permissions::EnvDescriptor; -use crate::permissions::FfiDescriptor; -use crate::permissions::NetDescriptor; -use crate::permissions::PermissionState; +use crate::permissions::create_child_permissions; +use crate::permissions::ChildPermissionsArg; use crate::permissions::Permissions; -use crate::permissions::ReadDescriptor; -use crate::permissions::RunDescriptor; -use crate::permissions::UnaryPermission; -use crate::permissions::UnitPermission; -use crate::permissions::WriteDescriptor; use crate::web_worker::run_web_worker; use crate::web_worker::SendableWebWorkerHandle; use crate::web_worker::WebWorker; @@ -20,14 +11,10 @@ use crate::web_worker::WebWorkerHandle; use crate::web_worker::WebWorkerType; use crate::web_worker::WorkerControlEvent; use crate::web_worker::WorkerId; -use deno_core::error::custom_error; use deno_core::error::AnyError; use deno_core::op_async; use deno_core::op_sync; -use deno_core::serde::de; -use deno_core::serde::de::SeqAccess; use deno_core::serde::Deserialize; -use deno_core::serde::Deserializer; use deno_core::Extension; use deno_core::ModuleSpecifier; use deno_core::OpState; @@ -35,10 +22,6 @@ use deno_web::JsMessageData; use log::debug; use std::cell::RefCell; use std::collections::HashMap; -use std::collections::HashSet; -use std::convert::From; -use std::fmt; -use std::path::PathBuf; use std::rc::Rc; use std::sync::Arc; use std::thread::JoinHandle; @@ -131,369 +114,12 @@ pub fn init(create_web_worker_cb: Arc) -> Extension { .build() } -fn merge_boolean_permission( - mut main: UnitPermission, - worker: Option, -) -> Result { - if let Some(worker) = worker { - if worker < main.state { - return Err(custom_error( - "PermissionDenied", - "Can't escalate parent thread permissions", - )); - } else { - main.state = worker; - } - } - Ok(main) -} - -fn merge_net_permission( - mut main: UnaryPermission, - worker: Option>, -) -> Result, AnyError> { - if let Some(worker) = worker { - if (worker.global_state < main.global_state) - || !worker - .granted_list - .iter() - .all(|x| main.check(&(&x.0, x.1)).is_ok()) - { - return Err(custom_error( - "PermissionDenied", - "Can't escalate parent thread permissions", - )); - } else { - main.global_state = worker.global_state; - main.granted_list = worker.granted_list; - } - } - Ok(main) -} - -fn merge_read_permission( - mut main: UnaryPermission, - worker: Option>, -) -> Result, AnyError> { - if let Some(worker) = worker { - if (worker.global_state < main.global_state) - || !worker - .granted_list - .iter() - .all(|x| main.check(x.0.as_path()).is_ok()) - { - return Err(custom_error( - "PermissionDenied", - "Can't escalate parent thread permissions", - )); - } else { - main.global_state = worker.global_state; - main.granted_list = worker.granted_list; - } - } - Ok(main) -} - -fn merge_write_permission( - mut main: UnaryPermission, - worker: Option>, -) -> Result, AnyError> { - if let Some(worker) = worker { - if (worker.global_state < main.global_state) - || !worker - .granted_list - .iter() - .all(|x| main.check(x.0.as_path()).is_ok()) - { - return Err(custom_error( - "PermissionDenied", - "Can't escalate parent thread permissions", - )); - } else { - main.global_state = worker.global_state; - main.granted_list = worker.granted_list; - } - } - Ok(main) -} - -fn merge_env_permission( - mut main: UnaryPermission, - worker: Option>, -) -> Result, AnyError> { - if let Some(worker) = worker { - if (worker.global_state < main.global_state) - || !worker - .granted_list - .iter() - .all(|x| main.check(x.as_ref()).is_ok()) - { - return Err(custom_error( - "PermissionDenied", - "Can't escalate parent thread permissions", - )); - } else { - main.global_state = worker.global_state; - main.granted_list = worker.granted_list; - } - } - Ok(main) -} - -fn merge_run_permission( - mut main: UnaryPermission, - worker: Option>, -) -> Result, AnyError> { - if let Some(worker) = worker { - if (worker.global_state < main.global_state) - || !worker.granted_list.iter().all(|x| main.check(&x.0).is_ok()) - { - return Err(custom_error( - "PermissionDenied", - "Can't escalate parent thread permissions", - )); - } else { - main.global_state = worker.global_state; - main.granted_list = worker.granted_list; - } - } - Ok(main) -} - -fn merge_ffi_permission( - mut main: UnaryPermission, - worker: Option>, -) -> Result, AnyError> { - if let Some(worker) = worker { - if (worker.global_state < main.global_state) - || !worker.granted_list.iter().all(|x| main.check(&x.0).is_ok()) - { - return Err(custom_error( - "PermissionDenied", - "Can't escalate parent thread permissions", - )); - } else { - main.global_state = worker.global_state; - main.granted_list = worker.granted_list; - } - } - Ok(main) -} - -pub fn create_worker_permissions( - main_perms: Permissions, - worker_perms: PermissionsArg, -) -> Result { - Ok(Permissions { - env: merge_env_permission(main_perms.env, worker_perms.env)?, - hrtime: merge_boolean_permission(main_perms.hrtime, worker_perms.hrtime)?, - net: merge_net_permission(main_perms.net, worker_perms.net)?, - ffi: merge_ffi_permission(main_perms.ffi, worker_perms.ffi)?, - read: merge_read_permission(main_perms.read, worker_perms.read)?, - run: merge_run_permission(main_perms.run, worker_perms.run)?, - write: merge_write_permission(main_perms.write, worker_perms.write)?, - }) -} - -#[derive(Debug, Deserialize)] -pub struct PermissionsArg { - #[serde(default, deserialize_with = "as_unary_env_permission")] - env: Option>, - #[serde(default, deserialize_with = "as_permission_state")] - hrtime: Option, - #[serde(default, deserialize_with = "as_unary_net_permission")] - net: Option>, - #[serde(default, deserialize_with = "as_unary_ffi_permission")] - ffi: Option>, - #[serde(default, deserialize_with = "as_unary_read_permission")] - read: Option>, - #[serde(default, deserialize_with = "as_unary_run_permission")] - run: Option>, - #[serde(default, deserialize_with = "as_unary_write_permission")] - write: Option>, -} - -fn as_permission_state<'de, D>( - deserializer: D, -) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - let value: bool = Deserialize::deserialize(deserializer)?; - - match value { - true => Ok(Some(PermissionState::Granted)), - false => Ok(Some(PermissionState::Denied)), - } -} - -struct UnaryPermissionBase { - global_state: PermissionState, - paths: Vec, -} - -struct ParseBooleanOrStringVec; - -impl<'de> de::Visitor<'de> for ParseBooleanOrStringVec { - type Value = UnaryPermissionBase; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("a vector of strings or a boolean") - } - - // visit_unit maps undefined/missing values to false - fn visit_unit(self) -> Result - where - E: de::Error, - { - self.visit_bool(false) - } - - fn visit_bool(self, v: bool) -> Result - where - E: de::Error, - { - Ok(UnaryPermissionBase { - global_state: match v { - true => PermissionState::Granted, - false => PermissionState::Denied, - }, - paths: Vec::new(), - }) - } - - fn visit_seq(self, mut visitor: V) -> Result - where - V: SeqAccess<'de>, - { - let mut vec: Vec = Vec::new(); - - let mut value = visitor.next_element::()?; - while value.is_some() { - vec.push(value.unwrap()); - value = visitor.next_element()?; - } - Ok(UnaryPermissionBase { - global_state: PermissionState::Prompt, - paths: vec, - }) - } -} - -fn as_unary_net_permission<'de, D>( - deserializer: D, -) -> Result>, D::Error> -where - D: Deserializer<'de>, -{ - let value: UnaryPermissionBase = - deserializer.deserialize_any(ParseBooleanOrStringVec)?; - - let allowed: HashSet = value - .paths - .into_iter() - .map(NetDescriptor::from_string) - .collect(); - - Ok(Some(UnaryPermission:: { - global_state: value.global_state, - granted_list: allowed, - ..Default::default() - })) -} - -fn as_unary_read_permission<'de, D>( - deserializer: D, -) -> Result>, D::Error> -where - D: Deserializer<'de>, -{ - let value: UnaryPermissionBase = - deserializer.deserialize_any(ParseBooleanOrStringVec)?; - - let paths: Vec = - value.paths.into_iter().map(PathBuf::from).collect(); - - Ok(Some(UnaryPermission:: { - global_state: value.global_state, - granted_list: resolve_read_allowlist(&Some(paths)), - ..Default::default() - })) -} - -fn as_unary_write_permission<'de, D>( - deserializer: D, -) -> Result>, D::Error> -where - D: Deserializer<'de>, -{ - let value: UnaryPermissionBase = - deserializer.deserialize_any(ParseBooleanOrStringVec)?; - - let paths: Vec = - value.paths.into_iter().map(PathBuf::from).collect(); - - Ok(Some(UnaryPermission:: { - global_state: value.global_state, - granted_list: resolve_write_allowlist(&Some(paths)), - ..Default::default() - })) -} - -fn as_unary_env_permission<'de, D>( - deserializer: D, -) -> Result>, D::Error> -where - D: Deserializer<'de>, -{ - let value: UnaryPermissionBase = - deserializer.deserialize_any(ParseBooleanOrStringVec)?; - - Ok(Some(UnaryPermission:: { - global_state: value.global_state, - granted_list: value.paths.into_iter().map(EnvDescriptor::new).collect(), - ..Default::default() - })) -} - -fn as_unary_run_permission<'de, D>( - deserializer: D, -) -> Result>, D::Error> -where - D: Deserializer<'de>, -{ - let value: UnaryPermissionBase = - deserializer.deserialize_any(ParseBooleanOrStringVec)?; - - Ok(Some(UnaryPermission:: { - global_state: value.global_state, - granted_list: value.paths.into_iter().map(RunDescriptor).collect(), - ..Default::default() - })) -} - -fn as_unary_ffi_permission<'de, D>( - deserializer: D, -) -> Result>, D::Error> -where - D: Deserializer<'de>, -{ - let value: UnaryPermissionBase = - deserializer.deserialize_any(ParseBooleanOrStringVec)?; - - Ok(Some(UnaryPermission:: { - global_state: value.global_state, - granted_list: value.paths.into_iter().map(FfiDescriptor).collect(), - ..Default::default() - })) -} - #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CreateWorkerArgs { has_source_code: bool, name: Option, - permissions: Option, + permissions: Option, source_code: String, specifier: String, use_deno_namespace: bool, @@ -528,13 +154,18 @@ fn op_create_worker( ); } } - let parent_permissions = state.borrow::().clone(); - let worker_permissions = if let Some(permissions) = args.permissions { + + if args.permissions.is_some() { super::check_unstable(state, "Worker.deno.permissions"); - create_worker_permissions(parent_permissions.clone(), permissions)? + } + let parent_permissions = state.borrow_mut::(); + let worker_permissions = if let Some(child_permissions_arg) = args.permissions + { + create_child_permissions(parent_permissions, child_permissions_arg)? } else { parent_permissions.clone() }; + let parent_permissions = parent_permissions.clone(); let worker_id = state.take::(); let create_module_loader = state.take::(); -- cgit v1.2.3