From 200bc9d69797f010818354f6dd2e91dd1a9a43a9 Mon Sep 17 00:00:00 2001 From: crowlkats Date: Wed, 6 Nov 2024 03:24:43 +0100 Subject: [PATCH 1/4] feat: permission traces --- cli/worker.rs | 2 + ext/fetch/lib.rs | 22 +- ext/ffi/call.rs | 9 +- ext/ffi/callback.rs | 6 +- ext/ffi/dlfcn.rs | 6 +- ext/ffi/lib.rs | 19 +- ext/ffi/repr.rs | 106 +++--- ext/kv/dynamic.rs | 15 +- ext/kv/interface.rs | 1 + ext/kv/lib.rs | 6 +- ext/kv/remote.rs | 28 +- ext/kv/sqlite.rs | 20 +- ext/napi/lib.rs | 18 +- ext/net/lib.rs | 23 +- ext/net/ops.rs | 60 ++- ext/net/ops_tls.rs | 26 +- ext/net/ops_unix.rs | 35 +- ext/websocket/lib.rs | 3 +- runtime/ops/fs_events.rs | 11 +- runtime/ops/os/mod.rs | 155 +++++--- runtime/ops/permissions.rs | 18 +- runtime/ops/process.rs | 29 +- runtime/ops/worker_host.rs | 5 +- runtime/permissions/lib.rs | 621 +++++++++++++++++++++----------- runtime/permissions/prompter.rs | 24 +- runtime/web_worker.rs | 2 + runtime/worker.rs | 3 + 27 files changed, 862 insertions(+), 411 deletions(-) diff --git a/cli/worker.rs b/cli/worker.rs index baacd681a16764..4bebc01700ddc6 100644 --- a/cli/worker.rs +++ b/cli/worker.rs @@ -596,6 +596,7 @@ impl CliMainWorkerFactory { origin_storage_dir, stdio, skip_op_registration: shared.options.skip_op_registration, + enable_stack_trace_arg_in_ops: crate::args::has_flag_env_var("DENO_TRACE_PERMISSIONS"), }; let mut worker = MainWorker::bootstrap_from_options( @@ -792,6 +793,7 @@ fn create_web_worker_callback( strace_ops: shared.options.strace_ops.clone(), close_on_idle: args.close_on_idle, maybe_worker_metadata: args.maybe_worker_metadata, + enable_stack_trace_arg_in_ops: crate::args::has_flag_env_var("DENO_TRACE_PERMISSIONS"), }; WebWorker::bootstrap_from_options(services, options) diff --git a/ext/fetch/lib.rs b/ext/fetch/lib.rs index 7ef26431c2b091..eb3de26538e2de 100644 --- a/ext/fetch/lib.rs +++ b/ext/fetch/lib.rs @@ -75,6 +75,7 @@ use tower_http::decompression::Decompression; // Re-export data_url pub use data_url; +use deno_core::error::JsStackFrame; pub use proxy::basic_auth; pub use fs_fetch_handler::FsFetchHandler; @@ -347,12 +348,14 @@ pub trait FetchPermissions { &mut self, url: &Url, api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError>; #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] fn check_read<'a>( &mut self, p: &'a Path, api_name: &str, + stack: Option>, ) -> Result, PermissionCheckError>; } @@ -362,8 +365,11 @@ impl FetchPermissions for deno_permissions::PermissionsContainer { &mut self, url: &Url, api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError> { - deno_permissions::PermissionsContainer::check_net_url(self, url, api_name) + deno_permissions::PermissionsContainer::check_net_url( + self, url, api_name, stack, + ) } #[inline(always)] @@ -371,16 +377,18 @@ impl FetchPermissions for deno_permissions::PermissionsContainer { &mut self, path: &'a Path, api_name: &str, + stack: Option>, ) -> Result, PermissionCheckError> { deno_permissions::PermissionsContainer::check_read_path( self, path, Some(api_name), + stack, ) } } -#[op2] +#[op2(reentrant)] #[serde] #[allow(clippy::too_many_arguments)] pub fn op_fetch( @@ -392,6 +400,7 @@ pub fn op_fetch( has_body: bool, #[buffer] data: Option, #[smi] resource: Option, + #[stack_trace] stack: Option>, ) -> Result where FP: FetchPermissions + 'static, @@ -415,7 +424,7 @@ where "file" => { let path = url.to_file_path().map_err(|_| FetchError::NetworkError)?; let permissions = state.borrow_mut::(); - let path = permissions.check_read(&path, "fetch()")?; + let path = permissions.check_read(&path, "fetch()", stack)?; let url = match path { Cow::Owned(path) => Url::from_file_path(path).unwrap(), Cow::Borrowed(_) => url, @@ -441,7 +450,7 @@ where } "http" | "https" => { let permissions = state.borrow_mut::(); - permissions.check_net_url(&url, "fetch()")?; + permissions.check_net_url(&url, "fetch()", stack)?; let maybe_authority = extract_authority(&mut url); let uri = url @@ -847,12 +856,13 @@ fn default_true() -> bool { true } -#[op2] +#[op2(reentrant)] #[smi] pub fn op_fetch_custom_client( state: &mut OpState, #[serde] args: CreateHttpClientArgs, #[cppgc] tls_keys: &TlsKeysHolder, + #[stack_trace] stack: Option>, ) -> Result where FP: FetchPermissions + 'static, @@ -860,7 +870,7 @@ where if let Some(proxy) = args.proxy.clone() { let permissions = state.borrow_mut::(); let url = Url::parse(&proxy.url)?; - permissions.check_net_url(&url, "Deno.createHttpClient()")?; + permissions.check_net_url(&url, "Deno.createHttpClient()", stack)?; } let options = state.borrow::(); diff --git a/ext/ffi/call.rs b/ext/ffi/call.rs index bbff0ee48f462d..8e3c5ee259ea58 100644 --- a/ext/ffi/call.rs +++ b/ext/ffi/call.rs @@ -7,6 +7,7 @@ use crate::symbol::NativeType; use crate::symbol::Symbol; use crate::FfiPermissions; use crate::ForeignFunction; +use deno_core::error::JsStackFrame; use deno_core::op2; use deno_core::serde_json::Value; use deno_core::serde_v8::BigInt as V8BigInt; @@ -287,7 +288,7 @@ fn ffi_call( } } -#[op2(async)] +#[op2(async, reentrant)] #[serde] pub fn op_ffi_call_ptr_nonblocking( scope: &mut v8::HandleScope, @@ -296,6 +297,7 @@ pub fn op_ffi_call_ptr_nonblocking( #[serde] def: ForeignFunction, parameters: v8::Local, out_buffer: Option>, + #[stack_trace] stack: Option>, ) -> Result>, CallError> where FP: FfiPermissions + 'static, @@ -303,7 +305,7 @@ where { let mut state = state.borrow_mut(); let permissions = state.borrow_mut::(); - permissions.check_partial_no_path()?; + permissions.check_partial_no_path(stack)?; }; let symbol = PtrSymbol::new(pointer, &def)?; @@ -394,6 +396,7 @@ pub fn op_ffi_call_ptr( #[serde] def: ForeignFunction, parameters: v8::Local, out_buffer: Option>, + #[stack_trace] stack: Option>, ) -> Result where FP: FfiPermissions + 'static, @@ -401,7 +404,7 @@ where { let mut state = state.borrow_mut(); let permissions = state.borrow_mut::(); - permissions.check_partial_no_path()?; + permissions.check_partial_no_path(stack)?; }; let symbol = PtrSymbol::new(pointer, &def)?; diff --git a/ext/ffi/callback.rs b/ext/ffi/callback.rs index 29583c800cd36d..b51a7f10e928a7 100644 --- a/ext/ffi/callback.rs +++ b/ext/ffi/callback.rs @@ -3,6 +3,7 @@ use crate::symbol::NativeType; use crate::FfiPermissions; use crate::ForeignFunction; +use deno_core::error::JsStackFrame; use deno_core::op2; use deno_core::v8; use deno_core::v8::TryCatch; @@ -561,18 +562,19 @@ pub struct RegisterCallbackArgs { result: NativeType, } -#[op2] +#[op2(reentrant)] pub fn op_ffi_unsafe_callback_create( state: &mut OpState, scope: &mut v8::HandleScope<'scope>, #[serde] args: RegisterCallbackArgs, cb: v8::Local, + #[stack_trace] stack: Option>, ) -> Result, CallbackError> where FP: FfiPermissions + 'static, { let permissions = state.borrow_mut::(); - permissions.check_partial_no_path()?; + permissions.check_partial_no_path(stack)?; let thread_id: u32 = LOCAL_THREAD_ID.with(|s| { let value = *s.borrow(); diff --git a/ext/ffi/dlfcn.rs b/ext/ffi/dlfcn.rs index 55909468f81044..e8cf5e4ccca2a2 100644 --- a/ext/ffi/dlfcn.rs +++ b/ext/ffi/dlfcn.rs @@ -6,6 +6,7 @@ use crate::symbol::Symbol; use crate::turbocall; use crate::turbocall::Turbocall; use crate::FfiPermissions; +use deno_core::error::JsStackFrame; use deno_core::op2; use deno_core::v8; use deno_core::GarbageCollected; @@ -123,17 +124,18 @@ pub struct FfiLoadArgs { symbols: HashMap, } -#[op2] +#[op2(reentrant)] pub fn op_ffi_load<'scope, FP>( scope: &mut v8::HandleScope<'scope>, state: &mut OpState, #[serde] args: FfiLoadArgs, + #[stack_trace] stack: Option>, ) -> Result, DlfcnError> where FP: FfiPermissions + 'static, { let permissions = state.borrow_mut::(); - let path = permissions.check_partial_with_path(&args.path)?; + let path = permissions.check_partial_with_path(&args.path, stack)?; let lib = Library::open(&path).map_err(|e| { dlopen2::Error::OpeningLibraryError(std::io::Error::new( diff --git a/ext/ffi/lib.rs b/ext/ffi/lib.rs index 73ec7757abc4e9..1a869cb8dfb81e 100644 --- a/ext/ffi/lib.rs +++ b/ext/ffi/lib.rs @@ -1,5 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +use deno_core::error::JsStackFrame; use std::mem::size_of; use std::os::raw::c_char; use std::os::raw::c_short; @@ -47,27 +48,37 @@ const _: () = { pub const UNSTABLE_FEATURE_NAME: &str = "ffi"; pub trait FfiPermissions { - fn check_partial_no_path(&mut self) -> Result<(), PermissionCheckError>; + fn check_partial_no_path( + &mut self, + stack: Option>, + ) -> Result<(), PermissionCheckError>; #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] fn check_partial_with_path( &mut self, path: &str, + stack: Option>, ) -> Result; } impl FfiPermissions for deno_permissions::PermissionsContainer { #[inline(always)] - fn check_partial_no_path(&mut self) -> Result<(), PermissionCheckError> { - deno_permissions::PermissionsContainer::check_ffi_partial_no_path(self) + fn check_partial_no_path( + &mut self, + stack: Option>, + ) -> Result<(), PermissionCheckError> { + deno_permissions::PermissionsContainer::check_ffi_partial_no_path( + self, stack, + ) } #[inline(always)] fn check_partial_with_path( &mut self, path: &str, + stack: Option>, ) -> Result { deno_permissions::PermissionsContainer::check_ffi_partial_with_path( - self, path, + self, path, stack, ) } } diff --git a/ext/ffi/repr.rs b/ext/ffi/repr.rs index fd8a2c8e707336..3f9b2b8abe7948 100644 --- a/ext/ffi/repr.rs +++ b/ext/ffi/repr.rs @@ -1,6 +1,7 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. use crate::FfiPermissions; +use deno_core::error::JsStackFrame; use deno_core::op2; use deno_core::v8; use deno_core::OpState; @@ -49,59 +50,63 @@ pub enum ReprError { Permission(#[from] deno_permissions::PermissionCheckError), } -#[op2(fast)] +#[op2(reentrant)] pub fn op_ffi_ptr_create( state: &mut OpState, #[bigint] ptr_number: usize, + #[stack_trace] stack: Option>, ) -> Result<*mut c_void, ReprError> where FP: FfiPermissions + 'static, { let permissions = state.borrow_mut::(); - permissions.check_partial_no_path()?; + permissions.check_partial_no_path(stack)?; Ok(ptr_number as *mut c_void) } -#[op2(fast)] +#[op2(reentrant)] pub fn op_ffi_ptr_equals( state: &mut OpState, a: *const c_void, b: *const c_void, + #[stack_trace] stack: Option>, ) -> Result where FP: FfiPermissions + 'static, { let permissions = state.borrow_mut::(); - permissions.check_partial_no_path()?; + permissions.check_partial_no_path(stack)?; Ok(a == b) } -#[op2] +#[op2(reentrant)] pub fn op_ffi_ptr_of( state: &mut OpState, #[anybuffer] buf: *const u8, + #[stack_trace] stack: Option>, ) -> Result<*mut c_void, ReprError> where FP: FfiPermissions + 'static, { let permissions = state.borrow_mut::(); - permissions.check_partial_no_path()?; + permissions.check_partial_no_path(stack)?; Ok(buf as *mut c_void) } -#[op2(fast)] +#[op2(reentrant)] pub fn op_ffi_ptr_of_exact( state: &mut OpState, buf: v8::Local, + #[stack_trace] stack: Option>, ) -> Result<*mut c_void, ReprError> where FP: FfiPermissions + 'static, { let permissions = state.borrow_mut::(); - permissions.check_partial_no_path()?; + permissions.check_partial_no_path(stack)?; let Some(buf) = buf.get_backing_store() else { return Ok(0 as _); @@ -112,17 +117,18 @@ where Ok(buf.as_ptr() as _) } -#[op2(fast)] +#[op2(reentrant)] pub fn op_ffi_ptr_offset( state: &mut OpState, ptr: *mut c_void, #[number] offset: isize, + #[stack_trace] stack: Option>, ) -> Result<*mut c_void, ReprError> where FP: FfiPermissions + 'static, { let permissions = state.borrow_mut::(); - permissions.check_partial_no_path()?; + permissions.check_partial_no_path(stack)?; if ptr.is_null() { return Err(ReprError::InvalidOffset); @@ -142,34 +148,36 @@ unsafe extern "C" fn noop_deleter_callback( ) { } -#[op2(fast)] +#[op2(reentrant)] #[bigint] pub fn op_ffi_ptr_value( state: &mut OpState, ptr: *mut c_void, + #[stack_trace] stack: Option>, ) -> Result where FP: FfiPermissions + 'static, { let permissions = state.borrow_mut::(); - permissions.check_partial_no_path()?; + permissions.check_partial_no_path(stack)?; Ok(ptr as usize) } -#[op2] +#[op2(reentrant)] pub fn op_ffi_get_buf( scope: &mut v8::HandleScope<'scope>, state: &mut OpState, ptr: *mut c_void, #[number] offset: isize, #[number] len: usize, + #[stack_trace] stack: Option>, ) -> Result, ReprError> where FP: FfiPermissions + 'static, { let permissions = state.borrow_mut::(); - permissions.check_partial_no_path()?; + permissions.check_partial_no_path(stack)?; if ptr.is_null() { return Err(ReprError::InvalidArrayBuffer); @@ -189,19 +197,20 @@ where Ok(array_buffer) } -#[op2] +#[op2(reentrant)] pub fn op_ffi_buf_copy_into( state: &mut OpState, src: *mut c_void, #[number] offset: isize, #[anybuffer] dst: &mut [u8], #[number] len: usize, + #[stack_trace] stack: Option>, ) -> Result<(), ReprError> where FP: FfiPermissions + 'static, { let permissions = state.borrow_mut::(); - permissions.check_partial_no_path()?; + permissions.check_partial_no_path(stack)?; if src.is_null() { Err(ReprError::InvalidArrayBuffer) @@ -219,18 +228,19 @@ where } } -#[op2] +#[op2(reentrant)] pub fn op_ffi_cstr_read( scope: &mut v8::HandleScope<'scope>, state: &mut OpState, ptr: *mut c_void, #[number] offset: isize, + #[stack_trace] stack: Option>, ) -> Result, ReprError> where FP: FfiPermissions + 'static, { let permissions = state.borrow_mut::(); - permissions.check_partial_no_path()?; + permissions.check_partial_no_path(stack)?; if ptr.is_null() { return Err(ReprError::InvalidCString); @@ -244,17 +254,18 @@ where Ok(value) } -#[op2(fast)] +#[op2(reentrant)] pub fn op_ffi_read_bool( state: &mut OpState, ptr: *mut c_void, #[number] offset: isize, + #[stack_trace] stack: Option>, ) -> Result where FP: FfiPermissions + 'static, { let permissions = state.borrow_mut::(); - permissions.check_partial_no_path()?; + permissions.check_partial_no_path(stack)?; if ptr.is_null() { return Err(ReprError::InvalidBool); @@ -264,17 +275,18 @@ where Ok(unsafe { ptr::read_unaligned::(ptr.offset(offset) as *const bool) }) } -#[op2(fast)] +#[op2(reentrant)] pub fn op_ffi_read_u8( state: &mut OpState, ptr: *mut c_void, #[number] offset: isize, + #[stack_trace] stack: Option>, ) -> Result where FP: FfiPermissions + 'static, { let permissions = state.borrow_mut::(); - permissions.check_partial_no_path()?; + permissions.check_partial_no_path(stack)?; if ptr.is_null() { return Err(ReprError::InvalidU8); @@ -286,17 +298,18 @@ where }) } -#[op2(fast)] +#[op2(reentrant)] pub fn op_ffi_read_i8( state: &mut OpState, ptr: *mut c_void, #[number] offset: isize, + #[stack_trace] stack: Option>, ) -> Result where FP: FfiPermissions + 'static, { let permissions = state.borrow_mut::(); - permissions.check_partial_no_path()?; + permissions.check_partial_no_path(stack)?; if ptr.is_null() { return Err(ReprError::InvalidI8); @@ -308,17 +321,18 @@ where }) } -#[op2(fast)] +#[op2(reentrant)] pub fn op_ffi_read_u16( state: &mut OpState, ptr: *mut c_void, #[number] offset: isize, + #[stack_trace] stack: Option>, ) -> Result where FP: FfiPermissions + 'static, { let permissions = state.borrow_mut::(); - permissions.check_partial_no_path()?; + permissions.check_partial_no_path(stack)?; if ptr.is_null() { return Err(ReprError::InvalidU16); @@ -330,17 +344,18 @@ where }) } -#[op2(fast)] +#[op2(reentrant)] pub fn op_ffi_read_i16( state: &mut OpState, ptr: *mut c_void, #[number] offset: isize, + #[stack_trace] stack: Option>, ) -> Result where FP: FfiPermissions + 'static, { let permissions = state.borrow_mut::(); - permissions.check_partial_no_path()?; + permissions.check_partial_no_path(stack)?; if ptr.is_null() { return Err(ReprError::InvalidI16); @@ -352,17 +367,18 @@ where }) } -#[op2(fast)] +#[op2(reentrant)] pub fn op_ffi_read_u32( state: &mut OpState, ptr: *mut c_void, #[number] offset: isize, + #[stack_trace] stack: Option>, ) -> Result where FP: FfiPermissions + 'static, { let permissions = state.borrow_mut::(); - permissions.check_partial_no_path()?; + permissions.check_partial_no_path(stack)?; if ptr.is_null() { return Err(ReprError::InvalidU32); @@ -372,17 +388,18 @@ where Ok(unsafe { ptr::read_unaligned::(ptr.offset(offset) as *const u32) }) } -#[op2(fast)] +#[op2(reentrant)] pub fn op_ffi_read_i32( state: &mut OpState, ptr: *mut c_void, #[number] offset: isize, + #[stack_trace] stack: Option>, ) -> Result where FP: FfiPermissions + 'static, { let permissions = state.borrow_mut::(); - permissions.check_partial_no_path()?; + permissions.check_partial_no_path(stack)?; if ptr.is_null() { return Err(ReprError::InvalidI32); @@ -392,7 +409,7 @@ where Ok(unsafe { ptr::read_unaligned::(ptr.offset(offset) as *const i32) }) } -#[op2(fast)] +#[op2(reentrant)] #[bigint] pub fn op_ffi_read_u64( state: &mut OpState, @@ -400,12 +417,13 @@ pub fn op_ffi_read_u64( // Note: The representation of 64-bit integers is function-wide. We cannot // choose to take this parameter as a number while returning a bigint. #[bigint] offset: isize, + #[stack_trace] stack: Option>, ) -> Result where FP: FfiPermissions + 'static, { let permissions = state.borrow_mut::(); - permissions.check_partial_no_path()?; + permissions.check_partial_no_path(stack)?; if ptr.is_null() { return Err(ReprError::InvalidU64); @@ -418,7 +436,7 @@ where Ok(value) } -#[op2(fast)] +#[op2(reentrant)] #[bigint] pub fn op_ffi_read_i64( state: &mut OpState, @@ -426,12 +444,13 @@ pub fn op_ffi_read_i64( // Note: The representation of 64-bit integers is function-wide. We cannot // choose to take this parameter as a number while returning a bigint. #[bigint] offset: isize, + #[stack_trace] stack: Option>, ) -> Result where FP: FfiPermissions + 'static, { let permissions = state.borrow_mut::(); - permissions.check_partial_no_path()?; + permissions.check_partial_no_path(stack)?; if ptr.is_null() { return Err(ReprError::InvalidI64); @@ -444,17 +463,18 @@ where Ok(value) } -#[op2(fast)] +#[op2(reentrant)] pub fn op_ffi_read_f32( state: &mut OpState, ptr: *mut c_void, #[number] offset: isize, + #[stack_trace] stack: Option>, ) -> Result where FP: FfiPermissions + 'static, { let permissions = state.borrow_mut::(); - permissions.check_partial_no_path()?; + permissions.check_partial_no_path(stack)?; if ptr.is_null() { return Err(ReprError::InvalidF32); @@ -464,17 +484,18 @@ where Ok(unsafe { ptr::read_unaligned::(ptr.offset(offset) as *const f32) }) } -#[op2(fast)] +#[op2(reentrant)] pub fn op_ffi_read_f64( state: &mut OpState, ptr: *mut c_void, #[number] offset: isize, + #[stack_trace] stack: Option>, ) -> Result where FP: FfiPermissions + 'static, { let permissions = state.borrow_mut::(); - permissions.check_partial_no_path()?; + permissions.check_partial_no_path(stack)?; if ptr.is_null() { return Err(ReprError::InvalidF64); @@ -484,17 +505,18 @@ where Ok(unsafe { ptr::read_unaligned::(ptr.offset(offset) as *const f64) }) } -#[op2(fast)] +#[op2(reentrant)] pub fn op_ffi_read_ptr( state: &mut OpState, ptr: *mut c_void, #[number] offset: isize, + #[stack_trace] stack: Option>, ) -> Result<*mut c_void, ReprError> where FP: FfiPermissions + 'static, { let permissions = state.borrow_mut::(); - permissions.check_partial_no_path()?; + permissions.check_partial_no_path(stack)?; if ptr.is_null() { return Err(ReprError::InvalidPointer); diff --git a/ext/kv/dynamic.rs b/ext/kv/dynamic.rs index 6d545d79f6407f..9f53f0cc71bc11 100644 --- a/ext/kv/dynamic.rs +++ b/ext/kv/dynamic.rs @@ -15,6 +15,7 @@ use crate::SnapshotReadOptions; use async_trait::async_trait; use deno_core::error::type_error; use deno_core::error::AnyError; +use deno_core::error::JsStackFrame; use deno_core::OpState; use denokv_proto::CommitResult; use denokv_proto::ReadRangeOutput; @@ -62,17 +63,20 @@ impl DatabaseHandler for MultiBackendDbHandler { &self, state: Rc>, path: Option, + stack: Option>, ) -> Result { for (prefixes, handler) in &self.backends { for &prefix in *prefixes { if prefix.is_empty() { - return handler.dyn_open(state.clone(), path.clone()).await; + return handler.dyn_open(state.clone(), path.clone(), stack).await; } let Some(path) = &path else { continue; }; if path.starts_with(prefix) { - return handler.dyn_open(state.clone(), Some(path.clone())).await; + return handler + .dyn_open(state.clone(), Some(path.clone()), stack) + .await; } } } @@ -89,6 +93,7 @@ pub trait DynamicDbHandler { &self, state: Rc>, path: Option, + stack: Option>, ) -> Result; } @@ -100,8 +105,9 @@ impl DatabaseHandler for Box { &self, state: Rc>, path: Option, + stack: Option>, ) -> Result { - (**self).dyn_open(state, path).await + (**self).dyn_open(state, path, stack).await } } @@ -115,8 +121,9 @@ where &self, state: Rc>, path: Option, + stack: Option>, ) -> Result { - Ok(RcDynamicDb(Rc::new(self.open(state, path).await?))) + Ok(RcDynamicDb(Rc::new(self.open(state, path, stack).await?))) } } diff --git a/ext/kv/interface.rs b/ext/kv/interface.rs index 9737a9366d3d1f..305748db32f613 100644 --- a/ext/kv/interface.rs +++ b/ext/kv/interface.rs @@ -16,5 +16,6 @@ pub trait DatabaseHandler { &self, state: Rc>, path: Option, + stack: Option>, ) -> Result; } diff --git a/ext/kv/lib.rs b/ext/kv/lib.rs index a4ccfe3d63f5c9..61d17491b0c247 100644 --- a/ext/kv/lib.rs +++ b/ext/kv/lib.rs @@ -17,6 +17,7 @@ use base64::Engine; use chrono::DateTime; use chrono::Utc; use deno_core::error::get_custom_error_class; +use deno_core::error::JsStackFrame; use deno_core::futures::StreamExt; use deno_core::op2; use deno_core::serde_v8::AnyValue; @@ -174,11 +175,12 @@ pub enum KvError { InvalidRange, } -#[op2(async)] +#[op2(async, reentrant)] #[smi] async fn op_kv_database_open( state: Rc>, #[string] path: Option, + #[stack_trace] stack: Option>, ) -> Result where DBH: DatabaseHandler + 'static, @@ -191,7 +193,7 @@ where state.borrow::>().clone() }; let db = handler - .open(state.clone(), path) + .open(state.clone(), path, stack) .await .map_err(KvError::DatabaseHandler)?; let rid = state.borrow_mut().resource_table.add(DatabaseResource { diff --git a/ext/kv/remote.rs b/ext/kv/remote.rs index 4930aacfe355c6..d4ec1a8ea04e53 100644 --- a/ext/kv/remote.rs +++ b/ext/kv/remote.rs @@ -11,6 +11,7 @@ use async_trait::async_trait; use bytes::Bytes; use deno_core::error::type_error; use deno_core::error::AnyError; +use deno_core::error::JsStackFrame; use deno_core::futures::Stream; use deno_core::OpState; use deno_fetch::create_http_client; @@ -46,18 +47,27 @@ impl HttpOptions { } pub trait RemoteDbHandlerPermissions { - fn check_env(&mut self, var: &str) -> Result<(), PermissionCheckError>; + fn check_env( + &mut self, + var: &str, + stack: Option>, + ) -> Result<(), PermissionCheckError>; fn check_net_url( &mut self, url: &Url, api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError>; } impl RemoteDbHandlerPermissions for deno_permissions::PermissionsContainer { #[inline(always)] - fn check_env(&mut self, var: &str) -> Result<(), PermissionCheckError> { - deno_permissions::PermissionsContainer::check_env(self, var) + fn check_env( + &mut self, + var: &str, + stack: Option>, + ) -> Result<(), PermissionCheckError> { + deno_permissions::PermissionsContainer::check_env(self, var, stack) } #[inline(always)] @@ -65,8 +75,11 @@ impl RemoteDbHandlerPermissions for deno_permissions::PermissionsContainer { &mut self, url: &Url, api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError> { - deno_permissions::PermissionsContainer::check_net_url(self, url, api_name) + deno_permissions::PermissionsContainer::check_net_url( + self, url, api_name, stack, + ) } } @@ -105,7 +118,7 @@ impl denokv_remote::RemotePermissions let mut state = self.state.borrow_mut(); let permissions = state.borrow_mut::

(); permissions - .check_net_url(url, "Deno.openKv") + .check_net_url(url, "Deno.openKv", None) .map_err(Into::into) } } @@ -161,6 +174,7 @@ impl DatabaseHandler &self, state: Rc>, path: Option, + stack: Option>, ) -> Result { const ENV_VAR_NAME: &str = "DENO_KV_ACCESS_TOKEN"; @@ -175,8 +189,8 @@ impl DatabaseHandler { let mut state = state.borrow_mut(); let permissions = state.borrow_mut::

(); - permissions.check_env(ENV_VAR_NAME)?; - permissions.check_net_url(&parsed_url, "Deno.openKv")?; + permissions.check_env(ENV_VAR_NAME, stack.clone())?; + permissions.check_net_url(&parsed_url, "Deno.openKv", stack)?; } let access_token = std::env::var(ENV_VAR_NAME) diff --git a/ext/kv/sqlite.rs b/ext/kv/sqlite.rs index 9de5209275c28c..1fb4264842d7a6 100644 --- a/ext/kv/sqlite.rs +++ b/ext/kv/sqlite.rs @@ -17,6 +17,7 @@ use crate::DatabaseHandler; use async_trait::async_trait; use deno_core::error::type_error; use deno_core::error::AnyError; +use deno_core::error::JsStackFrame; use deno_core::unsync::spawn_blocking; use deno_core::OpState; use deno_path_util::normalize_path; @@ -42,12 +43,14 @@ pub trait SqliteDbHandlerPermissions { &mut self, p: &str, api_name: &str, + stack: Option>, ) -> Result; #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] fn check_write<'a>( &mut self, p: &'a Path, api_name: &str, + stack: Option>, ) -> Result, PermissionCheckError>; } @@ -57,8 +60,9 @@ impl SqliteDbHandlerPermissions for deno_permissions::PermissionsContainer { &mut self, p: &str, api_name: &str, + stack: Option>, ) -> Result { - deno_permissions::PermissionsContainer::check_read(self, p, api_name) + deno_permissions::PermissionsContainer::check_read(self, p, api_name, stack) } #[inline(always)] @@ -66,8 +70,11 @@ impl SqliteDbHandlerPermissions for deno_permissions::PermissionsContainer { &mut self, p: &'a Path, api_name: &str, + stack: Option>, ) -> Result, PermissionCheckError> { - deno_permissions::PermissionsContainer::check_write_path(self, p, api_name) + deno_permissions::PermissionsContainer::check_write_path( + self, p, api_name, stack, + ) } } @@ -92,11 +99,13 @@ impl DatabaseHandler for SqliteDbHandler

{ &self, state: Rc>, path: Option, + stack: Option>, ) -> Result { #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] fn validate_path( state: &RefCell, path: Option, + stack: Option>, ) -> Result, AnyError> { let Some(path) = path else { return Ok(None); @@ -115,13 +124,14 @@ impl DatabaseHandler for SqliteDbHandler

{ { let mut state = state.borrow_mut(); let permissions = state.borrow_mut::

(); - let path = permissions.check_read(&path, "Deno.openKv")?; - let path = permissions.check_write(&path, "Deno.openKv")?; + let path = + permissions.check_read(&path, "Deno.openKv", stack.clone())?; + let path = permissions.check_write(&path, "Deno.openKv", stack)?; Ok(Some(path.to_string_lossy().to_string())) } } - let path = validate_path::

(&state, path)?; + let path = validate_path::

(&state, path, stack)?; let default_storage_dir = self.default_storage_dir.clone(); type ConnGen = Arc rusqlite::Result + Send + Sync>; diff --git a/ext/napi/lib.rs b/ext/napi/lib.rs index 88b8c238dffa1f..9d0745a74955db 100644 --- a/ext/napi/lib.rs +++ b/ext/napi/lib.rs @@ -54,6 +54,7 @@ use libloading::os::windows::*; // Expose common stuff for ease of use. // `use deno_napi::*` +use deno_core::error::JsStackFrame; pub use deno_core::v8; use deno_permissions::PermissionCheckError; pub use std::ffi::CStr; @@ -509,15 +510,23 @@ deno_core::extension!(deno_napi, pub trait NapiPermissions { #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] - fn check(&mut self, path: &str) -> Result; + fn check( + &mut self, + path: &str, + stack: Option>, + ) -> Result; } // NOTE(bartlomieju): for now, NAPI uses `--allow-ffi` flag, but that might // change in the future. impl NapiPermissions for deno_permissions::PermissionsContainer { #[inline(always)] - fn check(&mut self, path: &str) -> Result { - deno_permissions::PermissionsContainer::check_ffi(self, path) + fn check( + &mut self, + path: &str, + stack: Option>, + ) -> Result { + deno_permissions::PermissionsContainer::check_ffi(self, path, stack) } } @@ -539,6 +548,7 @@ fn op_napi_open( global: v8::Local<'scope, v8::Object>, buffer_constructor: v8::Local<'scope, v8::Function>, report_error: v8::Local<'scope, v8::Function>, + #[stack_trace] stack: Option>, ) -> Result, NApiError> where NP: NapiPermissions + 'static, @@ -548,7 +558,7 @@ where let (async_work_sender, cleanup_hooks, external_ops_tracker, path) = { let mut op_state = op_state.borrow_mut(); let permissions = op_state.borrow_mut::(); - let path = permissions.check(&path)?; + let path = permissions.check(&path, stack)?; let napi_state = op_state.borrow::(); ( op_state.borrow::().clone(), diff --git a/ext/net/lib.rs b/ext/net/lib.rs index bf8f58aa272396..74c1fcde0c0819 100644 --- a/ext/net/lib.rs +++ b/ext/net/lib.rs @@ -10,6 +10,7 @@ pub mod resolve_addr; mod tcp; use deno_core::error::AnyError; +use deno_core::error::JsStackFrame; use deno_core::OpState; use deno_permissions::PermissionCheckError; use deno_tls::rustls::RootCertStore; @@ -26,24 +27,28 @@ pub trait NetPermissions { &mut self, host: &(T, Option), api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError>; #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] fn check_read( &mut self, p: &str, api_name: &str, + stack: Option>, ) -> Result; #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] fn check_write( &mut self, p: &str, api_name: &str, + stack: Option>, ) -> Result; #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] fn check_write_path<'a>( &mut self, p: &'a Path, api_name: &str, + stack: Option>, ) -> Result, PermissionCheckError>; } @@ -53,8 +58,11 @@ impl NetPermissions for deno_permissions::PermissionsContainer { &mut self, host: &(T, Option), api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError> { - deno_permissions::PermissionsContainer::check_net(self, host, api_name) + deno_permissions::PermissionsContainer::check_net( + self, host, api_name, stack, + ) } #[inline(always)] @@ -62,8 +70,11 @@ impl NetPermissions for deno_permissions::PermissionsContainer { &mut self, path: &str, api_name: &str, + stack: Option>, ) -> Result { - deno_permissions::PermissionsContainer::check_read(self, path, api_name) + deno_permissions::PermissionsContainer::check_read( + self, path, api_name, stack, + ) } #[inline(always)] @@ -71,8 +82,11 @@ impl NetPermissions for deno_permissions::PermissionsContainer { &mut self, path: &str, api_name: &str, + stack: Option>, ) -> Result { - deno_permissions::PermissionsContainer::check_write(self, path, api_name) + deno_permissions::PermissionsContainer::check_write( + self, path, api_name, stack, + ) } #[inline(always)] @@ -80,9 +94,10 @@ impl NetPermissions for deno_permissions::PermissionsContainer { &mut self, path: &'a Path, api_name: &str, + stack: Option>, ) -> Result, PermissionCheckError> { deno_permissions::PermissionsContainer::check_write_path( - self, path, api_name, + self, path, api_name, stack, ) } } diff --git a/ext/net/ops.rs b/ext/net/ops.rs index 35bcff8dcf5d31..7bd44fb558943c 100644 --- a/ext/net/ops.rs +++ b/ext/net/ops.rs @@ -9,6 +9,7 @@ use crate::NetPermissions; use deno_core::op2; use deno_core::CancelFuture; +use deno_core::error::JsStackFrame; use deno_core::AsyncRefCell; use deno_core::ByteString; use deno_core::CancelHandle; @@ -182,13 +183,14 @@ pub async fn op_net_recv_udp( Ok((nread, IpAddr::from(remote_addr))) } -#[op2(async)] +#[op2(async, reentrant)] #[number] pub async fn op_net_send_udp( state: Rc>, #[smi] rid: ResourceId, #[serde] addr: IpAddr, #[buffer] zero_copy: JsBuffer, + #[stack_trace] stack: Option>, ) -> Result where NP: NetPermissions + 'static, @@ -198,6 +200,7 @@ where s.borrow_mut::().check_net( &(&addr.hostname, Some(addr.port)), "Deno.DatagramConn.send()", + stack, )?; } let addr = resolve_addr(&addr.hostname, addr.port) @@ -343,31 +346,35 @@ pub async fn op_net_set_multi_ttl_udp( Ok(()) } -#[op2(async)] +#[op2(async, reentrant)] #[serde] pub async fn op_net_connect_tcp( state: Rc>, #[serde] addr: IpAddr, + #[stack_trace] stack: Option>, ) -> Result<(ResourceId, IpAddr, IpAddr), NetError> where NP: NetPermissions + 'static, { - op_net_connect_tcp_inner::(state, addr).await + op_net_connect_tcp_inner::(state, addr, stack).await } #[inline] pub async fn op_net_connect_tcp_inner( state: Rc>, addr: IpAddr, + stack: Option>, ) -> Result<(ResourceId, IpAddr, IpAddr), NetError> where NP: NetPermissions + 'static, { { let mut state_ = state.borrow_mut(); - state_ - .borrow_mut::() - .check_net(&(&addr.hostname, Some(addr.port)), "Deno.connect()")?; + state_.borrow_mut::().check_net( + &(&addr.hostname, Some(addr.port)), + "Deno.connect()", + stack, + )?; } let addr = resolve_addr(&addr.hostname, addr.port) @@ -401,13 +408,14 @@ impl Resource for UdpSocketResource { } } -#[op2] +#[op2(reentrant)] #[serde] pub fn op_net_listen_tcp( state: &mut OpState, #[serde] addr: IpAddr, reuse_port: bool, load_balanced: bool, + #[stack_trace] stack: Option>, ) -> Result<(ResourceId, IpAddr), NetError> where NP: NetPermissions + 'static, @@ -415,9 +423,11 @@ where if reuse_port { super::check_unstable(state, "Deno.listen({ reusePort: true })"); } - state - .borrow_mut::() - .check_net(&(&addr.hostname, Some(addr.port)), "Deno.listen()")?; + state.borrow_mut::().check_net( + &(&addr.hostname, Some(addr.port)), + "Deno.listen()", + stack, + )?; let addr = resolve_addr_sync(&addr.hostname, addr.port)? .next() .ok_or_else(|| NetError::NoResolvedAddress)?; @@ -439,13 +449,16 @@ fn net_listen_udp( addr: IpAddr, reuse_address: bool, loopback: bool, + stack: Option>, ) -> Result<(ResourceId, IpAddr), NetError> where NP: NetPermissions + 'static, { - state - .borrow_mut::() - .check_net(&(&addr.hostname, Some(addr.port)), "Deno.listenDatagram()")?; + state.borrow_mut::().check_net( + &(&addr.hostname, Some(addr.port)), + "Deno.listenDatagram()", + stack, + )?; let addr = resolve_addr_sync(&addr.hostname, addr.port)? .next() .ok_or_else(|| NetError::NoResolvedAddress)?; @@ -501,33 +514,35 @@ where Ok((rid, IpAddr::from(local_addr))) } -#[op2] +#[op2(reentrant)] #[serde] pub fn op_net_listen_udp( state: &mut OpState, #[serde] addr: IpAddr, reuse_address: bool, loopback: bool, + #[stack_trace] stack: Option>, ) -> Result<(ResourceId, IpAddr), NetError> where NP: NetPermissions + 'static, { super::check_unstable(state, "Deno.listenDatagram"); - net_listen_udp::(state, addr, reuse_address, loopback) + net_listen_udp::(state, addr, reuse_address, loopback, stack) } -#[op2] +#[op2(reentrant)] #[serde] pub fn op_node_unstable_net_listen_udp( state: &mut OpState, #[serde] addr: IpAddr, reuse_address: bool, loopback: bool, + #[stack_trace] stack: Option>, ) -> Result<(ResourceId, IpAddr), NetError> where NP: NetPermissions + 'static, { - net_listen_udp::(state, addr, reuse_address, loopback) + net_listen_udp::(state, addr, reuse_address, loopback, stack) } #[derive(Serialize, Eq, PartialEq, Debug)] @@ -601,11 +616,12 @@ pub struct NameServer { port: u16, } -#[op2(async)] +#[op2(async, reentrant)] #[serde] pub async fn op_dns_resolve( state: Rc>, #[serde] args: ResolveAddrArgs, + #[stack_trace] stack: Option>, ) -> Result, NetError> where NP: NetPermissions + 'static, @@ -642,7 +658,7 @@ where let socker_addr = &ns.socket_addr; let ip = socker_addr.ip().to_string(); let port = socker_addr.port(); - perm.check_net(&(ip, Some(port)), "Deno.resolveDns()")?; + perm.check_net(&(ip, Some(port)), "Deno.resolveDns()", stack.clone())?; } } @@ -1035,6 +1051,7 @@ mod tests { &mut self, _host: &(T, Option), _api_name: &str, + _stack: Option>, ) -> Result<(), PermissionCheckError> { Ok(()) } @@ -1043,6 +1060,7 @@ mod tests { &mut self, p: &str, _api_name: &str, + _stack: Option>, ) -> Result { Ok(PathBuf::from(p)) } @@ -1051,6 +1069,7 @@ mod tests { &mut self, p: &str, _api_name: &str, + _stack: Option>, ) -> Result { Ok(PathBuf::from(p)) } @@ -1059,6 +1078,7 @@ mod tests { &mut self, p: &'a Path, _api_name: &str, + _stack: Option>, ) -> Result, PermissionCheckError> { Ok(Cow::Borrowed(p)) } @@ -1127,7 +1147,7 @@ mod tests { }; let mut connect_fut = - op_net_connect_tcp_inner::(conn_state, ip_addr) + op_net_connect_tcp_inner::(conn_state, ip_addr, None) .boxed_local(); let mut rid = None; diff --git a/ext/net/ops_tls.rs b/ext/net/ops_tls.rs index c7d65dd85ef7b8..ca98d7bdefd245 100644 --- a/ext/net/ops_tls.rs +++ b/ext/net/ops_tls.rs @@ -11,6 +11,7 @@ use crate::tcp::TcpListener; use crate::DefaultTlsOptions; use crate::NetPermissions; use crate::UnsafelyIgnoreCertificateErrors; +use deno_core::error::JsStackFrame; use deno_core::futures::TryFutureExt; use deno_core::op2; use deno_core::v8; @@ -251,11 +252,12 @@ pub fn op_tls_cert_resolver_resolve_error( lookup.resolve(sni, Err(error)) } -#[op2] +#[op2(reentrant)] #[serde] pub fn op_tls_start( state: Rc>, #[serde] args: StartTlsArgs, + #[stack_trace] stack: Option>, ) -> Result<(ResourceId, IpAddr, IpAddr), NetError> where NP: NetPermissions + 'static, @@ -270,7 +272,7 @@ where let mut s = state.borrow_mut(); let permissions = s.borrow_mut::(); permissions - .check_net(&(&hostname, Some(0)), "Deno.startTls()") + .check_net(&(&hostname, Some(0)), "Deno.startTls()", stack) .map_err(NetError::Permission)?; } @@ -340,13 +342,14 @@ where Ok((rid, IpAddr::from(local_addr), IpAddr::from(remote_addr))) } -#[op2(async)] +#[op2(async, reentrant)] #[serde] pub async fn op_net_connect_tls( state: Rc>, #[serde] addr: IpAddr, #[serde] args: ConnectTlsArgs, #[cppgc] key_pair: &TlsKeysHolder, + #[stack_trace] stack: Option>, ) -> Result<(ResourceId, IpAddr, IpAddr), NetError> where NP: NetPermissions + 'static, @@ -361,12 +364,16 @@ where let mut s = state.borrow_mut(); let permissions = s.borrow_mut::(); permissions - .check_net(&(&addr.hostname, Some(addr.port)), "Deno.connectTls()") + .check_net( + &(&addr.hostname, Some(addr.port)), + "Deno.connectTls()", + stack.clone(), + ) .map_err(NetError::Permission)?; if let Some(path) = cert_file { Some( permissions - .check_read(path, "Deno.connectTls()") + .check_read(path, "Deno.connectTls()", stack) .map_err(NetError::Permission)?, ) } else { @@ -445,13 +452,14 @@ pub struct ListenTlsArgs { load_balanced: bool, } -#[op2] +#[op2(reentrant)] #[serde] pub fn op_net_listen_tls( state: &mut OpState, #[serde] addr: IpAddr, #[serde] args: ListenTlsArgs, #[cppgc] keys: &TlsKeysHolder, + #[stack_trace] stack: Option>, ) -> Result<(ResourceId, IpAddr), NetError> where NP: NetPermissions + 'static, @@ -463,7 +471,11 @@ where { let permissions = state.borrow_mut::(); permissions - .check_net(&(&addr.hostname, Some(addr.port)), "Deno.listenTls()") + .check_net( + &(&addr.hostname, Some(addr.port)), + "Deno.listenTls()", + stack, + ) .map_err(NetError::Permission)?; } diff --git a/ext/net/ops_unix.rs b/ext/net/ops_unix.rs index 04ae84906fba3f..4c4ec558667d7c 100644 --- a/ext/net/ops_unix.rs +++ b/ext/net/ops_unix.rs @@ -4,6 +4,7 @@ use crate::io::UnixStreamResource; use crate::ops::NetError; use crate::raw::NetworkListenerResource; use crate::NetPermissions; +use deno_core::error::JsStackFrame; use deno_core::op2; use deno_core::AsyncRefCell; use deno_core::CancelHandle; @@ -85,11 +86,12 @@ pub async fn op_net_accept_unix( Ok((rid, local_addr_path, remote_addr_path)) } -#[op2(async)] +#[op2(async, reentrant)] #[serde] pub async fn op_net_connect_unix( state: Rc>, #[string] address_path: String, + #[stack_trace] stack: Option>, ) -> Result<(ResourceId, Option, Option), NetError> where NP: NetPermissions + 'static, @@ -98,11 +100,11 @@ where let mut state_ = state.borrow_mut(); let address_path = state_ .borrow_mut::() - .check_read(&address_path, "Deno.connect()") + .check_read(&address_path, "Deno.connect()", stack.clone()) .map_err(NetError::Permission)?; _ = state_ .borrow_mut::() - .check_write_path(&address_path, "Deno.connect()") + .check_write_path(&address_path, "Deno.connect()", stack) .map_err(NetError::Permission)?; address_path }; @@ -140,13 +142,14 @@ pub async fn op_net_recv_unixpacket( Ok((nread, path)) } -#[op2(async)] +#[op2(async, reentrant)] #[number] pub async fn op_net_send_unixpacket( state: Rc>, #[smi] rid: ResourceId, #[string] address_path: String, #[buffer] zero_copy: JsBuffer, + #[stack_trace] stack: Option>, ) -> Result where NP: NetPermissions + 'static, @@ -154,7 +157,7 @@ where let address_path = { let mut s = state.borrow_mut(); s.borrow_mut::() - .check_write(&address_path, "Deno.DatagramConn.send()") + .check_write(&address_path, "Deno.DatagramConn.send()", stack) .map_err(NetError::Permission)? }; @@ -171,12 +174,13 @@ where Ok(nwritten) } -#[op2] +#[op2(reentrant)] #[serde] pub fn op_net_listen_unix( state: &mut OpState, #[string] address_path: String, #[string] api_name: String, + #[stack_trace] stack: Option>, ) -> Result<(ResourceId, Option), NetError> where NP: NetPermissions + 'static, @@ -184,10 +188,10 @@ where let permissions = state.borrow_mut::(); let api_call_expr = format!("{}()", api_name); let address_path = permissions - .check_read(&address_path, &api_call_expr) + .check_read(&address_path, &api_call_expr, stack.clone()) .map_err(NetError::Permission)?; _ = permissions - .check_write_path(&address_path, &api_call_expr) + .check_write_path(&address_path, &api_call_expr, stack) .map_err(NetError::Permission)?; let listener = UnixListener::bind(address_path)?; let local_addr = listener.local_addr()?; @@ -200,16 +204,17 @@ where pub fn net_listen_unixpacket( state: &mut OpState, address_path: String, + stack: Option>, ) -> Result<(ResourceId, Option), NetError> where NP: NetPermissions + 'static, { let permissions = state.borrow_mut::(); let address_path = permissions - .check_read(&address_path, "Deno.listenDatagram()") + .check_read(&address_path, "Deno.listenDatagram()", stack.clone()) .map_err(NetError::Permission)?; _ = permissions - .check_write_path(&address_path, "Deno.listenDatagram()") + .check_write_path(&address_path, "Deno.listenDatagram()", stack) .map_err(NetError::Permission)?; let socket = UnixDatagram::bind(address_path)?; let local_addr = socket.local_addr()?; @@ -222,29 +227,31 @@ where Ok((rid, pathname)) } -#[op2] +#[op2(reentrant)] #[serde] pub fn op_net_listen_unixpacket( state: &mut OpState, #[string] path: String, + #[stack_trace] stack: Option>, ) -> Result<(ResourceId, Option), NetError> where NP: NetPermissions + 'static, { super::check_unstable(state, "Deno.listenDatagram"); - net_listen_unixpacket::(state, path) + net_listen_unixpacket::(state, path, stack) } -#[op2] +#[op2(reentrant)] #[serde] pub fn op_node_unstable_net_listen_unixpacket( state: &mut OpState, #[string] path: String, + #[stack_trace] stack: Option>, ) -> Result<(ResourceId, Option), NetError> where NP: NetPermissions + 'static, { - net_listen_unixpacket::(state, path) + net_listen_unixpacket::(state, path, stack) } pub fn pathstring(pathname: &Path) -> Result { diff --git a/ext/websocket/lib.rs b/ext/websocket/lib.rs index a5734271cf17be..e466ef19ac68f6 100644 --- a/ext/websocket/lib.rs +++ b/ext/websocket/lib.rs @@ -1,6 +1,7 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. use crate::stream::WebSocketStream; use bytes::Bytes; +use deno_core::error::JsStackFrame; use deno_core::futures::TryFutureExt; use deno_core::op2; use deno_core::unsync::spawn; @@ -123,7 +124,7 @@ impl WebSocketPermissions for deno_permissions::PermissionsContainer { url: &url::Url, api_name: &str, ) -> Result<(), PermissionCheckError> { - deno_permissions::PermissionsContainer::check_net_url(self, url, api_name) + deno_permissions::PermissionsContainer::check_net_url(self, url, api_name, todo!()) } } diff --git a/runtime/ops/fs_events.rs b/runtime/ops/fs_events.rs index c8e0228bc04199..6446da6d68dd64 100644 --- a/runtime/ops/fs_events.rs +++ b/runtime/ops/fs_events.rs @@ -162,12 +162,13 @@ fn start_watcher( Ok(()) } -#[op2] +#[op2(reentrant)] #[smi] fn op_fs_events_open( state: &mut OpState, recursive: bool, #[serde] paths: Vec, + #[stack_trace] stack: Option>, ) -> Result { let (sender, receiver) = mpsc::channel::>(16); @@ -179,9 +180,11 @@ fn op_fs_events_open( RecursiveMode::NonRecursive }; for path in &paths { - let path = state - .borrow_mut::() - .check_read(path, "Deno.watchFs()")?; + let path = state.borrow_mut::().check_read( + path, + "Deno.watchFs()", + stack.clone(), + )?; let watcher = state.borrow_mut::(); watcher.watcher.watch(&path, recursive_mode)?; diff --git a/runtime/ops/os/mod.rs b/runtime/ops/os/mod.rs index 9bee9d82349d24..ba456673627323 100644 --- a/runtime/ops/os/mod.rs +++ b/runtime/ops/os/mod.rs @@ -1,6 +1,7 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. use crate::worker::ExitCode; +use deno_core::error::JsStackFrame; use deno_core::op2; use deno_core::v8; use deno_core::OpState; @@ -88,13 +89,16 @@ pub enum OsError { Io(#[from] std::io::Error), } -#[op2] +#[op2(reentrant)] #[string] -fn op_exec_path(state: &mut OpState) -> Result { +fn op_exec_path( + state: &mut OpState, + #[stack_trace] stack: Option>, +) -> Result { let current_exe = env::current_exe().unwrap(); state .borrow_mut::() - .check_read_blind(¤t_exe, "exec_path", "Deno.execPath()")?; + .check_read_blind(¤t_exe, "exec_path", "Deno.execPath()", stack)?; // normalize path so it doesn't include '.' or '..' components let path = normalize_path(current_exe); @@ -104,13 +108,16 @@ fn op_exec_path(state: &mut OpState) -> Result { .map_err(OsError::InvalidUtf8) } -#[op2(fast)] +#[op2(reentrant)] fn op_set_env( state: &mut OpState, #[string] key: &str, #[string] value: &str, + #[stack_trace] stack: Option>, ) -> Result<(), OsError> { - state.borrow_mut::().check_env(key)?; + state + .borrow_mut::() + .check_env(key, stack)?; if key.is_empty() { return Err(OsError::EnvEmptyKey); } @@ -124,25 +131,31 @@ fn op_set_env( Ok(()) } -#[op2] +#[op2(reentrant)] #[serde] fn op_env( state: &mut OpState, + #[stack_trace] stack: Option>, ) -> Result, deno_core::error::AnyError> { - state.borrow_mut::().check_env_all()?; + state + .borrow_mut::() + .check_env_all(stack)?; Ok(env::vars().collect()) } -#[op2] +#[op2(reentrant)] #[string] fn op_get_env( state: &mut OpState, #[string] key: String, + #[stack_trace] stack: Option>, ) -> Result, OsError> { let skip_permission_check = NODE_ENV_VAR_ALLOWLIST.contains(&key); if !skip_permission_check { - state.borrow_mut::().check_env(&key)?; + state + .borrow_mut::() + .check_env(&key, stack)?; } if key.is_empty() { @@ -160,12 +173,15 @@ fn op_get_env( Ok(r) } -#[op2(fast)] +#[op2(fast, reentrant)] fn op_delete_env( state: &mut OpState, #[string] key: String, + #[stack_trace] stack: Option>, ) -> Result<(), OsError> { - state.borrow_mut::().check_env(&key)?; + state + .borrow_mut::() + .check_env(&key, stack)?; if key.is_empty() || key.contains(&['=', '\0'] as &[char]) { return Err(OsError::EnvInvalidKey(key.to_string())); } @@ -190,47 +206,59 @@ fn op_exit(state: &mut OpState) { std::process::exit(code) } -#[op2] +#[op2(reentrant)] #[serde] fn op_loadavg( state: &mut OpState, + #[stack_trace] stack: Option>, ) -> Result<(f64, f64, f64), deno_core::error::AnyError> { - state - .borrow_mut::() - .check_sys("loadavg", "Deno.loadavg()")?; + state.borrow_mut::().check_sys( + "loadavg", + "Deno.loadavg()", + stack, + )?; Ok(sys_info::loadavg()) } -#[op2] +#[op2(reentrant)] #[string] fn op_hostname( state: &mut OpState, + #[stack_trace] stack: Option>, ) -> Result { - state - .borrow_mut::() - .check_sys("hostname", "Deno.hostname()")?; + state.borrow_mut::().check_sys( + "hostname", + "Deno.hostname()", + stack, + )?; Ok(sys_info::hostname()) } -#[op2] +#[op2(reentrant)] #[string] fn op_os_release( state: &mut OpState, + #[stack_trace] stack: Option>, ) -> Result { - state - .borrow_mut::() - .check_sys("osRelease", "Deno.osRelease()")?; + state.borrow_mut::().check_sys( + "osRelease", + "Deno.osRelease()", + stack, + )?; Ok(sys_info::os_release()) } -#[op2] +#[op2(reentrant)] #[serde] fn op_network_interfaces( state: &mut OpState, + #[stack_trace] stack: Option>, ) -> Result, OsError> { - state - .borrow_mut::() - .check_sys("networkInterfaces", "Deno.networkInterfaces()")?; + state.borrow_mut::().check_sys( + "networkInterfaces", + "Deno.networkInterfaces()", + stack, + )?; Ok(netif::up()?.map(NetworkInterface::from).collect()) } @@ -275,26 +303,32 @@ impl From for NetworkInterface { } } -#[op2] +#[op2(reentrant)] #[serde] fn op_system_memory_info( state: &mut OpState, + #[stack_trace] stack: Option>, ) -> Result, deno_core::error::AnyError> { - state - .borrow_mut::() - .check_sys("systemMemoryInfo", "Deno.systemMemoryInfo()")?; + state.borrow_mut::().check_sys( + "systemMemoryInfo", + "Deno.systemMemoryInfo()", + stack, + )?; Ok(sys_info::mem_info()) } #[cfg(not(windows))] -#[op2] +#[op2(reentrant)] #[smi] fn op_gid( state: &mut OpState, + #[stack_trace] stack: Option>, ) -> Result, deno_core::error::AnyError> { - state - .borrow_mut::() - .check_sys("gid", "Deno.gid()")?; + state.borrow_mut::().check_sys( + "gid", + "Deno.gid()", + stack, + )?; // TODO(bartlomieju): #[allow(clippy::undocumented_unsafe_blocks)] unsafe { @@ -303,26 +337,32 @@ fn op_gid( } #[cfg(windows)] -#[op2] +#[op2(reentrant)] #[smi] fn op_gid( state: &mut OpState, + #[stack_trace] stack: Option>, ) -> Result, deno_core::error::AnyError> { - state - .borrow_mut::() - .check_sys("gid", "Deno.gid()")?; + state.borrow_mut::().check_sys( + "gid", + "Deno.gid()", + stack, + )?; Ok(None) } #[cfg(not(windows))] -#[op2] +#[op2(reentrant)] #[smi] fn op_uid( state: &mut OpState, + #[stack_trace] stack: Option>, ) -> Result, deno_core::error::AnyError> { - state - .borrow_mut::() - .check_sys("uid", "Deno.uid()")?; + state.borrow_mut::().check_sys( + "uid", + "Deno.uid()", + stack, + )?; // TODO(bartlomieju): #[allow(clippy::undocumented_unsafe_blocks)] unsafe { @@ -331,14 +371,17 @@ fn op_uid( } #[cfg(windows)] -#[op2] +#[op2(reentrant)] #[smi] fn op_uid( state: &mut OpState, + #[stack_trace] stack: Option>, ) -> Result, deno_core::error::AnyError> { - state - .borrow_mut::() - .check_sys("uid", "Deno.uid()")?; + state.borrow_mut::().check_sys( + "uid", + "Deno.uid()", + stack, + )?; Ok(None) } @@ -513,17 +556,23 @@ fn rss() -> usize { } } -fn os_uptime(state: &mut OpState) -> Result { - state - .borrow_mut::() - .check_sys("osUptime", "Deno.osUptime()")?; +fn os_uptime( + state: &mut OpState, + stack: Option>, +) -> Result { + state.borrow_mut::().check_sys( + "osUptime", + "Deno.osUptime()", + stack, + )?; Ok(sys_info::os_uptime()) } -#[op2(fast)] +#[op2(reentrant)] #[number] fn op_os_uptime( state: &mut OpState, + #[stack_trace] stack: Option>, ) -> Result { - os_uptime(state) + os_uptime(state, stack) } diff --git a/runtime/ops/permissions.rs b/runtime/ops/permissions.rs index 9ad963f3bc1aa4..d4b09c6693698b 100644 --- a/runtime/ops/permissions.rs +++ b/runtime/ops/permissions.rs @@ -2,6 +2,7 @@ use ::deno_permissions::PermissionState; use ::deno_permissions::PermissionsContainer; +use deno_core::error::JsStackFrame; use deno_core::op2; use deno_core::OpState; use serde::Deserialize; @@ -99,21 +100,22 @@ pub fn op_revoke_permission( Ok(PermissionStatus::from(perm)) } -#[op2] +#[op2(reentrant)] #[serde] pub fn op_request_permission( state: &mut OpState, #[serde] args: PermissionArgs, + #[stack_trace] stack: Option>, ) -> Result { let permissions = state.borrow::(); let perm = match args.name.as_ref() { - "read" => permissions.request_read(args.path.as_deref())?, - "write" => permissions.request_write(args.path.as_deref())?, - "net" => permissions.request_net(args.host.as_deref())?, - "env" => permissions.request_env(args.variable.as_deref()), - "sys" => permissions.request_sys(args.kind.as_deref())?, - "run" => permissions.request_run(args.command.as_deref())?, - "ffi" => permissions.request_ffi(args.path.as_deref())?, + "read" => permissions.request_read(args.path.as_deref(), stack)?, + "write" => permissions.request_write(args.path.as_deref(), stack)?, + "net" => permissions.request_net(args.host.as_deref(), stack)?, + "env" => permissions.request_env(args.variable.as_deref(), stack), + "sys" => permissions.request_sys(args.kind.as_deref(), stack)?, + "run" => permissions.request_run(args.command.as_deref(), stack)?, + "ffi" => permissions.request_ffi(args.path.as_deref(), stack)?, _ => return Err(PermissionError::InvalidPermissionName(args.name)), }; Ok(PermissionStatus::from(perm)) diff --git a/runtime/ops/process.rs b/runtime/ops/process.rs index de3141f1f933dd..87a65d937d713b 100644 --- a/runtime/ops/process.rs +++ b/runtime/ops/process.rs @@ -33,6 +33,7 @@ use tokio::process::Command; use std::os::windows::process::CommandExt; use crate::ops::signal::SignalError; +use deno_core::error::JsStackFrame; #[cfg(unix)] use std::os::unix::prelude::ExitStatusExt; #[cfg(unix)] @@ -335,6 +336,7 @@ fn create_command( state: &mut OpState, mut args: SpawnArgs, api_name: &str, + stack: Option>, ) -> Result { let maybe_npm_process_state = if args.needs_npm_process_state { let provider = state.borrow::(); @@ -356,6 +358,7 @@ fn create_command( args.clear_env, state, api_name, + stack, )?; let mut command = std::process::Command::new(cmd); @@ -634,6 +637,7 @@ fn compute_run_cmd_and_check_permissions( arg_clear_env: bool, state: &mut OpState, api_name: &str, + stack: Option>, ) -> Result<(PathBuf, RunEnv), ProcessError> { let run_env = compute_run_env(arg_cwd, arg_envs, arg_clear_env).map_err(|e| { @@ -655,6 +659,7 @@ fn compute_run_cmd_and_check_permissions( }, &run_env, api_name, + stack, )?; Ok((cmd, run_env)) } @@ -748,9 +753,10 @@ fn check_run_permission( cmd: &RunQueryDescriptor, run_env: &RunEnv, api_name: &str, + stack: Option>, ) -> Result<(), CheckRunPermissionError> { let permissions = state.borrow_mut::(); - if !permissions.query_run_all(api_name) { + if !permissions.query_run_all(api_name, stack.clone()) { // error the same on all platforms let env_var_names = get_requires_allow_all_env_vars(run_env); if !env_var_names.is_empty() { @@ -765,7 +771,7 @@ fn check_run_permission( ) ))); } - permissions.check_run(cmd, api_name)?; + permissions.check_run(cmd, api_name, stack)?; } Ok(()) } @@ -799,16 +805,17 @@ fn get_requires_allow_all_env_vars(env: &RunEnv) -> Vec<&str> { found_envs } -#[op2] +#[op2(reentrant)] #[serde] fn op_spawn_child( state: &mut OpState, #[serde] args: SpawnArgs, #[string] api_name: String, + #[stack_trace] stack: Option>, ) -> Result { let detached = args.detached; let (command, pipe_rid, extra_pipe_rids, handles_to_close) = - create_command(state, args, &api_name)?; + create_command(state, args, &api_name, stack)?; let child = spawn_child(state, command, pipe_rid, extra_pipe_rids, detached); for handle in handles_to_close { deno_io::close_raw_handle(handle); @@ -841,16 +848,17 @@ async fn op_spawn_wait( Ok(result) } -#[op2] +#[op2(reentrant)] #[serde] fn op_spawn_sync( state: &mut OpState, #[serde] args: SpawnArgs, + #[stack_trace] stack: Option>, ) -> Result { let stdout = matches!(args.stdio.stdout, StdioOrRid::Stdio(Stdio::Piped)); let stderr = matches!(args.stdio.stderr, StdioOrRid::Stdio(Stdio::Piped)); let (mut command, _, _, _) = - create_command(state, args, "Deno.Command().outputSync()")?; + create_command(state, args, "Deno.Command().outputSync()", stack)?; let output = command.output().map_err(|e| ProcessError::SpawnFailed { command: command.get_program().to_string_lossy().to_string(), error: Box::new(e.into()), @@ -925,11 +933,12 @@ mod deprecated { stderr_rid: Option, } - #[op2] + #[op2(reentrant)] #[serde] pub fn op_run( state: &mut OpState, #[serde] run_args: RunArgs, + #[stack_trace] stack: Option>, ) -> Result { let args = run_args.cmd; let cmd = args.first().ok_or(ProcessError::MissingCmd)?; @@ -940,6 +949,7 @@ mod deprecated { /* clear env */ false, state, "Deno.run()", + stack, )?; let mut c = Command::new(cmd); @@ -1126,16 +1136,17 @@ mod deprecated { } } - #[op2(fast)] + #[op2(reentrant)] pub fn op_kill( state: &mut OpState, #[smi] pid: i32, #[string] signal: String, #[string] api_name: String, + #[stack_trace] stack: Option>, ) -> Result<(), ProcessError> { state .borrow_mut::() - .check_run_all(&api_name)?; + .check_run_all(&api_name, stack)?; kill(pid, &signal) } } diff --git a/runtime/ops/worker_host.rs b/runtime/ops/worker_host.rs index 521284a6a065b2..010c9b15726011 100644 --- a/runtime/ops/worker_host.rs +++ b/runtime/ops/worker_host.rs @@ -133,12 +133,13 @@ pub enum CreateWorkerError { } /// Create worker as the host -#[op2] +#[op2(reentrant)] #[serde] fn op_create_worker( state: &mut OpState, #[serde] args: CreateWorkerArgs, #[serde] maybe_worker_metadata: Option, + #[stack_trace] stack: Option>, ) -> Result { let specifier = args.specifier.clone(); let maybe_source_code = if args.has_source_code { @@ -165,7 +166,7 @@ fn op_create_worker( let worker_permissions = if let Some(child_permissions_arg) = args.permissions { parent_permissions - .create_child_permissions(child_permissions_arg) + .create_child_permissions(child_permissions_arg, stack) .map_err(CreateWorkerError::Permission)? } else { parent_permissions.clone() diff --git a/runtime/permissions/lib.rs b/runtime/permissions/lib.rs index 6480f4bf586094..8d6b0e9ca60771 100644 --- a/runtime/permissions/lib.rs +++ b/runtime/permissions/lib.rs @@ -1,5 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +use deno_core::error::JsStackFrame; use deno_core::parking_lot::Mutex; use deno_core::serde::de; use deno_core::serde::Deserialize; @@ -161,17 +162,25 @@ impl PermissionState { api_name: Option<&str>, info: Option<&str>, prompt: bool, + stack: Option>, ) -> (Result<(), PermissionDeniedError>, bool, bool) { - self.check2(name, api_name, || info.map(|s| s.to_string()), prompt) + self.check_inner( + name, + api_name, + || info.map(|s| s.to_string()), + prompt, + stack, + ) } #[inline] - fn check2( + fn check_inner( self, name: &'static str, api_name: Option<&str>, info: impl Fn() -> Option, prompt: bool, + stack: Option>, ) -> (Result<(), PermissionDeniedError>, bool, bool) { match self { PermissionState::Granted => { @@ -186,7 +195,7 @@ impl PermissionState { .map(|info| { format!(" to {info}") }) .unwrap_or_default(), ); - match permission_prompt(&msg, name, api_name, true) { + match permission_prompt(&msg, name, api_name, true, stack) { PromptResponse::Allow => { Self::log_perm_access(name, info); (Ok(()), true, false) @@ -227,7 +236,10 @@ impl UnitPermission { self.state } - pub fn request(&mut self) -> PermissionState { + pub fn request( + &mut self, + stack: Option>, + ) -> PermissionState { if self.state == PermissionState::Prompt { if PromptResponse::Allow == permission_prompt( @@ -235,6 +247,7 @@ impl UnitPermission { self.name, Some("Deno.permissions.query()"), false, + stack, ) { self.state = PermissionState::Granted; @@ -252,9 +265,12 @@ impl UnitPermission { self.state } - pub fn check(&mut self) -> Result<(), PermissionDeniedError> { + pub fn check( + &mut self, + stack: Option>, + ) -> Result<(), PermissionDeniedError> { let (result, prompted, _is_allow_all) = - self.state.check(self.name, None, None, self.prompt); + self.state.check(self.name, None, None, self.prompt, stack); if prompted { if result.is_ok() { self.state = PermissionState::Granted; @@ -268,6 +284,7 @@ impl UnitPermission { fn create_child_permissions( &mut self, flag: ChildUnitPermissionArg, + stack: Option>, ) -> Result { let mut perm = self.clone(); match flag { @@ -275,7 +292,7 @@ impl UnitPermission { // copy } ChildUnitPermissionArg::Granted => { - if self.check().is_err() { + if self.check(stack).is_err() { return Err(ChildPermissionError::Escalation); } perm.state = PermissionState::Granted; @@ -333,6 +350,7 @@ pub trait QueryDescriptor: Debug { &self, perm: &mut UnaryPermission, api_name: Option<&str>, + stack: Option>, ) -> Result<(), PermissionDeniedError>; fn matches_allow(&self, other: &Self::AllowDesc) -> bool; @@ -408,9 +426,10 @@ impl UnaryPermission { pub fn check_all_api( &mut self, api_name: Option<&str>, + stack: Option>, ) -> Result<(), PermissionDeniedError> { skip_check_if_is_permission_fully_granted!(self); - self.check_desc(None, false, api_name) + self.check_desc(None, false, api_name, stack) } fn check_desc( @@ -418,14 +437,16 @@ impl UnaryPermission { desc: Option<&TQuery>, assert_non_partial: bool, api_name: Option<&str>, + stack: Option>, ) -> Result<(), PermissionDeniedError> { let (result, prompted, is_allow_all) = self .query_desc(desc, AllowPartial::from(!assert_non_partial)) - .check2( + .check_inner( TQuery::flag_name(), api_name, || desc.map(|d| format_display_name(d.display_name())), self.prompt, + stack, ); if prompted { if result.is_ok() { @@ -475,7 +496,11 @@ impl UnaryPermission { } } - fn request_desc(&mut self, desc: Option<&TQuery>) -> PermissionState { + fn request_desc( + &mut self, + desc: Option<&TQuery>, + stack: Option>, + ) -> PermissionState { let state = self.query_desc(desc, AllowPartial::TreatAsPartialGranted); if state == PermissionState::Granted { self.insert_granted(desc); @@ -498,6 +523,7 @@ impl UnaryPermission { TQuery::flag_name(), Some("Deno.permissions.request()"), true, + stack, ) { PromptResponse::Allow => { self.insert_granted(desc); @@ -609,6 +635,7 @@ impl UnaryPermission { &mut self, flag: ChildUnaryPermissionArg, parse: impl Fn(&str) -> Result, E>, + stack: Option>, ) -> Result, ChildPermissionError> where ChildPermissionError: From, @@ -620,7 +647,7 @@ impl UnaryPermission { perms.clone_from(self); } ChildUnaryPermissionArg::Granted => { - if self.check_all_api(None).is_err() { + if self.check_all_api(None, stack).is_err() { return Err(ChildPermissionError::Escalation); } perms.granted_global = true; @@ -633,7 +660,7 @@ impl UnaryPermission { .collect::>()?; if !perms.granted_list.iter().all(|desc| { TQuery::from_allow(desc) - .check_in_permission(self, None) + .check_in_permission(self, None, stack.clone()) .is_ok() }) { return Err(ChildPermissionError::Escalation); @@ -707,9 +734,10 @@ impl QueryDescriptor for ReadQueryDescriptor { &self, perm: &mut UnaryPermission, api_name: Option<&str>, + stack: Option>, ) -> Result<(), PermissionDeniedError> { skip_check_if_is_permission_fully_granted!(perm); - perm.check_desc(Some(self), true, api_name) + perm.check_desc(Some(self), true, api_name, stack) } fn matches_allow(&self, other: &Self::AllowDesc) -> bool { @@ -770,9 +798,10 @@ impl QueryDescriptor for WriteQueryDescriptor { &self, perm: &mut UnaryPermission, api_name: Option<&str>, + stack: Option>, ) -> Result<(), PermissionDeniedError> { skip_check_if_is_permission_fully_granted!(perm); - perm.check_desc(Some(self), true, api_name) + perm.check_desc(Some(self), true, api_name, stack) } fn matches_allow(&self, other: &Self::AllowDesc) -> bool { @@ -896,9 +925,10 @@ impl QueryDescriptor for NetDescriptor { &self, perm: &mut UnaryPermission, api_name: Option<&str>, + stack: Option>, ) -> Result<(), PermissionDeniedError> { skip_check_if_is_permission_fully_granted!(perm); - perm.check_desc(Some(self), false, api_name) + perm.check_desc(Some(self), false, api_name, stack) } fn matches_allow(&self, other: &Self::AllowDesc) -> bool { @@ -1073,9 +1103,10 @@ impl QueryDescriptor for ImportDescriptor { &self, perm: &mut UnaryPermission, api_name: Option<&str>, + stack: Option>, ) -> Result<(), PermissionDeniedError> { skip_check_if_is_permission_fully_granted!(perm); - perm.check_desc(Some(self), false, api_name) + perm.check_desc(Some(self), false, api_name, stack) } fn matches_allow(&self, other: &Self::AllowDesc) -> bool { @@ -1150,9 +1181,10 @@ impl QueryDescriptor for EnvDescriptor { &self, perm: &mut UnaryPermission, api_name: Option<&str>, + stack: Option>, ) -> Result<(), PermissionDeniedError> { skip_check_if_is_permission_fully_granted!(perm); - perm.check_desc(Some(self), false, api_name) + perm.check_desc(Some(self), false, api_name, stack) } fn matches_allow(&self, other: &Self::AllowDesc) -> bool { @@ -1287,9 +1319,10 @@ impl QueryDescriptor for RunQueryDescriptor { &self, perm: &mut UnaryPermission, api_name: Option<&str>, + stack: Option>, ) -> Result<(), PermissionDeniedError> { skip_check_if_is_permission_fully_granted!(perm); - perm.check_desc(Some(self), false, api_name) + perm.check_desc(Some(self), false, api_name, stack) } fn matches_allow(&self, other: &Self::AllowDesc) -> bool { @@ -1506,9 +1539,10 @@ impl QueryDescriptor for SysDescriptor { &self, perm: &mut UnaryPermission, api_name: Option<&str>, + stack: Option>, ) -> Result<(), PermissionDeniedError> { skip_check_if_is_permission_fully_granted!(perm); - perm.check_desc(Some(self), false, api_name) + perm.check_desc(Some(self), false, api_name, stack) } fn matches_allow(&self, other: &Self::AllowDesc) -> bool { @@ -1567,9 +1601,10 @@ impl QueryDescriptor for FfiQueryDescriptor { &self, perm: &mut UnaryPermission, api_name: Option<&str>, + stack: Option>, ) -> Result<(), PermissionDeniedError> { skip_check_if_is_permission_fully_granted!(perm); - perm.check_desc(Some(self), true, api_name) + perm.check_desc(Some(self), true, api_name, stack) } fn matches_allow(&self, other: &Self::AllowDesc) -> bool { @@ -1604,8 +1639,9 @@ impl UnaryPermission { pub fn request( &mut self, path: Option<&ReadQueryDescriptor>, + stack: Option>, ) -> PermissionState { - self.request_desc(path) + self.request_desc(path, stack) } pub fn revoke( @@ -1619,9 +1655,10 @@ impl UnaryPermission { &mut self, desc: &ReadQueryDescriptor, api_name: Option<&str>, + stack: Option>, ) -> Result<(), PermissionDeniedError> { skip_check_if_is_permission_fully_granted!(self); - self.check_desc(Some(desc), true, api_name) + self.check_desc(Some(desc), true, api_name, stack) } #[inline] @@ -1629,17 +1666,19 @@ impl UnaryPermission { &mut self, desc: &ReadQueryDescriptor, api_name: Option<&str>, + stack: Option>, ) -> Result<(), PermissionDeniedError> { skip_check_if_is_permission_fully_granted!(self); - self.check_desc(Some(desc), false, api_name) + self.check_desc(Some(desc), false, api_name, stack) } pub fn check_all( &mut self, api_name: Option<&str>, + stack: Option>, ) -> Result<(), PermissionDeniedError> { skip_check_if_is_permission_fully_granted!(self); - self.check_desc(None, false, api_name) + self.check_desc(None, false, api_name, stack) } } @@ -1651,8 +1690,9 @@ impl UnaryPermission { pub fn request( &mut self, path: Option<&WriteQueryDescriptor>, + stack: Option>, ) -> PermissionState { - self.request_desc(path) + self.request_desc(path, stack) } pub fn revoke( @@ -1666,9 +1706,10 @@ impl UnaryPermission { &mut self, path: &WriteQueryDescriptor, api_name: Option<&str>, + stack: Option>, ) -> Result<(), PermissionDeniedError> { skip_check_if_is_permission_fully_granted!(self); - self.check_desc(Some(path), true, api_name) + self.check_desc(Some(path), true, api_name, stack) } #[inline] @@ -1676,17 +1717,19 @@ impl UnaryPermission { &mut self, path: &WriteQueryDescriptor, api_name: Option<&str>, + stack: Option>, ) -> Result<(), PermissionDeniedError> { skip_check_if_is_permission_fully_granted!(self); - self.check_desc(Some(path), false, api_name) + self.check_desc(Some(path), false, api_name, stack) } pub fn check_all( &mut self, api_name: Option<&str>, + stack: Option>, ) -> Result<(), PermissionDeniedError> { skip_check_if_is_permission_fully_granted!(self); - self.check_desc(None, false, api_name) + self.check_desc(None, false, api_name, stack) } } @@ -1695,8 +1738,12 @@ impl UnaryPermission { self.query_desc(host, AllowPartial::TreatAsPartialGranted) } - pub fn request(&mut self, host: Option<&NetDescriptor>) -> PermissionState { - self.request_desc(host) + pub fn request( + &mut self, + host: Option<&NetDescriptor>, + stack: Option>, + ) -> PermissionState { + self.request_desc(host, stack) } pub fn revoke(&mut self, host: Option<&NetDescriptor>) -> PermissionState { @@ -1707,14 +1754,18 @@ impl UnaryPermission { &mut self, host: &NetDescriptor, api_name: Option<&str>, + stack: Option>, ) -> Result<(), PermissionDeniedError> { skip_check_if_is_permission_fully_granted!(self); - self.check_desc(Some(host), false, api_name) + self.check_desc(Some(host), false, api_name, stack) } - pub fn check_all(&mut self) -> Result<(), PermissionDeniedError> { + pub fn check_all( + &mut self, + stack: Option>, + ) -> Result<(), PermissionDeniedError> { skip_check_if_is_permission_fully_granted!(self); - self.check_desc(None, false, None) + self.check_desc(None, false, None, stack) } } @@ -1726,8 +1777,9 @@ impl UnaryPermission { pub fn request( &mut self, host: Option<&ImportDescriptor>, + stack: Option>, ) -> PermissionState { - self.request_desc(host) + self.request_desc(host, stack) } pub fn revoke(&mut self, host: Option<&ImportDescriptor>) -> PermissionState { @@ -1738,14 +1790,18 @@ impl UnaryPermission { &mut self, host: &ImportDescriptor, api_name: Option<&str>, + stack: Option>, ) -> Result<(), PermissionDeniedError> { skip_check_if_is_permission_fully_granted!(self); - self.check_desc(Some(host), false, api_name) + self.check_desc(Some(host), false, api_name, stack) } - pub fn check_all(&mut self) -> Result<(), PermissionDeniedError> { + pub fn check_all( + &mut self, + stack: Option>, + ) -> Result<(), PermissionDeniedError> { skip_check_if_is_permission_fully_granted!(self); - self.check_desc(None, false, None) + self.check_desc(None, false, None, stack) } } @@ -1757,8 +1813,12 @@ impl UnaryPermission { ) } - pub fn request(&mut self, env: Option<&str>) -> PermissionState { - self.request_desc(env.map(EnvDescriptor::new).as_ref()) + pub fn request( + &mut self, + env: Option<&str>, + stack: Option>, + ) -> PermissionState { + self.request_desc(env.map(EnvDescriptor::new).as_ref(), stack) } pub fn revoke(&mut self, env: Option<&str>) -> PermissionState { @@ -1769,14 +1829,18 @@ impl UnaryPermission { &mut self, env: &str, api_name: Option<&str>, + stack: Option>, ) -> Result<(), PermissionDeniedError> { skip_check_if_is_permission_fully_granted!(self); - self.check_desc(Some(&EnvDescriptor::new(env)), false, api_name) + self.check_desc(Some(&EnvDescriptor::new(env)), false, api_name, stack) } - pub fn check_all(&mut self) -> Result<(), PermissionDeniedError> { + pub fn check_all( + &mut self, + stack: Option>, + ) -> Result<(), PermissionDeniedError> { skip_check_if_is_permission_fully_granted!(self); - self.check_desc(None, false, None) + self.check_desc(None, false, None, stack) } } @@ -1785,8 +1849,12 @@ impl UnaryPermission { self.query_desc(kind, AllowPartial::TreatAsPartialGranted) } - pub fn request(&mut self, kind: Option<&SysDescriptor>) -> PermissionState { - self.request_desc(kind) + pub fn request( + &mut self, + kind: Option<&SysDescriptor>, + stack: Option>, + ) -> PermissionState { + self.request_desc(kind, stack) } pub fn revoke(&mut self, kind: Option<&SysDescriptor>) -> PermissionState { @@ -1797,14 +1865,18 @@ impl UnaryPermission { &mut self, kind: &SysDescriptor, api_name: Option<&str>, + stack: Option>, ) -> Result<(), PermissionDeniedError> { skip_check_if_is_permission_fully_granted!(self); - self.check_desc(Some(kind), false, api_name) + self.check_desc(Some(kind), false, api_name, stack) } - pub fn check_all(&mut self) -> Result<(), PermissionDeniedError> { + pub fn check_all( + &mut self, + stack: Option>, + ) -> Result<(), PermissionDeniedError> { skip_check_if_is_permission_fully_granted!(self); - self.check_desc(None, false, None) + self.check_desc(None, false, None, stack) } } @@ -1816,8 +1888,9 @@ impl UnaryPermission { pub fn request( &mut self, cmd: Option<&RunQueryDescriptor>, + stack: Option>, ) -> PermissionState { - self.request_desc(cmd) + self.request_desc(cmd, stack) } pub fn revoke( @@ -1831,28 +1904,36 @@ impl UnaryPermission { &mut self, cmd: &RunQueryDescriptor, api_name: Option<&str>, + stack: Option>, ) -> Result<(), PermissionDeniedError> { - self.check_desc(Some(cmd), false, api_name) + self.check_desc(Some(cmd), false, api_name, stack) } pub fn check_all( &mut self, api_name: Option<&str>, + stack: Option>, ) -> Result<(), PermissionDeniedError> { - self.check_desc(None, false, api_name) + self.check_desc(None, false, api_name, stack) } /// Queries without prompting - pub fn query_all(&mut self, api_name: Option<&str>) -> bool { + pub fn query_all( + &mut self, + api_name: Option<&str>, + stack: Option>, + ) -> bool { if self.is_allow_all() { return true; } - let (result, _prompted, _is_allow_all) = - self.query_desc(None, AllowPartial::TreatAsDenied).check2( + let (result, _prompted, _is_allow_all) = self + .query_desc(None, AllowPartial::TreatAsDenied) + .check_inner( RunQueryDescriptor::flag_name(), api_name, || None, /* prompt */ false, + stack, ); result.is_ok() } @@ -1866,8 +1947,9 @@ impl UnaryPermission { pub fn request( &mut self, path: Option<&FfiQueryDescriptor>, + stack: Option>, ) -> PermissionState { - self.request_desc(path) + self.request_desc(path, stack) } pub fn revoke( @@ -1881,22 +1963,27 @@ impl UnaryPermission { &mut self, path: &FfiQueryDescriptor, api_name: Option<&str>, + stack: Option>, ) -> Result<(), PermissionDeniedError> { skip_check_if_is_permission_fully_granted!(self); - self.check_desc(Some(path), true, api_name) + self.check_desc(Some(path), true, api_name, stack) } pub fn check_partial( &mut self, path: Option<&FfiQueryDescriptor>, + stack: Option>, ) -> Result<(), PermissionDeniedError> { skip_check_if_is_permission_fully_granted!(self); - self.check_desc(path, false, None) + self.check_desc(path, false, None, stack) } - pub fn check_all(&mut self) -> Result<(), PermissionDeniedError> { + pub fn check_all( + &mut self, + stack: Option>, + ) -> Result<(), PermissionDeniedError> { skip_check_if_is_permission_fully_granted!(self); - self.check_desc(None, false, Some("all")) + self.check_desc(None, false, Some("all"), stack) } } @@ -2239,6 +2326,7 @@ impl PermissionsContainer { pub fn create_child_permissions( &self, child_permissions_arg: ChildPermissionsArg, + stack: Option>, ) -> Result { fn is_granted_unary(arg: &ChildUnaryPermissionArg) -> bool { match arg { @@ -2253,9 +2341,10 @@ impl PermissionsContainer { let mut worker_perms = Permissions::none_without_prompt(); let mut inner = self.inner.lock(); - worker_perms.all = inner - .all - .create_child_permissions(ChildUnitPermissionArg::Inherit)?; + worker_perms.all = inner.all.create_child_permissions( + ChildUnitPermissionArg::Inherit, + stack.clone(), + )?; // downgrade the `worker_perms.all` based on the other values if worker_perms.all.query() == PermissionState::Granted { @@ -2284,6 +2373,7 @@ impl PermissionsContainer { self.descriptor_parser.parse_read_descriptor(text)?, )) }, + stack.clone(), )?; worker_perms.write = inner.write.create_child_permissions( child_permissions_arg.write, @@ -2292,6 +2382,7 @@ impl PermissionsContainer { self.descriptor_parser.parse_write_descriptor(text)?, )) }, + stack.clone(), )?; worker_perms.import = inner.import.create_child_permissions( child_permissions_arg.import, @@ -2300,6 +2391,7 @@ impl PermissionsContainer { self.descriptor_parser.parse_import_descriptor(text)?, )) }, + stack.clone(), )?; worker_perms.net = inner.net.create_child_permissions( child_permissions_arg.net, @@ -2308,6 +2400,7 @@ impl PermissionsContainer { self.descriptor_parser.parse_net_descriptor(text)?, )) }, + stack.clone(), )?; worker_perms.env = inner.env.create_child_permissions( child_permissions_arg.env, @@ -2316,6 +2409,7 @@ impl PermissionsContainer { self.descriptor_parser.parse_env_descriptor(text)?, )) }, + stack.clone(), )?; worker_perms.sys = inner.sys.create_child_permissions( child_permissions_arg.sys, @@ -2324,6 +2418,7 @@ impl PermissionsContainer { self.descriptor_parser.parse_sys_descriptor(text)?, )) }, + stack.clone(), )?; worker_perms.run = inner.run.create_child_permissions( child_permissions_arg.run, @@ -2333,6 +2428,7 @@ impl PermissionsContainer { } AllowRunDescriptorParseResult::Descriptor(desc) => Ok(Some(desc)), }, + stack.clone(), )?; worker_perms.ffi = inner.ffi.create_child_permissions( child_permissions_arg.ffi, @@ -2341,6 +2437,7 @@ impl PermissionsContainer { self.descriptor_parser.parse_ffi_descriptor(text)?, )) }, + stack, )?; Ok(PermissionsContainer::new( @@ -2354,6 +2451,7 @@ impl PermissionsContainer { &self, specifier: &ModuleSpecifier, kind: CheckSpecifierKind, + stack: Option>, ) -> Result<(), PermissionCheckError> { let mut inner = self.inner.lock(); match specifier.scheme() { @@ -2372,6 +2470,7 @@ impl PermissionsContainer { } .into_read(), Some("import()"), + stack, ) .map_err(PermissionCheckError::PermissionDenied), Err(_) => { @@ -2389,7 +2488,7 @@ impl PermissionsContainer { let desc = self .descriptor_parser .parse_import_descriptor_from_url(specifier)?; - inner.import.check(&desc, Some("import()"))?; + inner.import.check(&desc, Some("import()"), stack)?; Ok(()) } } @@ -2401,8 +2500,9 @@ impl PermissionsContainer { &self, path: &str, api_name: &str, + stack: Option>, ) -> Result { - self.check_read_with_api_name(path, Some(api_name)) + self.check_read_with_api_name(path, Some(api_name), stack) } #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] @@ -2411,6 +2511,7 @@ impl PermissionsContainer { &self, path: &str, api_name: Option<&str>, + stack: Option>, ) -> Result { let mut inner = self.inner.lock(); let inner = &mut inner.read; @@ -2418,7 +2519,7 @@ impl PermissionsContainer { Ok(PathBuf::from(path)) } else { let desc = self.descriptor_parser.parse_path_query(path)?.into_read(); - inner.check(&desc, api_name)?; + inner.check(&desc, api_name, stack)?; Ok(desc.0.resolved) } } @@ -2429,6 +2530,7 @@ impl PermissionsContainer { &self, path: &'a Path, api_name: Option<&str>, + stack: Option>, ) -> Result, PermissionCheckError> { let mut inner = self.inner.lock(); let inner = &mut inner.read; @@ -2440,7 +2542,7 @@ impl PermissionsContainer { resolved: path.to_path_buf(), } .into_read(); - inner.check(&desc, api_name)?; + inner.check(&desc, api_name, stack)?; Ok(Cow::Owned(desc.0.resolved)) } } @@ -2453,6 +2555,7 @@ impl PermissionsContainer { path: &Path, display: &str, api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError> { let mut inner = self.inner.lock(); let inner = &mut inner.read; @@ -2464,6 +2567,7 @@ impl PermissionsContainer { } .into_read(), Some(api_name), + stack, )?; Ok(()) } @@ -2472,8 +2576,9 @@ impl PermissionsContainer { pub fn check_read_all( &self, api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError> { - self.inner.lock().read.check_all(Some(api_name))?; + self.inner.lock().read.check_all(Some(api_name), stack)?; Ok(()) } @@ -2488,8 +2593,9 @@ impl PermissionsContainer { &self, path: &str, api_name: &str, + stack: Option>, ) -> Result { - self.check_write_with_api_name(path, Some(api_name)) + self.check_write_with_api_name(path, Some(api_name), stack) } #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] @@ -2498,6 +2604,7 @@ impl PermissionsContainer { &self, path: &str, api_name: Option<&str>, + stack: Option>, ) -> Result { let mut inner = self.inner.lock(); let inner = &mut inner.write; @@ -2505,7 +2612,7 @@ impl PermissionsContainer { Ok(PathBuf::from(path)) } else { let desc = self.descriptor_parser.parse_path_query(path)?.into_write(); - inner.check(&desc, api_name)?; + inner.check(&desc, api_name, stack)?; Ok(desc.0.resolved) } } @@ -2516,6 +2623,7 @@ impl PermissionsContainer { &self, path: &'a Path, api_name: &str, + stack: Option>, ) -> Result, PermissionCheckError> { let mut inner = self.inner.lock(); let inner = &mut inner.write; @@ -2527,7 +2635,7 @@ impl PermissionsContainer { resolved: path.to_path_buf(), } .into_write(); - inner.check(&desc, Some(api_name))?; + inner.check(&desc, Some(api_name), stack)?; Ok(Cow::Owned(desc.0.resolved)) } } @@ -2536,8 +2644,9 @@ impl PermissionsContainer { pub fn check_write_all( &self, api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError> { - self.inner.lock().write.check_all(Some(api_name))?; + self.inner.lock().write.check_all(Some(api_name), stack)?; Ok(()) } @@ -2549,6 +2658,7 @@ impl PermissionsContainer { path: &Path, display: &str, api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError> { let mut inner = self.inner.lock(); let inner = &mut inner.write; @@ -2560,6 +2670,7 @@ impl PermissionsContainer { } .into_write(), Some(api_name), + stack, )?; Ok(()) } @@ -2569,6 +2680,7 @@ impl PermissionsContainer { &mut self, path: &str, api_name: &str, + stack: Option>, ) -> Result { let mut inner = self.inner.lock(); let inner = &mut inner.write; @@ -2576,7 +2688,7 @@ impl PermissionsContainer { Ok(PathBuf::from(path)) } else { let desc = self.descriptor_parser.parse_path_query(path)?.into_write(); - inner.check_partial(&desc, Some(api_name))?; + inner.check_partial(&desc, Some(api_name), stack)?; Ok(desc.0.resolved) } } @@ -2586,8 +2698,9 @@ impl PermissionsContainer { &mut self, cmd: &RunQueryDescriptor, api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError> { - self.inner.lock().run.check(cmd, Some(api_name))?; + self.inner.lock().run.check(cmd, Some(api_name), stack)?; Ok(()) } @@ -2595,14 +2708,19 @@ impl PermissionsContainer { pub fn check_run_all( &mut self, api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError> { - self.inner.lock().run.check_all(Some(api_name))?; + self.inner.lock().run.check_all(Some(api_name), stack)?; Ok(()) } #[inline(always)] - pub fn query_run_all(&mut self, api_name: &str) -> bool { - self.inner.lock().run.query_all(Some(api_name)) + pub fn query_run_all( + &mut self, + api_name: &str, + stack: Option>, + ) -> bool { + self.inner.lock().run.query_all(Some(api_name), stack) } #[inline(always)] @@ -2610,35 +2728,50 @@ impl PermissionsContainer { &self, kind: &str, api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError> { self.inner.lock().sys.check( &self.descriptor_parser.parse_sys_descriptor(kind)?, Some(api_name), + stack, )?; Ok(()) } #[inline(always)] - pub fn check_env(&mut self, var: &str) -> Result<(), PermissionCheckError> { - self.inner.lock().env.check(var, None)?; + pub fn check_env( + &mut self, + var: &str, + stack: Option>, + ) -> Result<(), PermissionCheckError> { + self.inner.lock().env.check(var, None, stack)?; Ok(()) } #[inline(always)] - pub fn check_env_all(&mut self) -> Result<(), PermissionCheckError> { - self.inner.lock().env.check_all()?; + pub fn check_env_all( + &mut self, + stack: Option>, + ) -> Result<(), PermissionCheckError> { + self.inner.lock().env.check_all(stack)?; Ok(()) } #[inline(always)] - pub fn check_sys_all(&mut self) -> Result<(), PermissionCheckError> { - self.inner.lock().sys.check_all()?; + pub fn check_sys_all( + &mut self, + stack: Option>, + ) -> Result<(), PermissionCheckError> { + self.inner.lock().sys.check_all(stack)?; Ok(()) } #[inline(always)] - pub fn check_ffi_all(&mut self) -> Result<(), PermissionCheckError> { - self.inner.lock().ffi.check_all()?; + pub fn check_ffi_all( + &mut self, + stack: Option>, + ) -> Result<(), PermissionCheckError> { + self.inner.lock().ffi.check_all(stack)?; Ok(()) } @@ -2647,8 +2780,9 @@ impl PermissionsContainer { #[inline(always)] pub fn check_was_allow_all_flag_passed( &mut self, + stack: Option>, ) -> Result<(), PermissionCheckError> { - self.inner.lock().all.check()?; + self.inner.lock().all.check(stack)?; Ok(()) } @@ -2658,6 +2792,7 @@ impl PermissionsContainer { &mut self, path: &Path, _api_name: &str, + stack: Option>, ) -> Result<(), &'static str> { let error_all = |_| "all"; @@ -2718,14 +2853,18 @@ impl PermissionsContainer { || path.starts_with("/sys") { if path.ends_with("/environ") { - self.check_env_all().map_err(|_| "env")?; + self.check_env_all(stack).map_err(|_| "env")?; } else { - self.check_was_allow_all_flag_passed().map_err(error_all)?; + self + .check_was_allow_all_flag_passed(stack) + .map_err(error_all)?; } } } else if cfg!(unix) { if path.starts_with("/dev") { - self.check_was_allow_all_flag_passed().map_err(error_all)?; + self + .check_was_allow_all_flag_passed(stack) + .map_err(error_all)?; } } else if cfg!(target_os = "windows") { // \\.\nul is allowed @@ -2748,7 +2887,9 @@ impl PermissionsContainer { // If this is a normalized drive path, accept it if !is_normalized_windows_drive_path(path) { - self.check_was_allow_all_flag_passed().map_err(error_all)?; + self + .check_was_allow_all_flag_passed(stack) + .map_err(error_all)?; } } else { unimplemented!() @@ -2761,13 +2902,14 @@ impl PermissionsContainer { &mut self, url: &Url, api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError> { let mut inner = self.inner.lock(); if inner.net.is_allow_all() { return Ok(()); } let desc = self.descriptor_parser.parse_net_descriptor_from_url(url)?; - inner.net.check(&desc, Some(api_name))?; + inner.net.check(&desc, Some(api_name), stack)?; Ok(()) } @@ -2776,13 +2918,14 @@ impl PermissionsContainer { &mut self, host: &(T, Option), api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError> { let mut inner = self.inner.lock(); let inner = &mut inner.net; skip_check_if_is_permission_fully_granted!(inner); let hostname = Host::parse(host.0.as_ref())?; let descriptor = NetDescriptor(hostname, host.1); - inner.check(&descriptor, Some(api_name))?; + inner.check(&descriptor, Some(api_name), stack)?; Ok(()) } @@ -2790,6 +2933,7 @@ impl PermissionsContainer { pub fn check_ffi( &mut self, path: &str, + stack: Option>, ) -> Result { let mut inner = self.inner.lock(); let inner = &mut inner.ffi; @@ -2797,7 +2941,7 @@ impl PermissionsContainer { Ok(PathBuf::from(path)) } else { let desc = self.descriptor_parser.parse_path_query(path)?.into_ffi(); - inner.check(&desc, None)?; + inner.check(&desc, None, stack)?; Ok(desc.0.resolved) } } @@ -2806,11 +2950,12 @@ impl PermissionsContainer { #[inline(always)] pub fn check_ffi_partial_no_path( &mut self, + stack: Option>, ) -> Result<(), PermissionCheckError> { let mut inner = self.inner.lock(); let inner = &mut inner.ffi; if !inner.is_allow_all() { - inner.check_partial(None)?; + inner.check_partial(None, stack)?; } Ok(()) } @@ -2820,6 +2965,7 @@ impl PermissionsContainer { pub fn check_ffi_partial_with_path( &mut self, path: &str, + stack: Option>, ) -> Result { let mut inner = self.inner.lock(); let inner = &mut inner.ffi; @@ -2827,7 +2973,7 @@ impl PermissionsContainer { Ok(PathBuf::from(path)) } else { let desc = self.descriptor_parser.parse_path_query(path)?.into_ffi(); - inner.check_partial(Some(&desc))?; + inner.check_partial(Some(&desc), stack)?; Ok(desc.0.resolved) } } @@ -3093,6 +3239,7 @@ impl PermissionsContainer { pub fn request_read( &self, path: Option<&str>, + stack: Option>, ) -> Result { Ok( self.inner.lock().read.request( @@ -3104,6 +3251,7 @@ impl PermissionsContainer { }) .transpose()? .as_ref(), + stack, ), ) } @@ -3112,6 +3260,7 @@ impl PermissionsContainer { pub fn request_write( &self, path: Option<&str>, + stack: Option>, ) -> Result { Ok( self.inner.lock().write.request( @@ -3123,6 +3272,7 @@ impl PermissionsContainer { }) .transpose()? .as_ref(), + stack, ), ) } @@ -3131,6 +3281,7 @@ impl PermissionsContainer { pub fn request_net( &self, host: Option<&str>, + stack: Option>, ) -> Result { Ok( self.inner.lock().net.request( @@ -3139,19 +3290,25 @@ impl PermissionsContainer { Some(h) => Some(self.descriptor_parser.parse_net_descriptor(h)?), } .as_ref(), + stack, ), ) } #[inline(always)] - pub fn request_env(&self, var: Option<&str>) -> PermissionState { - self.inner.lock().env.request(var) + pub fn request_env( + &self, + var: Option<&str>, + stack: Option>, + ) -> PermissionState { + self.inner.lock().env.request(var, stack) } #[inline(always)] pub fn request_sys( &self, kind: Option<&str>, + stack: Option>, ) -> Result { Ok( self.inner.lock().sys.request( @@ -3159,6 +3316,7 @@ impl PermissionsContainer { .map(|kind| self.descriptor_parser.parse_sys_descriptor(kind)) .transpose()? .as_ref(), + stack, ), ) } @@ -3167,6 +3325,7 @@ impl PermissionsContainer { pub fn request_run( &self, cmd: Option<&str>, + stack: Option>, ) -> Result { Ok( self.inner.lock().run.request( @@ -3174,6 +3333,7 @@ impl PermissionsContainer { .map(|request| self.descriptor_parser.parse_run_query(request)) .transpose()? .as_ref(), + stack, ), ) } @@ -3182,6 +3342,7 @@ impl PermissionsContainer { pub fn request_ffi( &self, path: Option<&str>, + stack: Option>, ) -> Result { Ok( self.inner.lock().ffi.request( @@ -3193,6 +3354,7 @@ impl PermissionsContainer { }) .transpose()? .as_ref(), + stack, ), ) } @@ -3716,9 +3878,9 @@ mod tests { ]; for (path, is_ok) in cases { - assert_eq!(perms.check_read(path, "api").is_ok(), is_ok); - assert_eq!(perms.check_write(path, "api").is_ok(), is_ok); - assert_eq!(perms.check_ffi(path).is_ok(), is_ok); + assert_eq!(perms.check_read(path, "api", None).is_ok(), is_ok); + assert_eq!(perms.check_write(path, "api", None).is_ok(), is_ok); + assert_eq!(perms.check_ffi(path, None).is_ok(), is_ok); } } @@ -3775,7 +3937,7 @@ mod tests { let descriptor = NetDescriptor(host, Some(port)); assert_eq!( is_ok, - perms.net.check(&descriptor, None).is_ok(), + perms.net.check(&descriptor, None, None).is_ok(), "{descriptor}", ); } @@ -3820,7 +3982,7 @@ mod tests { let host = Host::parse(host_str).unwrap(); let descriptor = NetDescriptor(host, Some(port)); assert!( - perms.net.check(&descriptor, None).is_ok(), + perms.net.check(&descriptor, None, None).is_ok(), "expected {host_str}:{port} to pass" ); } @@ -3865,7 +4027,7 @@ mod tests { let host = Host::parse(host_str).unwrap(); let descriptor = NetDescriptor(host, Some(port)); assert!( - perms.net.check(&descriptor, None).is_err(), + perms.net.check(&descriptor, None, None).is_err(), "expected {host_str}:{port} to fail" ); } @@ -3932,7 +4094,12 @@ mod tests { for (url_str, is_ok) in url_tests { let u = Url::parse(url_str).unwrap(); - assert_eq!(is_ok, perms.check_net_url(&u, "api()").is_ok(), "{}", u); + assert_eq!( + is_ok, + perms.check_net_url(&u, "api()", None).is_ok(), + "{}", + u + ); } } @@ -4015,7 +4182,7 @@ mod tests { for (specifier, kind, expected) in fixtures { assert_eq!( - perms.check_specifier(&specifier, kind).is_ok(), + perms.check_specifier(&specifier, kind, None).is_ok(), expected, "{}", specifier, @@ -4185,45 +4352,45 @@ mod tests { { let prompt_value = PERMISSION_PROMPT_STUB_VALUE_SETTER.lock(); prompt_value.set(true); - assert_eq!(perms.read.request(Some(&read_query("/foo"))), PermissionState::Granted); + assert_eq!(perms.read.request(Some(&read_query("/foo")), None), PermissionState::Granted); assert_eq!(perms.read.query(None), PermissionState::Prompt); prompt_value.set(false); - assert_eq!(perms.read.request(Some(&read_query("/foo/bar"))), PermissionState::Granted); + assert_eq!(perms.read.request(Some(&read_query("/foo/bar")), None), PermissionState::Granted); prompt_value.set(false); - assert_eq!(perms.write.request(Some(&write_query("/foo"))), PermissionState::Denied); + assert_eq!(perms.write.request(Some(&write_query("/foo")), None), PermissionState::Denied); assert_eq!(perms.write.query(Some(&write_query("/foo/bar"))), PermissionState::Prompt); prompt_value.set(true); - assert_eq!(perms.write.request(None), PermissionState::Denied); + assert_eq!(perms.write.request(None, None), PermissionState::Denied); prompt_value.set(false); - assert_eq!(perms.ffi.request(Some(&ffi_query("/foo"))), PermissionState::Denied); + assert_eq!(perms.ffi.request(Some(&ffi_query("/foo")), None), PermissionState::Denied); assert_eq!(perms.ffi.query(Some(&ffi_query("/foo/bar"))), PermissionState::Prompt); prompt_value.set(true); - assert_eq!(perms.ffi.request(None), PermissionState::Denied); + assert_eq!(perms.ffi.request(None, None), PermissionState::Denied); prompt_value.set(true); - assert_eq!(perms.net.request(Some(&NetDescriptor(Host::must_parse("127.0.0.1"), None))), PermissionState::Granted); + assert_eq!(perms.net.request(Some(&NetDescriptor(Host::must_parse("127.0.0.1"), None)), None), PermissionState::Granted); prompt_value.set(false); - assert_eq!(perms.net.request(Some(&NetDescriptor(Host::must_parse("127.0.0.1"), Some(8000)))), PermissionState::Granted); + assert_eq!(perms.net.request(Some(&NetDescriptor(Host::must_parse("127.0.0.1"), Some(8000))), None), PermissionState::Granted); prompt_value.set(true); - assert_eq!(perms.env.request(Some("HOME")), PermissionState::Granted); + assert_eq!(perms.env.request(Some("HOME"), None), PermissionState::Granted); assert_eq!(perms.env.query(None), PermissionState::Prompt); prompt_value.set(false); - assert_eq!(perms.env.request(Some("HOME")), PermissionState::Granted); + assert_eq!(perms.env.request(Some("HOME"), None), PermissionState::Granted); prompt_value.set(true); let sys_desc = |name: &str| SysDescriptor::parse(name.to_string()).unwrap(); - assert_eq!(perms.sys.request(Some(&sys_desc("hostname"))), PermissionState::Granted); + assert_eq!(perms.sys.request(Some(&sys_desc("hostname")), None), PermissionState::Granted); assert_eq!(perms.sys.query(None), PermissionState::Prompt); prompt_value.set(false); - assert_eq!(perms.sys.request(Some(&sys_desc("hostname"))), PermissionState::Granted); + assert_eq!(perms.sys.request(Some(&sys_desc("hostname")), None), PermissionState::Granted); prompt_value.set(true); let run_query = RunQueryDescriptor::Path { requested: "deno".to_string(), resolved: PathBuf::from("/deno"), }; - assert_eq!(perms.run.request(Some(&run_query)), PermissionState::Granted); + assert_eq!(perms.run.request(Some(&run_query), None), PermissionState::Granted); assert_eq!(perms.run.query(None), PermissionState::Prompt); prompt_value.set(false); - assert_eq!(perms.run.request(Some(&run_query)), PermissionState::Granted); - assert_eq!(perms_no_prompt.read.request(Some(&read_query("/foo"))), PermissionState::Denied); + assert_eq!(perms.run.request(Some(&run_query), None), PermissionState::Granted); + assert_eq!(perms_no_prompt.read.request(Some(&read_query("/foo")), None), PermissionState::Denied); }; } @@ -4289,29 +4456,30 @@ mod tests { |path: &str| parser.parse_path_query(path).unwrap().into_ffi(); prompt_value.set(true); - assert!(perms.read.check(&read_query("/foo"), None).is_ok()); + assert!(perms.read.check(&read_query("/foo"), None, None).is_ok()); prompt_value.set(false); - assert!(perms.read.check(&read_query("/foo"), None).is_ok()); - assert!(perms.read.check(&read_query("/bar"), None).is_err()); + assert!(perms.read.check(&read_query("/foo"), None, None).is_ok()); + assert!(perms.read.check(&read_query("/bar"), None, None).is_err()); prompt_value.set(true); - assert!(perms.write.check(&write_query("/foo"), None).is_ok()); + assert!(perms.write.check(&write_query("/foo"), None, None).is_ok()); prompt_value.set(false); - assert!(perms.write.check(&write_query("/foo"), None).is_ok()); - assert!(perms.write.check(&write_query("/bar"), None).is_err()); + assert!(perms.write.check(&write_query("/foo"), None, None).is_ok()); + assert!(perms.write.check(&write_query("/bar"), None, None).is_err()); prompt_value.set(true); - assert!(perms.ffi.check(&ffi_query("/foo"), None).is_ok()); + assert!(perms.ffi.check(&ffi_query("/foo"), None, None).is_ok()); prompt_value.set(false); - assert!(perms.ffi.check(&ffi_query("/foo"), None).is_ok()); - assert!(perms.ffi.check(&ffi_query("/bar"), None).is_err()); + assert!(perms.ffi.check(&ffi_query("/foo"), None, None).is_ok()); + assert!(perms.ffi.check(&ffi_query("/bar"), None, None).is_err()); prompt_value.set(true); assert!(perms .net .check( &NetDescriptor(Host::must_parse("127.0.0.1"), Some(8000)), - None + None, + None, ) .is_ok()); prompt_value.set(false); @@ -4319,30 +4487,41 @@ mod tests { .net .check( &NetDescriptor(Host::must_parse("127.0.0.1"), Some(8000)), - None + None, + None, ) .is_ok()); assert!(perms .net .check( &NetDescriptor(Host::must_parse("127.0.0.1"), Some(8001)), - None + None, + None, ) .is_err()); assert!(perms .net - .check(&NetDescriptor(Host::must_parse("127.0.0.1"), None), None) + .check( + &NetDescriptor(Host::must_parse("127.0.0.1"), None), + None, + None + ) .is_err()); assert!(perms .net .check( &NetDescriptor(Host::must_parse("deno.land"), Some(8000)), - None + None, + None, ) .is_err()); assert!(perms .net - .check(&NetDescriptor(Host::must_parse("deno.land"), None), None) + .check( + &NetDescriptor(Host::must_parse("deno.land"), None), + None, + None + ) .is_err()); #[allow(clippy::disallowed_methods)] @@ -4355,7 +4534,8 @@ mod tests { requested: "cat".to_string(), resolved: cwd.join("cat") }, - None + None, + None, ) .is_ok()); prompt_value.set(false); @@ -4366,7 +4546,8 @@ mod tests { requested: "cat".to_string(), resolved: cwd.join("cat") }, - None + None, + None, ) .is_ok()); assert!(perms @@ -4376,21 +4557,22 @@ mod tests { requested: "ls".to_string(), resolved: cwd.join("ls") }, - None + None, + None, ) .is_err()); prompt_value.set(true); - assert!(perms.env.check("HOME", None).is_ok()); + assert!(perms.env.check("HOME", None, None).is_ok()); prompt_value.set(false); - assert!(perms.env.check("HOME", None).is_ok()); - assert!(perms.env.check("PATH", None).is_err()); + assert!(perms.env.check("HOME", None, None).is_ok()); + assert!(perms.env.check("PATH", None, None).is_err()); prompt_value.set(true); - assert!(perms.env.check("hostname", None).is_ok()); + assert!(perms.env.check("hostname", None, None).is_ok()); prompt_value.set(false); - assert!(perms.env.check("hostname", None).is_ok()); - assert!(perms.env.check("osRelease", None).is_err()); + assert!(perms.env.check("hostname", None, None).is_ok()); + assert!(perms.env.check("osRelease", None, None).is_err()); } #[test] @@ -4407,35 +4589,36 @@ mod tests { |path: &str| parser.parse_path_query(path).unwrap().into_ffi(); prompt_value.set(false); - assert!(perms.read.check(&read_query("/foo"), None).is_err()); + assert!(perms.read.check(&read_query("/foo"), None, None).is_err()); prompt_value.set(true); - assert!(perms.read.check(&read_query("/foo"), None).is_err()); - assert!(perms.read.check(&read_query("/bar"), None).is_ok()); + assert!(perms.read.check(&read_query("/foo"), None, None).is_err()); + assert!(perms.read.check(&read_query("/bar"), None, None).is_ok()); prompt_value.set(false); - assert!(perms.read.check(&read_query("/bar"), None).is_ok()); + assert!(perms.read.check(&read_query("/bar"), None, None).is_ok()); prompt_value.set(false); - assert!(perms.write.check(&write_query("/foo"), None).is_err()); + assert!(perms.write.check(&write_query("/foo"), None, None).is_err()); prompt_value.set(true); - assert!(perms.write.check(&write_query("/foo"), None).is_err()); - assert!(perms.write.check(&write_query("/bar"), None).is_ok()); + assert!(perms.write.check(&write_query("/foo"), None, None).is_err()); + assert!(perms.write.check(&write_query("/bar"), None, None).is_ok()); prompt_value.set(false); - assert!(perms.write.check(&write_query("/bar"), None).is_ok()); + assert!(perms.write.check(&write_query("/bar"), None, None).is_ok()); prompt_value.set(false); - assert!(perms.ffi.check(&ffi_query("/foo"), None).is_err()); + assert!(perms.ffi.check(&ffi_query("/foo"), None, None).is_err()); prompt_value.set(true); - assert!(perms.ffi.check(&ffi_query("/foo"), None).is_err()); - assert!(perms.ffi.check(&ffi_query("/bar"), None).is_ok()); + assert!(perms.ffi.check(&ffi_query("/foo"), None, None).is_err()); + assert!(perms.ffi.check(&ffi_query("/bar"), None, None).is_ok()); prompt_value.set(false); - assert!(perms.ffi.check(&ffi_query("/bar"), None).is_ok()); + assert!(perms.ffi.check(&ffi_query("/bar"), None, None).is_ok()); prompt_value.set(false); assert!(perms .net .check( &NetDescriptor(Host::must_parse("127.0.0.1"), Some(8000)), - None + None, + None, ) .is_err()); prompt_value.set(true); @@ -4443,21 +4626,24 @@ mod tests { .net .check( &NetDescriptor(Host::must_parse("127.0.0.1"), Some(8000)), - None + None, + None, ) .is_err()); assert!(perms .net .check( &NetDescriptor(Host::must_parse("127.0.0.1"), Some(8001)), - None + None, + None, ) .is_ok()); assert!(perms .net .check( &NetDescriptor(Host::must_parse("deno.land"), Some(8000)), - None + None, + None, ) .is_ok()); prompt_value.set(false); @@ -4465,14 +4651,16 @@ mod tests { .net .check( &NetDescriptor(Host::must_parse("127.0.0.1"), Some(8001)), - None + None, + None, ) .is_ok()); assert!(perms .net .check( &NetDescriptor(Host::must_parse("deno.land"), Some(8000)), - None + None, + None, ) .is_ok()); @@ -4486,7 +4674,8 @@ mod tests { requested: "cat".to_string(), resolved: cwd.join("cat") }, - None + None, + None, ) .is_err()); prompt_value.set(true); @@ -4497,7 +4686,8 @@ mod tests { requested: "cat".to_string(), resolved: cwd.join("cat") }, - None + None, + None, ) .is_err()); assert!(perms @@ -4507,7 +4697,8 @@ mod tests { requested: "ls".to_string(), resolved: cwd.join("ls") }, - None + None, + None, ) .is_ok()); prompt_value.set(false); @@ -4518,26 +4709,27 @@ mod tests { requested: "ls".to_string(), resolved: cwd.join("ls") }, - None + None, + None, ) .is_ok()); prompt_value.set(false); - assert!(perms.env.check("HOME", None).is_err()); + assert!(perms.env.check("HOME", None, None).is_err()); prompt_value.set(true); - assert!(perms.env.check("HOME", None).is_err()); - assert!(perms.env.check("PATH", None).is_ok()); + assert!(perms.env.check("HOME", None, None).is_err()); + assert!(perms.env.check("PATH", None, None).is_ok()); prompt_value.set(false); - assert!(perms.env.check("PATH", None).is_ok()); + assert!(perms.env.check("PATH", None, None).is_ok()); prompt_value.set(false); let sys_desc = |name: &str| SysDescriptor::parse(name.to_string()).unwrap(); - assert!(perms.sys.check(&sys_desc("hostname"), None).is_err()); + assert!(perms.sys.check(&sys_desc("hostname"), None, None).is_err()); prompt_value.set(true); - assert!(perms.sys.check(&sys_desc("hostname"), None).is_err()); - assert!(perms.sys.check(&sys_desc("osRelease"), None).is_ok()); + assert!(perms.sys.check(&sys_desc("hostname"), None, None).is_err()); + assert!(perms.sys.check(&sys_desc("osRelease"), None, None).is_ok()); prompt_value.set(false); - assert!(perms.sys.check(&sys_desc("osRelease"), None).is_ok()); + assert!(perms.sys.check(&sys_desc("osRelease"), None, None).is_ok()); } #[test] @@ -4556,10 +4748,10 @@ mod tests { }; prompt_value.set(true); - assert!(perms.env.check("HOME", None).is_ok()); + assert!(perms.env.check("HOME", None, None).is_ok()); prompt_value.set(false); - assert!(perms.env.check("HOME", None).is_ok()); - assert!(perms.env.check("hOmE", None).is_ok()); + assert!(perms.env.check("HOME", None, None).is_ok()); + assert!(perms.env.check("hOmE", None, None).is_ok()); assert_eq!(perms.env.revoke(Some("HomE")), PermissionState::Prompt); } @@ -4580,12 +4772,12 @@ mod tests { .unwrap(); let read_query = parser.parse_path_query("/foo").unwrap().into_read(); - perms.read.check_partial(&read_query, None).unwrap(); - assert!(perms.read.check(&read_query, None).is_err()); + perms.read.check_partial(&read_query, None, None).unwrap(); + assert!(perms.read.check(&read_query, None, None).is_err()); let write_query = parser.parse_path_query("/foo").unwrap().into_write(); - perms.write.check_partial(&write_query, None).unwrap(); - assert!(perms.write.check(&write_query, None).is_err()); + perms.write.check_partial(&write_query, None, None).unwrap(); + assert!(perms.write.check(&write_query, None, None).is_err()); } #[test] @@ -4610,7 +4802,7 @@ mod tests { ]; for (host, is_ok) in cases { - assert_eq!(perms.check_net(&(host, None), "api").is_ok(), is_ok); + assert_eq!(perms.check_net(&(host, None), "api", None).is_ok(), is_ok); } } @@ -4768,12 +4960,15 @@ mod tests { let main_perms = PermissionsContainer::new(Arc::new(parser), main_perms); assert_eq!( main_perms - .create_child_permissions(ChildPermissionsArg { - env: ChildUnaryPermissionArg::Inherit, - net: ChildUnaryPermissionArg::GrantedList(svec!["foo"]), - ffi: ChildUnaryPermissionArg::NotGranted, - ..ChildPermissionsArg::none() - }) + .create_child_permissions( + ChildPermissionsArg { + env: ChildUnaryPermissionArg::Inherit, + net: ChildUnaryPermissionArg::GrantedList(svec!["foo"]), + ffi: ChildUnaryPermissionArg::NotGranted, + ..ChildPermissionsArg::none() + }, + None + ) .unwrap() .inner .lock() @@ -4789,22 +4984,31 @@ mod tests { } ); assert!(main_perms - .create_child_permissions(ChildPermissionsArg { - net: ChildUnaryPermissionArg::Granted, - ..ChildPermissionsArg::none() - }) + .create_child_permissions( + ChildPermissionsArg { + net: ChildUnaryPermissionArg::Granted, + ..ChildPermissionsArg::none() + }, + None + ) .is_err()); assert!(main_perms - .create_child_permissions(ChildPermissionsArg { - net: ChildUnaryPermissionArg::GrantedList(svec!["foo", "bar", "baz"]), - ..ChildPermissionsArg::none() - }) + .create_child_permissions( + ChildPermissionsArg { + net: ChildUnaryPermissionArg::GrantedList(svec!["foo", "bar", "baz"]), + ..ChildPermissionsArg::none() + }, + None + ) .is_err()); assert!(main_perms - .create_child_permissions(ChildPermissionsArg { - ffi: ChildUnaryPermissionArg::GrantedList(svec!["foo"]), - ..ChildPermissionsArg::none() - }) + .create_child_permissions( + ChildPermissionsArg { + ffi: ChildUnaryPermissionArg::GrantedList(svec!["foo"]), + ..ChildPermissionsArg::none() + }, + None + ) .is_err()); } @@ -4826,11 +5030,14 @@ mod tests { ); prompt_value.set(true); let worker_perms = main_perms - .create_child_permissions(ChildPermissionsArg { - read: ChildUnaryPermissionArg::Granted, - run: ChildUnaryPermissionArg::GrantedList(svec!["foo", "bar"]), - ..ChildPermissionsArg::none() - }) + .create_child_permissions( + ChildPermissionsArg { + read: ChildUnaryPermissionArg::Granted, + run: ChildUnaryPermissionArg::GrantedList(svec!["foo", "bar"]), + ..ChildPermissionsArg::none() + }, + None, + ) .unwrap(); assert_eq!( main_perms.inner.lock().clone(), @@ -4865,10 +5072,14 @@ mod tests { .inner .lock() .write - .check(&parser.parse_path_query("foo").unwrap().into_write(), None) + .check( + &parser.parse_path_query("foo").unwrap().into_write(), + None, + None + ) .is_err()); let worker_perms = main_perms - .create_child_permissions(ChildPermissionsArg::none()) + .create_child_permissions(ChildPermissionsArg::none(), None) .unwrap(); assert_eq!( worker_perms.inner.lock().write.flag_denied_list.clone(), diff --git a/runtime/permissions/prompter.rs b/runtime/permissions/prompter.rs index 168a845a29611a..ebf83c7a7fca6b 100644 --- a/runtime/permissions/prompter.rs +++ b/runtime/permissions/prompter.rs @@ -1,5 +1,7 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +use crate::is_standalone; +use deno_core::error::JsStackFrame; use deno_core::parking_lot::Mutex; use deno_terminal::colors; use once_cell::sync::Lazy; @@ -10,8 +12,6 @@ use std::io::StderrLock; use std::io::StdinLock; use std::io::Write as IoWrite; -use crate::is_standalone; - /// Helper function to make control characters visible so users can see the underlying filename. fn escape_control_characters(s: &str) -> std::borrow::Cow { if !s.contains(|c: char| c.is_ascii_control() || c.is_control()) { @@ -58,13 +58,14 @@ pub fn permission_prompt( flag: &str, api_name: Option<&str>, is_unary: bool, + stack: Option>, ) -> PromptResponse { if let Some(before_callback) = MAYBE_BEFORE_PROMPT_CALLBACK.lock().as_mut() { before_callback(); } let r = PERMISSION_PROMPTER .lock() - .prompt(message, flag, api_name, is_unary); + .prompt(message, flag, api_name, is_unary, stack); if let Some(after_callback) = MAYBE_AFTER_PROMPT_CALLBACK.lock().as_mut() { after_callback(); } @@ -92,6 +93,7 @@ pub trait PermissionPrompter: Send + Sync { name: &str, api_name: Option<&str>, is_unary: bool, + stack: Option>, ) -> PromptResponse; } @@ -298,6 +300,7 @@ impl PermissionPrompter for TtyPrompter { name: &str, api_name: Option<&str>, is_unary: bool, + stack: Option>, ) -> PromptResponse { if !std::io::stdin().is_terminal() || !std::io::stderr().is_terminal() { return PromptResponse::Deny; @@ -354,6 +357,20 @@ impl PermissionPrompter for TtyPrompter { ) .unwrap(); } + if let Some(stack) = stack { + let len = stack.len(); + for (idx, frame) in stack.into_iter().enumerate() { + writeln!( + &mut output, + "┃ {} {}", + colors::gray(if idx != len - 1 { "├─" } else { "└─" }), + colors::gray(deno_core::error::format_frame::< + deno_core::error::NoAnsiColors, + >(&frame)) + ) + .unwrap(); + } + } let msg = format!( "Learn more at: {}", colors::cyan_with_underline(&format!( @@ -475,6 +492,7 @@ pub mod tests { _name: &str, _api_name: Option<&str>, _is_unary: bool, + _stack: Option>, ) -> PromptResponse { if STUB_PROMPT_VALUE.load(Ordering::SeqCst) { PromptResponse::Allow diff --git a/runtime/web_worker.rs b/runtime/web_worker.rs index 04cd3305e56ad7..d37c0a6a19a5d7 100644 --- a/runtime/web_worker.rs +++ b/runtime/web_worker.rs @@ -371,6 +371,7 @@ pub struct WebWorkerOptions { pub strace_ops: Option>, pub close_on_idle: bool, pub maybe_worker_metadata: Option, + pub enable_stack_trace_arg_in_ops: bool, } /// This struct is an implementation of `Worker` Web API @@ -572,6 +573,7 @@ impl WebWorker { validate_import_attributes_callback, )), import_assertions_support: deno_core::ImportAssertionsSupport::Error, + enable_stack_trace_arg_in_ops: options.enable_stack_trace_arg_in_ops, ..Default::default() }); diff --git a/runtime/worker.rs b/runtime/worker.rs index b780aefc1b28b7..aef21858335627 100644 --- a/runtime/worker.rs +++ b/runtime/worker.rs @@ -206,6 +206,7 @@ pub struct WorkerOptions { pub cache_storage_dir: Option, pub origin_storage_dir: Option, pub stdio: Stdio, + pub enable_stack_trace_arg_in_ops: bool, } impl Default for WorkerOptions { @@ -230,6 +231,7 @@ impl Default for WorkerOptions { create_params: Default::default(), bootstrap: Default::default(), stdio: Default::default(), + enable_stack_trace_arg_in_ops: false, } } } @@ -502,6 +504,7 @@ impl MainWorker { validate_import_attributes_callback, )), import_assertions_support: deno_core::ImportAssertionsSupport::Error, + enable_stack_trace_arg_in_ops: options.enable_stack_trace_arg_in_ops, eval_context_code_cache_cbs: services.v8_code_cache.map(|cache| { let cache_clone = cache.clone(); ( From 8821d3af4b3b1de4af51ba40e8e70bc318be94b3 Mon Sep 17 00:00:00 2001 From: crowlkats Date: Wed, 6 Nov 2024 03:39:40 +0100 Subject: [PATCH 2/4] add node, fs and websocket exzs --- cli/worker.rs | 8 +- ext/fs/lib.rs | 57 ++++-- ext/fs/ops.rs | 397 ++++++++++++++++++++++++++-------------- ext/node/lib.rs | 30 ++- ext/node/ops/fs.rs | 123 ++++++++----- ext/node/ops/http.rs | 6 +- ext/node/ops/os/mod.rs | 43 +++-- ext/node/ops/process.rs | 5 +- ext/websocket/lib.rs | 14 +- 9 files changed, 453 insertions(+), 230 deletions(-) diff --git a/cli/worker.rs b/cli/worker.rs index 4bebc01700ddc6..f86b45016b194b 100644 --- a/cli/worker.rs +++ b/cli/worker.rs @@ -596,7 +596,9 @@ impl CliMainWorkerFactory { origin_storage_dir, stdio, skip_op_registration: shared.options.skip_op_registration, - enable_stack_trace_arg_in_ops: crate::args::has_flag_env_var("DENO_TRACE_PERMISSIONS"), + enable_stack_trace_arg_in_ops: crate::args::has_flag_env_var( + "DENO_TRACE_PERMISSIONS", + ), }; let mut worker = MainWorker::bootstrap_from_options( @@ -793,7 +795,9 @@ fn create_web_worker_callback( strace_ops: shared.options.strace_ops.clone(), close_on_idle: args.close_on_idle, maybe_worker_metadata: args.maybe_worker_metadata, - enable_stack_trace_arg_in_ops: crate::args::has_flag_env_var("DENO_TRACE_PERMISSIONS"), + enable_stack_trace_arg_in_ops: crate::args::has_flag_env_var( + "DENO_TRACE_PERMISSIONS", + ), }; WebWorker::bootstrap_from_options(services, options) diff --git a/ext/fs/lib.rs b/ext/fs/lib.rs index dd852e6be82fd2..dad07b2bd02bb1 100644 --- a/ext/fs/lib.rs +++ b/ext/fs/lib.rs @@ -22,6 +22,7 @@ pub use crate::sync::MaybeSync; use crate::ops::*; +use deno_core::error::JsStackFrame; use deno_io::fs::FsError; use deno_permissions::PermissionCheckError; use std::borrow::Cow; @@ -36,56 +37,66 @@ pub trait FsPermissions { write: bool, path: &'a Path, api_name: &str, + stack: Option>, ) -> Result, FsError>; #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] fn check_read( &mut self, path: &str, api_name: &str, + stack: Option>, ) -> Result; #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] fn check_read_path<'a>( &mut self, path: &'a Path, api_name: &str, + stack: Option>, ) -> Result, PermissionCheckError>; fn check_read_all( &mut self, api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError>; fn check_read_blind( &mut self, p: &Path, display: &str, api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError>; #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] fn check_write( &mut self, path: &str, api_name: &str, + stack: Option>, ) -> Result; #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] fn check_write_path<'a>( &mut self, path: &'a Path, api_name: &str, + stack: Option>, ) -> Result, PermissionCheckError>; #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] fn check_write_partial( &mut self, path: &str, api_name: &str, + stack: Option>, ) -> Result; fn check_write_all( &mut self, api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError>; fn check_write_blind( &mut self, p: &Path, display: &str, api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError>; fn check<'a>( @@ -94,6 +105,7 @@ pub trait FsPermissions { open_options: &OpenOptions, path: &'a Path, api_name: &str, + stack: Option>, ) -> Result, FsError> { self.check_open( resolved, @@ -101,6 +113,7 @@ pub trait FsPermissions { open_options.write || open_options.append, path, api_name, + stack, ) } } @@ -113,10 +126,11 @@ impl FsPermissions for deno_permissions::PermissionsContainer { write: bool, path: &'a Path, api_name: &str, + stack: Option>, ) -> Result, FsError> { if resolved { self - .check_special_file(path, api_name) + .check_special_file(path, api_name, stack) .map_err(FsError::NotCapable)?; return Ok(Cow::Borrowed(path)); } @@ -125,15 +139,16 @@ impl FsPermissions for deno_permissions::PermissionsContainer { let read = read || !write; let mut path: Cow<'a, Path> = Cow::Borrowed(path); if read { - let resolved_path = FsPermissions::check_read_path(self, &path, api_name) - .map_err(|_| FsError::NotCapable("read"))?; + let resolved_path = + FsPermissions::check_read_path(self, &path, api_name, stack.clone()) + .map_err(|_| FsError::NotCapable("read"))?; if let Cow::Owned(resolved_path) = resolved_path { path = Cow::Owned(resolved_path); } } if write { let resolved_path = - FsPermissions::check_write_path(self, &path, api_name) + FsPermissions::check_write_path(self, &path, api_name, stack) .map_err(|_| FsError::NotCapable("write"))?; if let Cow::Owned(resolved_path) = resolved_path { path = Cow::Owned(resolved_path); @@ -146,19 +161,24 @@ impl FsPermissions for deno_permissions::PermissionsContainer { &mut self, path: &str, api_name: &str, + stack: Option>, ) -> Result { - deno_permissions::PermissionsContainer::check_read(self, path, api_name) + deno_permissions::PermissionsContainer::check_read( + self, path, api_name, stack, + ) } fn check_read_path<'a>( &mut self, path: &'a Path, api_name: &str, + stack: Option>, ) -> Result, PermissionCheckError> { deno_permissions::PermissionsContainer::check_read_path( self, path, Some(api_name), + stack, ) } fn check_read_blind( @@ -166,9 +186,10 @@ impl FsPermissions for deno_permissions::PermissionsContainer { path: &Path, display: &str, api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError> { deno_permissions::PermissionsContainer::check_read_blind( - self, path, display, api_name, + self, path, display, api_name, stack, ) } @@ -176,17 +197,21 @@ impl FsPermissions for deno_permissions::PermissionsContainer { &mut self, path: &str, api_name: &str, + stack: Option>, ) -> Result { - deno_permissions::PermissionsContainer::check_write(self, path, api_name) + deno_permissions::PermissionsContainer::check_write( + self, path, api_name, stack, + ) } fn check_write_path<'a>( &mut self, path: &'a Path, api_name: &str, + stack: Option>, ) -> Result, PermissionCheckError> { deno_permissions::PermissionsContainer::check_write_path( - self, path, api_name, + self, path, api_name, stack, ) } @@ -194,9 +219,10 @@ impl FsPermissions for deno_permissions::PermissionsContainer { &mut self, path: &str, api_name: &str, + stack: Option>, ) -> Result { deno_permissions::PermissionsContainer::check_write_partial( - self, path, api_name, + self, path, api_name, stack, ) } @@ -205,24 +231,31 @@ impl FsPermissions for deno_permissions::PermissionsContainer { p: &Path, display: &str, api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError> { deno_permissions::PermissionsContainer::check_write_blind( - self, p, display, api_name, + self, p, display, api_name, stack, ) } fn check_read_all( &mut self, api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError> { - deno_permissions::PermissionsContainer::check_read_all(self, api_name) + deno_permissions::PermissionsContainer::check_read_all( + self, api_name, stack, + ) } fn check_write_all( &mut self, api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError> { - deno_permissions::PermissionsContainer::check_write_all(self, api_name) + deno_permissions::PermissionsContainer::check_write_all( + self, api_name, stack, + ) } } diff --git a/ext/fs/ops.rs b/ext/fs/ops.rs index 9b76b49e613418..017deb268173d6 100644 --- a/ext/fs/ops.rs +++ b/ext/fs/ops.rs @@ -16,6 +16,7 @@ use crate::interface::FsDirEntry; use crate::interface::FsFileType; use crate::FsPermissions; use crate::OpenOptions; +use deno_core::error::JsStackFrame; use deno_core::op2; use deno_core::CancelFuture; use deno_core::CancelHandle; @@ -96,20 +97,22 @@ fn print_not_capable_info(standalone: bool, err: &'static str) -> String { fn sync_permission_check<'a, P: FsPermissions + 'static>( permissions: &'a mut P, api_name: &'static str, + stack: Option>, ) -> impl AccessCheckFn + 'a { move |resolved, path, options| { - permissions.check(resolved, options, path, api_name) + permissions.check(resolved, options, path, api_name, stack.clone()) } } fn async_permission_check( state: Rc>, api_name: &'static str, + stack: Option>, ) -> impl AccessCheckFn { move |resolved, path, options| { let mut state = state.borrow_mut(); let permissions = state.borrow_mut::

(); - permissions.check(resolved, options, path, api_name) + permissions.check(resolved, options, path, api_name, stack.clone()) } } @@ -140,32 +143,40 @@ fn map_permission_error( } } -#[op2] +#[op2(reentrant)] #[string] -pub fn op_fs_cwd

(state: &mut OpState) -> Result +pub fn op_fs_cwd

( + state: &mut OpState, + #[stack_trace] stack: Option>, +) -> Result where P: FsPermissions + 'static, { let fs = state.borrow::(); let path = fs.cwd()?; - state - .borrow_mut::

() - .check_read_blind(&path, "CWD", "Deno.cwd()")?; + state.borrow_mut::

().check_read_blind( + &path, + "CWD", + "Deno.cwd()", + stack, + )?; let path_str = path_into_string(path.into_os_string())?; Ok(path_str) } -#[op2(fast)] +#[op2(reentrant)] pub fn op_fs_chdir

( state: &mut OpState, #[string] directory: &str, + #[stack_trace] stack: Option>, ) -> Result<(), FsOpsError> where P: FsPermissions + 'static, { - let d = state - .borrow_mut::

() - .check_read(directory, "Deno.chdir()")?; + let d = + state + .borrow_mut::

() + .check_read(directory, "Deno.chdir()", stack)?; state .borrow::() .chdir(&d) @@ -182,12 +193,13 @@ where state.borrow::().umask(mask).context("umask") } -#[op2] +#[op2(reentrant)] #[smi] pub fn op_fs_open_sync

( state: &mut OpState, #[string] path: String, #[serde] options: Option, + #[stack_trace] stack: Option>, ) -> Result where P: FsPermissions + 'static, @@ -198,7 +210,7 @@ where let fs = state.borrow::().clone(); let mut access_check = - sync_permission_check::

(state.borrow_mut(), "Deno.openSync()"); + sync_permission_check::

(state.borrow_mut(), "Deno.openSync()", stack); let file = fs .open_sync(&path, options, Some(&mut access_check)) .map_err(|error| map_permission_error("open", error, &path))?; @@ -209,12 +221,13 @@ where Ok(rid) } -#[op2(async)] +#[op2(async, reentrant)] #[smi] pub async fn op_fs_open_async

( state: Rc>, #[string] path: String, #[serde] options: Option, + #[stack_trace] stack: Option>, ) -> Result where P: FsPermissions + 'static, @@ -223,7 +236,7 @@ where let options = options.unwrap_or_else(OpenOptions::read); let mut access_check = - async_permission_check::

(state.clone(), "Deno.open()"); + async_permission_check::

(state.clone(), "Deno.open()", stack); let fs = state.borrow().borrow::().clone(); let file = fs .open_async(path.clone(), options, Some(&mut access_check)) @@ -237,21 +250,23 @@ where Ok(rid) } -#[op2] +#[op2(reentrant)] pub fn op_fs_mkdir_sync

( state: &mut OpState, #[string] path: String, recursive: bool, mode: Option, + #[stack_trace] stack: Option>, ) -> Result<(), FsOpsError> where P: FsPermissions + 'static, { let mode = mode.unwrap_or(0o777) & 0o777; - let path = state - .borrow_mut::

() - .check_write(&path, "Deno.mkdirSync()")?; + let path = + state + .borrow_mut::

() + .check_write(&path, "Deno.mkdirSync()", stack)?; let fs = state.borrow::(); fs.mkdir_sync(&path, recursive, Some(mode)) @@ -260,12 +275,13 @@ where Ok(()) } -#[op2(async)] +#[op2(async, reentrant)] pub async fn op_fs_mkdir_async

( state: Rc>, #[string] path: String, recursive: bool, mode: Option, + #[stack_trace] stack: Option>, ) -> Result<(), FsOpsError> where P: FsPermissions + 'static, @@ -274,7 +290,10 @@ where let (fs, path) = { let mut state = state.borrow_mut(); - let path = state.borrow_mut::

().check_write(&path, "Deno.mkdir()")?; + let path = + state + .borrow_mut::

() + .check_write(&path, "Deno.mkdir()", stack)?; (state.borrow::().clone(), path) }; @@ -285,35 +304,41 @@ where Ok(()) } -#[op2(fast)] +#[op2(reentrant)] pub fn op_fs_chmod_sync

( state: &mut OpState, #[string] path: String, mode: u32, + #[stack_trace] stack: Option>, ) -> Result<(), FsOpsError> where P: FsPermissions + 'static, { - let path = state - .borrow_mut::

() - .check_write(&path, "Deno.chmodSync()")?; + let path = + state + .borrow_mut::

() + .check_write(&path, "Deno.chmodSync()", stack)?; let fs = state.borrow::(); fs.chmod_sync(&path, mode).context_path("chmod", &path)?; Ok(()) } -#[op2(async)] +#[op2(async, reentrant)] pub async fn op_fs_chmod_async

( state: Rc>, #[string] path: String, mode: u32, + #[stack_trace] stack: Option>, ) -> Result<(), FsOpsError> where P: FsPermissions + 'static, { let (fs, path) = { let mut state = state.borrow_mut(); - let path = state.borrow_mut::

().check_write(&path, "Deno.chmod()")?; + let path = + state + .borrow_mut::

() + .check_write(&path, "Deno.chmod()", stack)?; (state.borrow::().clone(), path) }; fs.chmod_async(path.clone(), mode) @@ -322,38 +347,44 @@ where Ok(()) } -#[op2] +#[op2(reentrant)] pub fn op_fs_chown_sync

( state: &mut OpState, #[string] path: String, uid: Option, gid: Option, + #[stack_trace] stack: Option>, ) -> Result<(), FsOpsError> where P: FsPermissions + 'static, { - let path = state - .borrow_mut::

() - .check_write(&path, "Deno.chownSync()")?; + let path = + state + .borrow_mut::

() + .check_write(&path, "Deno.chownSync()", stack)?; let fs = state.borrow::(); fs.chown_sync(&path, uid, gid) .context_path("chown", &path)?; Ok(()) } -#[op2(async)] +#[op2(async, reentrant)] pub async fn op_fs_chown_async

( state: Rc>, #[string] path: String, uid: Option, gid: Option, + #[stack_trace] stack: Option>, ) -> Result<(), FsOpsError> where P: FsPermissions + 'static, { let (fs, path) = { let mut state = state.borrow_mut(); - let path = state.borrow_mut::

().check_write(&path, "Deno.chown()")?; + let path = + state + .borrow_mut::

() + .check_write(&path, "Deno.chown()", stack)?; (state.borrow::().clone(), path) }; fs.chown_async(path.clone(), uid, gid) @@ -362,18 +393,20 @@ where Ok(()) } -#[op2(fast)] +#[op2(reentrant)] pub fn op_fs_remove_sync

( state: &mut OpState, #[string] path: &str, recursive: bool, + #[stack_trace] stack: Option>, ) -> Result<(), FsOpsError> where P: FsPermissions + 'static, { - let path = state - .borrow_mut::

() - .check_write(path, "Deno.removeSync()")?; + let path = + state + .borrow_mut::

() + .check_write(path, "Deno.removeSync()", stack)?; let fs = state.borrow::(); fs.remove_sync(&path, recursive) @@ -382,11 +415,12 @@ where Ok(()) } -#[op2(async)] +#[op2(async, reentrant)] pub async fn op_fs_remove_async

( state: Rc>, #[string] path: String, recursive: bool, + #[stack_trace] stack: Option>, ) -> Result<(), FsOpsError> where P: FsPermissions + 'static, @@ -396,11 +430,13 @@ where let path = if recursive { state .borrow_mut::

() - .check_write(&path, "Deno.remove()")? + .check_write(&path, "Deno.remove()", stack)? } else { - state - .borrow_mut::

() - .check_write_partial(&path, "Deno.remove()")? + state.borrow_mut::

().check_write_partial( + &path, + "Deno.remove()", + stack, + )? }; (state.borrow::().clone(), path) @@ -413,18 +449,20 @@ where Ok(()) } -#[op2(fast)] +#[op2(reentrant)] pub fn op_fs_copy_file_sync

( state: &mut OpState, #[string] from: &str, #[string] to: &str, + #[stack_trace] stack: Option>, ) -> Result<(), FsOpsError> where P: FsPermissions + 'static, { let permissions = state.borrow_mut::

(); - let from = permissions.check_read(from, "Deno.copyFileSync()")?; - let to = permissions.check_write(to, "Deno.copyFileSync()")?; + let from = + permissions.check_read(from, "Deno.copyFileSync()", stack.clone())?; + let to = permissions.check_write(to, "Deno.copyFileSync()", stack)?; let fs = state.borrow::(); fs.copy_file_sync(&from, &to) @@ -433,11 +471,12 @@ where Ok(()) } -#[op2(async)] +#[op2(async, reentrant)] pub async fn op_fs_copy_file_async

( state: Rc>, #[string] from: String, #[string] to: String, + #[stack_trace] stack: Option>, ) -> Result<(), FsOpsError> where P: FsPermissions + 'static, @@ -445,8 +484,9 @@ where let (fs, from, to) = { let mut state = state.borrow_mut(); let permissions = state.borrow_mut::

(); - let from = permissions.check_read(&from, "Deno.copyFile()")?; - let to = permissions.check_write(&to, "Deno.copyFile()")?; + let from = + permissions.check_read(&from, "Deno.copyFile()", stack.clone())?; + let to = permissions.check_write(&to, "Deno.copyFile()", stack)?; (state.borrow::().clone(), from, to) }; @@ -457,18 +497,20 @@ where Ok(()) } -#[op2(fast)] +#[op2(reentrant)] pub fn op_fs_stat_sync

( state: &mut OpState, #[string] path: String, #[buffer] stat_out_buf: &mut [u32], + #[stack_trace] stack: Option>, ) -> Result<(), FsOpsError> where P: FsPermissions + 'static, { - let path = state - .borrow_mut::

() - .check_read(&path, "Deno.statSync()")?; + let path = + state + .borrow_mut::

() + .check_read(&path, "Deno.statSync()", stack)?; let fs = state.borrow::(); let stat = fs.stat_sync(&path).context_path("stat", &path)?; let serializable_stat = SerializableStat::from(stat); @@ -476,11 +518,12 @@ where Ok(()) } -#[op2(async)] +#[op2(async, reentrant)] #[serde] pub async fn op_fs_stat_async

( state: Rc>, #[string] path: String, + #[stack_trace] stack: Option>, ) -> Result where P: FsPermissions + 'static, @@ -488,7 +531,7 @@ where let (fs, path) = { let mut state = state.borrow_mut(); let permissions = state.borrow_mut::

(); - let path = permissions.check_read(&path, "Deno.stat()")?; + let path = permissions.check_read(&path, "Deno.stat()", stack)?; (state.borrow::().clone(), path) }; let stat = fs @@ -498,18 +541,20 @@ where Ok(SerializableStat::from(stat)) } -#[op2(fast)] +#[op2(reentrant)] pub fn op_fs_lstat_sync

( state: &mut OpState, #[string] path: String, #[buffer] stat_out_buf: &mut [u32], + #[stack_trace] stack: Option>, ) -> Result<(), FsOpsError> where P: FsPermissions + 'static, { - let path = state - .borrow_mut::

() - .check_read(&path, "Deno.lstatSync()")?; + let path = + state + .borrow_mut::

() + .check_read(&path, "Deno.lstatSync()", stack)?; let fs = state.borrow::(); let stat = fs.lstat_sync(&path).context_path("lstat", &path)?; let serializable_stat = SerializableStat::from(stat); @@ -517,11 +562,12 @@ where Ok(()) } -#[op2(async)] +#[op2(async, reentrant)] #[serde] pub async fn op_fs_lstat_async

( state: Rc>, #[string] path: String, + #[stack_trace] stack: Option>, ) -> Result where P: FsPermissions + 'static, @@ -529,7 +575,7 @@ where let (fs, path) = { let mut state = state.borrow_mut(); let permissions = state.borrow_mut::

(); - let path = permissions.check_read(&path, "Deno.lstat()")?; + let path = permissions.check_read(&path, "Deno.lstat()", stack)?; (state.borrow::().clone(), path) }; let stat = fs @@ -539,20 +585,27 @@ where Ok(SerializableStat::from(stat)) } -#[op2] +#[op2(reentrant)] #[string] pub fn op_fs_realpath_sync

( state: &mut OpState, #[string] path: String, + #[stack_trace] stack: Option>, ) -> Result where P: FsPermissions + 'static, { let fs = state.borrow::().clone(); let permissions = state.borrow_mut::

(); - let path = permissions.check_read(&path, "Deno.realPathSync()")?; + let path = + permissions.check_read(&path, "Deno.realPathSync()", stack.clone())?; if path.is_relative() { - permissions.check_read_blind(&fs.cwd()?, "CWD", "Deno.realPathSync()")?; + permissions.check_read_blind( + &fs.cwd()?, + "CWD", + "Deno.realPathSync()", + stack, + )?; } let resolved_path = @@ -562,11 +615,12 @@ where Ok(path_string) } -#[op2(async)] +#[op2(async, reentrant)] #[string] pub async fn op_fs_realpath_async

( state: Rc>, #[string] path: String, + #[stack_trace] stack: Option>, ) -> Result where P: FsPermissions + 'static, @@ -575,9 +629,15 @@ where let mut state = state.borrow_mut(); let fs = state.borrow::().clone(); let permissions = state.borrow_mut::

(); - let path = permissions.check_read(&path, "Deno.realPath()")?; + let path = + permissions.check_read(&path, "Deno.realPath()", stack.clone())?; if path.is_relative() { - permissions.check_read_blind(&fs.cwd()?, "CWD", "Deno.realPath()")?; + permissions.check_read_blind( + &fs.cwd()?, + "CWD", + "Deno.realPath()", + stack, + )?; } (fs, path) }; @@ -590,18 +650,20 @@ where Ok(path_string) } -#[op2] +#[op2(reentrant)] #[serde] pub fn op_fs_read_dir_sync

( state: &mut OpState, #[string] path: String, + #[stack_trace] stack: Option>, ) -> Result, FsOpsError> where P: FsPermissions + 'static, { - let path = state - .borrow_mut::

() - .check_read(&path, "Deno.readDirSync()")?; + let path = + state + .borrow_mut::

() + .check_read(&path, "Deno.readDirSync()", stack)?; let fs = state.borrow::(); let entries = fs.read_dir_sync(&path).context_path("readdir", &path)?; @@ -609,20 +671,22 @@ where Ok(entries) } -#[op2(async)] +#[op2(async, reentrant)] #[serde] pub async fn op_fs_read_dir_async

( state: Rc>, #[string] path: String, + #[stack_trace] stack: Option>, ) -> Result, FsOpsError> where P: FsPermissions + 'static, { let (fs, path) = { let mut state = state.borrow_mut(); - let path = state - .borrow_mut::

() - .check_read(&path, "Deno.readDir()")?; + let path = + state + .borrow_mut::

() + .check_read(&path, "Deno.readDir()", stack)?; (state.borrow::().clone(), path) }; @@ -634,19 +698,23 @@ where Ok(entries) } -#[op2(fast)] +#[op2(reentrant)] pub fn op_fs_rename_sync

( state: &mut OpState, #[string] oldpath: String, #[string] newpath: String, + #[stack_trace] stack: Option>, ) -> Result<(), FsOpsError> where P: FsPermissions + 'static, { let permissions = state.borrow_mut::

(); - let _ = permissions.check_read(&oldpath, "Deno.renameSync()")?; - let oldpath = permissions.check_write(&oldpath, "Deno.renameSync()")?; - let newpath = permissions.check_write(&newpath, "Deno.renameSync()")?; + let _ = + permissions.check_read(&oldpath, "Deno.renameSync()", stack.clone())?; + let oldpath = + permissions.check_write(&oldpath, "Deno.renameSync()", stack.clone())?; + let newpath = + permissions.check_write(&newpath, "Deno.renameSync()", stack)?; let fs = state.borrow::(); fs.rename_sync(&oldpath, &newpath) @@ -655,11 +723,12 @@ where Ok(()) } -#[op2(async)] +#[op2(async, reentrant)] pub async fn op_fs_rename_async

( state: Rc>, #[string] oldpath: String, #[string] newpath: String, + #[stack_trace] stack: Option>, ) -> Result<(), FsOpsError> where P: FsPermissions + 'static, @@ -667,9 +736,10 @@ where let (fs, oldpath, newpath) = { let mut state = state.borrow_mut(); let permissions = state.borrow_mut::

(); - _ = permissions.check_read(&oldpath, "Deno.rename()")?; - let oldpath = permissions.check_write(&oldpath, "Deno.rename()")?; - let newpath = permissions.check_write(&newpath, "Deno.rename()")?; + _ = permissions.check_read(&oldpath, "Deno.rename()", stack.clone())?; + let oldpath = + permissions.check_write(&oldpath, "Deno.rename()", stack.clone())?; + let newpath = permissions.check_write(&newpath, "Deno.rename()", stack)?; (state.borrow::().clone(), oldpath, newpath) }; @@ -680,20 +750,22 @@ where Ok(()) } -#[op2(fast)] +#[op2(reentrant)] pub fn op_fs_link_sync

( state: &mut OpState, #[string] oldpath: &str, #[string] newpath: &str, + #[stack_trace] stack: Option>, ) -> Result<(), FsOpsError> where P: FsPermissions + 'static, { let permissions = state.borrow_mut::

(); - _ = permissions.check_read(oldpath, "Deno.linkSync()")?; - let oldpath = permissions.check_write(oldpath, "Deno.linkSync()")?; - _ = permissions.check_read(newpath, "Deno.linkSync()")?; - let newpath = permissions.check_write(newpath, "Deno.linkSync()")?; + _ = permissions.check_read(oldpath, "Deno.linkSync()", stack.clone())?; + let oldpath = + permissions.check_write(oldpath, "Deno.linkSync()", stack.clone())?; + _ = permissions.check_read(newpath, "Deno.linkSync()", stack.clone())?; + let newpath = permissions.check_write(newpath, "Deno.linkSync()", stack)?; let fs = state.borrow::(); fs.link_sync(&oldpath, &newpath) @@ -702,11 +774,12 @@ where Ok(()) } -#[op2(async)] +#[op2(async, reentrant)] pub async fn op_fs_link_async

( state: Rc>, #[string] oldpath: String, #[string] newpath: String, + #[stack_trace] stack: Option>, ) -> Result<(), FsOpsError> where P: FsPermissions + 'static, @@ -714,10 +787,11 @@ where let (fs, oldpath, newpath) = { let mut state = state.borrow_mut(); let permissions = state.borrow_mut::

(); - _ = permissions.check_read(&oldpath, "Deno.link()")?; - let oldpath = permissions.check_write(&oldpath, "Deno.link()")?; - _ = permissions.check_read(&newpath, "Deno.link()")?; - let newpath = permissions.check_write(&newpath, "Deno.link()")?; + _ = permissions.check_read(&oldpath, "Deno.link()", stack.clone())?; + let oldpath = + permissions.check_write(&oldpath, "Deno.link()", stack.clone())?; + _ = permissions.check_read(&newpath, "Deno.link()", stack.clone())?; + let newpath = permissions.check_write(&newpath, "Deno.link()", stack)?; (state.borrow::().clone(), oldpath, newpath) }; @@ -728,12 +802,13 @@ where Ok(()) } -#[op2] +#[op2(reentrant)] pub fn op_fs_symlink_sync

( state: &mut OpState, #[string] oldpath: &str, #[string] newpath: &str, #[serde] file_type: Option, + #[stack_trace] stack: Option>, ) -> Result<(), FsOpsError> where P: FsPermissions + 'static, @@ -742,8 +817,8 @@ where let newpath = PathBuf::from(newpath); let permissions = state.borrow_mut::

(); - permissions.check_write_all("Deno.symlinkSync()")?; - permissions.check_read_all("Deno.symlinkSync()")?; + permissions.check_write_all("Deno.symlinkSync()", stack.clone())?; + permissions.check_read_all("Deno.symlinkSync()", stack)?; let fs = state.borrow::(); fs.symlink_sync(&oldpath, &newpath, file_type) @@ -752,12 +827,13 @@ where Ok(()) } -#[op2(async)] +#[op2(async, reentrant)] pub async fn op_fs_symlink_async

( state: Rc>, #[string] oldpath: String, #[string] newpath: String, #[serde] file_type: Option, + #[stack_trace] stack: Option>, ) -> Result<(), FsOpsError> where P: FsPermissions + 'static, @@ -768,8 +844,8 @@ where let fs = { let mut state = state.borrow_mut(); let permissions = state.borrow_mut::

(); - permissions.check_write_all("Deno.symlink()")?; - permissions.check_read_all("Deno.symlink()")?; + permissions.check_write_all("Deno.symlink()", stack.clone())?; + permissions.check_read_all("Deno.symlink()", stack)?; state.borrow::().clone() }; @@ -780,18 +856,20 @@ where Ok(()) } -#[op2] +#[op2(reentrant)] #[string] pub fn op_fs_read_link_sync

( state: &mut OpState, #[string] path: String, + #[stack_trace] stack: Option>, ) -> Result where P: FsPermissions + 'static, { - let path = state - .borrow_mut::

() - .check_read(&path, "Deno.readLink()")?; + let path = + state + .borrow_mut::

() + .check_read(&path, "Deno.readLink()", stack)?; let fs = state.borrow::(); @@ -805,15 +883,17 @@ where pub async fn op_fs_read_link_async

( state: Rc>, #[string] path: String, + #[stack_trace] stack: Option>, ) -> Result where P: FsPermissions + 'static, { let (fs, path) = { let mut state = state.borrow_mut(); - let path = state - .borrow_mut::

() - .check_read(&path, "Deno.readLink()")?; + let path = + state + .borrow_mut::

() + .check_read(&path, "Deno.readLink()", stack)?; (state.borrow::().clone(), path) }; @@ -825,18 +905,20 @@ where Ok(target_string) } -#[op2(fast)] +#[op2(reentrant)] pub fn op_fs_truncate_sync

( state: &mut OpState, #[string] path: &str, #[number] len: u64, + #[stack_trace] stack: Option>, ) -> Result<(), FsOpsError> where P: FsPermissions + 'static, { - let path = state - .borrow_mut::

() - .check_write(path, "Deno.truncateSync()")?; + let path = + state + .borrow_mut::

() + .check_write(path, "Deno.truncateSync()", stack)?; let fs = state.borrow::(); fs.truncate_sync(&path, len) @@ -845,20 +927,22 @@ where Ok(()) } -#[op2(async)] +#[op2(async, reentrant)] pub async fn op_fs_truncate_async

( state: Rc>, #[string] path: String, #[number] len: u64, + #[stack_trace] stack: Option>, ) -> Result<(), FsOpsError> where P: FsPermissions + 'static, { let (fs, path) = { let mut state = state.borrow_mut(); - let path = state - .borrow_mut::

() - .check_write(&path, "Deno.truncate()")?; + let path = + state + .borrow_mut::

() + .check_write(&path, "Deno.truncate()", stack)?; (state.borrow::().clone(), path) }; @@ -869,7 +953,7 @@ where Ok(()) } -#[op2(fast)] +#[op2(reentrant)] pub fn op_fs_utime_sync

( state: &mut OpState, #[string] path: &str, @@ -877,11 +961,15 @@ pub fn op_fs_utime_sync

( #[smi] atime_nanos: u32, #[number] mtime_secs: i64, #[smi] mtime_nanos: u32, + #[stack_trace] stack: Option>, ) -> Result<(), FsOpsError> where P: FsPermissions + 'static, { - let path = state.borrow_mut::

().check_write(path, "Deno.utime()")?; + let path = + state + .borrow_mut::

() + .check_write(path, "Deno.utime()", stack)?; let fs = state.borrow::(); fs.utime_sync(&path, atime_secs, atime_nanos, mtime_secs, mtime_nanos) @@ -890,7 +978,7 @@ where Ok(()) } -#[op2(async)] +#[op2(async, reentrant)] pub async fn op_fs_utime_async

( state: Rc>, #[string] path: String, @@ -898,13 +986,17 @@ pub async fn op_fs_utime_async

( #[smi] atime_nanos: u32, #[number] mtime_secs: i64, #[smi] mtime_nanos: u32, + #[stack_trace] stack: Option>, ) -> Result<(), FsOpsError> where P: FsPermissions + 'static, { let (fs, path) = { let mut state = state.borrow_mut(); - let path = state.borrow_mut::

().check_write(&path, "Deno.utime()")?; + let path = + state + .borrow_mut::

() + .check_write(&path, "Deno.utime()", stack)?; (state.borrow::().clone(), path) }; @@ -921,13 +1013,14 @@ where Ok(()) } -#[op2] +#[op2(reentrant)] #[string] pub fn op_fs_make_temp_dir_sync

( state: &mut OpState, #[string] dir_arg: Option, #[string] prefix: Option, #[string] suffix: Option, + #[stack_trace] stack: Option>, ) -> Result where P: FsPermissions + 'static, @@ -936,6 +1029,7 @@ where state, dir_arg.as_deref(), "Deno.makeTempDirSync()", + stack, )?; let mut rng = thread_rng(); @@ -963,13 +1057,14 @@ where .context("tmpdir") } -#[op2(async)] +#[op2(async, reentrant)] #[string] pub async fn op_fs_make_temp_dir_async

( state: Rc>, #[string] dir_arg: Option, #[string] prefix: Option, #[string] suffix: Option, + #[stack_trace] stack: Option>, ) -> Result where P: FsPermissions + 'static, @@ -978,6 +1073,7 @@ where state, dir_arg.as_deref(), "Deno.makeTempDir()", + stack, )?; let mut rng = thread_rng(); @@ -1009,13 +1105,14 @@ where .context("tmpdir") } -#[op2] +#[op2(reentrant)] #[string] pub fn op_fs_make_temp_file_sync

( state: &mut OpState, #[string] dir_arg: Option, #[string] prefix: Option, #[string] suffix: Option, + #[stack_trace] stack: Option>, ) -> Result where P: FsPermissions + 'static, @@ -1024,6 +1121,7 @@ where state, dir_arg.as_deref(), "Deno.makeTempFileSync()", + stack, )?; let open_opts = OpenOptions { @@ -1057,13 +1155,14 @@ where .context("tmpfile") } -#[op2(async)] +#[op2(async, reentrant)] #[string] pub async fn op_fs_make_temp_file_async

( state: Rc>, #[string] dir_arg: Option, #[string] prefix: Option, #[string] suffix: Option, + #[stack_trace] stack: Option>, ) -> Result where P: FsPermissions + 'static, @@ -1072,6 +1171,7 @@ where state, dir_arg.as_deref(), "Deno.makeTempFile()", + stack, )?; let open_opts = OpenOptions { @@ -1126,18 +1226,19 @@ fn make_temp_check_sync

( state: &mut OpState, dir: Option<&str>, api_name: &str, + stack: Option>, ) -> Result<(PathBuf, FileSystemRc), FsOpsError> where P: FsPermissions + 'static, { let fs = state.borrow::().clone(); let dir = match dir { - Some(dir) => state.borrow_mut::

().check_write(dir, api_name)?, + Some(dir) => state.borrow_mut::

().check_write(dir, api_name, stack)?, None => { let dir = fs.tmp_dir().context("tmpdir")?; state .borrow_mut::

() - .check_write_blind(&dir, "TMP", api_name)?; + .check_write_blind(&dir, "TMP", api_name, stack)?; dir } }; @@ -1148,6 +1249,7 @@ fn make_temp_check_async

( state: Rc>, dir: Option<&str>, api_name: &str, + stack: Option>, ) -> Result<(PathBuf, FileSystemRc), FsOpsError> where P: FsPermissions + 'static, @@ -1155,12 +1257,12 @@ where let mut state = state.borrow_mut(); let fs = state.borrow::().clone(); let dir = match dir { - Some(dir) => state.borrow_mut::

().check_write(dir, api_name)?, + Some(dir) => state.borrow_mut::

().check_write(dir, api_name, stack)?, None => { let dir = fs.tmp_dir().context("tmpdir")?; state .borrow_mut::

() - .check_write_blind(&dir, "TMP", api_name)?; + .check_write_blind(&dir, "TMP", api_name, stack)?; dir } }; @@ -1227,7 +1329,7 @@ fn tmp_name( Ok(path) } -#[op2] +#[op2(reentrant)] pub fn op_fs_write_file_sync

( state: &mut OpState, #[string] path: String, @@ -1236,6 +1338,7 @@ pub fn op_fs_write_file_sync

( create: bool, create_new: bool, #[buffer] data: JsBuffer, + #[stack_trace] stack: Option>, ) -> Result<(), FsOpsError> where P: FsPermissions + 'static, @@ -1244,8 +1347,11 @@ where let options = OpenOptions::write(create, append, create_new, mode); let fs = state.borrow::().clone(); - let mut access_check = - sync_permission_check::

(state.borrow_mut(), "Deno.writeFileSync()"); + let mut access_check = sync_permission_check::

( + state.borrow_mut(), + "Deno.writeFileSync()", + stack, + ); fs.write_file_sync(&path, options, Some(&mut access_check), &data) .map_err(|error| map_permission_error("writefile", error, &path))?; @@ -1253,7 +1359,7 @@ where Ok(()) } -#[op2(async)] +#[op2(async, reentrant)] #[allow(clippy::too_many_arguments)] pub async fn op_fs_write_file_async

( state: Rc>, @@ -1264,6 +1370,7 @@ pub async fn op_fs_write_file_async

( create_new: bool, #[buffer] data: JsBuffer, #[smi] cancel_rid: Option, + #[stack_trace] stack: Option>, ) -> Result<(), FsOpsError> where P: FsPermissions + 'static, @@ -1273,7 +1380,7 @@ where let options = OpenOptions::write(create, append, create_new, mode); let mut access_check = - async_permission_check::

(state.clone(), "Deno.writeFile()"); + async_permission_check::

(state.clone(), "Deno.writeFile()", stack); let (fs, cancel_handle) = { let state = state.borrow_mut(); let cancel_handle = cancel_rid @@ -1307,11 +1414,12 @@ where Ok(()) } -#[op2] +#[op2(reentrant)] #[serde] pub fn op_fs_read_file_sync

( state: &mut OpState, #[string] path: String, + #[stack_trace] stack: Option>, ) -> Result where P: FsPermissions + 'static, @@ -1319,8 +1427,11 @@ where let path = PathBuf::from(path); let fs = state.borrow::().clone(); - let mut access_check = - sync_permission_check::

(state.borrow_mut(), "Deno.readFileSync()"); + let mut access_check = sync_permission_check::

( + state.borrow_mut(), + "Deno.readFileSync()", + stack, + ); let buf = fs .read_file_sync(&path, Some(&mut access_check)) .map_err(|error| map_permission_error("readfile", error, &path))?; @@ -1328,12 +1439,13 @@ where Ok(buf.into()) } -#[op2(async)] +#[op2(async, reentrant)] #[serde] pub async fn op_fs_read_file_async

( state: Rc>, #[string] path: String, #[smi] cancel_rid: Option, + #[stack_trace] stack: Option>, ) -> Result where P: FsPermissions + 'static, @@ -1341,7 +1453,7 @@ where let path = PathBuf::from(path); let mut access_check = - async_permission_check::

(state.clone(), "Deno.readFile()"); + async_permission_check::

(state.clone(), "Deno.readFile()", stack); let (fs, cancel_handle) = { let state = state.borrow(); let cancel_handle = cancel_rid @@ -1370,11 +1482,12 @@ where Ok(buf.into()) } -#[op2] +#[op2(reentrant)] #[string] pub fn op_fs_read_file_text_sync

( state: &mut OpState, #[string] path: String, + #[stack_trace] stack: Option>, ) -> Result where P: FsPermissions + 'static, @@ -1382,8 +1495,11 @@ where let path = PathBuf::from(path); let fs = state.borrow::().clone(); - let mut access_check = - sync_permission_check::

(state.borrow_mut(), "Deno.readFileSync()"); + let mut access_check = sync_permission_check::

( + state.borrow_mut(), + "Deno.readFileSync()", + stack, + ); let str = fs .read_text_file_lossy_sync(&path, Some(&mut access_check)) .map_err(|error| map_permission_error("readfile", error, &path))?; @@ -1391,12 +1507,13 @@ where Ok(str) } -#[op2(async)] +#[op2(async, reentrant)] #[string] pub async fn op_fs_read_file_text_async

( state: Rc>, #[string] path: String, #[smi] cancel_rid: Option, + #[stack_trace] stack: Option>, ) -> Result where P: FsPermissions + 'static, @@ -1404,7 +1521,7 @@ where let path = PathBuf::from(path); let mut access_check = - async_permission_check::

(state.clone(), "Deno.readFile()"); + async_permission_check::

(state.clone(), "Deno.readFile()", stack); let (fs, cancel_handle) = { let state = state.borrow_mut(); let cancel_handle = cancel_rid diff --git a/ext/node/lib.rs b/ext/node/lib.rs index b08b0493b0a147..f4a95180ce9d59 100644 --- a/ext/node/lib.rs +++ b/ext/node/lib.rs @@ -9,6 +9,7 @@ use std::path::Path; use std::path::PathBuf; use deno_core::error::AnyError; +use deno_core::error::JsStackFrame; use deno_core::op2; use deno_core::url::Url; #[allow(unused_imports)] @@ -46,37 +47,43 @@ pub trait NodePermissions { &mut self, url: &Url, api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError>; #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] #[inline(always)] fn check_read( &mut self, path: &str, + stack: Option>, ) -> Result { - self.check_read_with_api_name(path, None) + self.check_read_with_api_name(path, None, stack) } #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] fn check_read_with_api_name( &mut self, path: &str, api_name: Option<&str>, + stack: Option>, ) -> Result; #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] fn check_read_path<'a>( &mut self, path: &'a Path, + stack: Option>, ) -> Result, PermissionCheckError>; fn query_read_all(&mut self) -> bool; fn check_sys( &mut self, kind: &str, api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError>; #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] fn check_write_with_api_name( &mut self, path: &str, api_name: Option<&str>, + stack: Option>, ) -> Result; } @@ -86,8 +93,11 @@ impl NodePermissions for deno_permissions::PermissionsContainer { &mut self, url: &Url, api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError> { - deno_permissions::PermissionsContainer::check_net_url(self, url, api_name) + deno_permissions::PermissionsContainer::check_net_url( + self, url, api_name, stack, + ) } #[inline(always)] @@ -95,17 +105,21 @@ impl NodePermissions for deno_permissions::PermissionsContainer { &mut self, path: &str, api_name: Option<&str>, + stack: Option>, ) -> Result { deno_permissions::PermissionsContainer::check_read_with_api_name( - self, path, api_name, + self, path, api_name, stack, ) } fn check_read_path<'a>( &mut self, path: &'a Path, + stack: Option>, ) -> Result, PermissionCheckError> { - deno_permissions::PermissionsContainer::check_read_path(self, path, None) + deno_permissions::PermissionsContainer::check_read_path( + self, path, None, stack, + ) } fn query_read_all(&mut self) -> bool { @@ -117,9 +131,10 @@ impl NodePermissions for deno_permissions::PermissionsContainer { &mut self, path: &str, api_name: Option<&str>, + stack: Option>, ) -> Result { deno_permissions::PermissionsContainer::check_write_with_api_name( - self, path, api_name, + self, path, api_name, stack, ) } @@ -127,8 +142,11 @@ impl NodePermissions for deno_permissions::PermissionsContainer { &mut self, kind: &str, api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError> { - deno_permissions::PermissionsContainer::check_sys(self, kind, api_name) + deno_permissions::PermissionsContainer::check_sys( + self, kind, api_name, stack, + ) } } diff --git a/ext/node/ops/fs.rs b/ext/node/ops/fs.rs index 9c0e4e1ccff212..681fa9445fade6 100644 --- a/ext/node/ops/fs.rs +++ b/ext/node/ops/fs.rs @@ -1,12 +1,12 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use std::cell::RefCell; -use std::rc::Rc; - +use deno_core::error::JsStackFrame; use deno_core::op2; use deno_core::OpState; use deno_fs::FileSystemRc; use serde::Serialize; +use std::cell::RefCell; +use std::rc::Rc; use crate::NodePermissions; @@ -26,78 +26,94 @@ pub enum FsError { Fs(#[from] deno_io::fs::FsError), } -#[op2(fast)] +#[op2(reentrant)] pub fn op_node_fs_exists_sync

( state: &mut OpState, #[string] path: String, + #[stack_trace] stack: Option>, ) -> Result where P: NodePermissions + 'static, { - let path = state - .borrow_mut::

() - .check_read_with_api_name(&path, Some("node:fs.existsSync()"))?; + let path = state.borrow_mut::

().check_read_with_api_name( + &path, + Some("node:fs.existsSync()"), + stack, + )?; let fs = state.borrow::(); Ok(fs.exists_sync(&path)) } -#[op2(async)] +#[op2(async, reentrant)] pub async fn op_node_fs_exists

( state: Rc>, #[string] path: String, + #[stack_trace] stack: Option>, ) -> Result where P: NodePermissions + 'static, { let (fs, path) = { let mut state = state.borrow_mut(); - let path = state - .borrow_mut::

() - .check_read_with_api_name(&path, Some("node:fs.exists()"))?; + let path = state.borrow_mut::

().check_read_with_api_name( + &path, + Some("node:fs.exists()"), + stack, + )?; (state.borrow::().clone(), path) }; Ok(fs.exists_async(path).await?) } -#[op2(fast)] +#[op2(reentrant)] pub fn op_node_cp_sync

( state: &mut OpState, #[string] path: &str, #[string] new_path: &str, + #[stack_trace] stack: Option>, ) -> Result<(), FsError> where P: NodePermissions + 'static, { - let path = state - .borrow_mut::

() - .check_read_with_api_name(path, Some("node:fs.cpSync"))?; - let new_path = state - .borrow_mut::

() - .check_write_with_api_name(new_path, Some("node:fs.cpSync"))?; + let path = state.borrow_mut::

().check_read_with_api_name( + path, + Some("node:fs.cpSync"), + stack.clone(), + )?; + let new_path = state.borrow_mut::

().check_write_with_api_name( + new_path, + Some("node:fs.cpSync"), + stack, + )?; let fs = state.borrow::(); fs.cp_sync(&path, &new_path)?; Ok(()) } -#[op2(async)] +#[op2(async, reentrant)] pub async fn op_node_cp

( state: Rc>, #[string] path: String, #[string] new_path: String, + #[stack_trace] stack: Option>, ) -> Result<(), FsError> where P: NodePermissions + 'static, { let (fs, path, new_path) = { let mut state = state.borrow_mut(); - let path = state - .borrow_mut::

() - .check_read_with_api_name(&path, Some("node:fs.cpSync"))?; - let new_path = state - .borrow_mut::

() - .check_write_with_api_name(&new_path, Some("node:fs.cpSync"))?; + let path = state.borrow_mut::

().check_read_with_api_name( + &path, + Some("node:fs.cpSync"), + stack.clone(), + )?; + let new_path = state.borrow_mut::

().check_write_with_api_name( + &new_path, + Some("node:fs.cpSync"), + stack, + )?; (state.borrow::().clone(), path, new_path) }; @@ -117,24 +133,27 @@ pub struct StatFs { pub ffree: u64, } -#[op2] +#[op2(reentrant)] #[serde] pub fn op_node_statfs

( state: Rc>, #[string] path: String, bigint: bool, + #[stack_trace] stack: Option>, ) -> Result where P: NodePermissions + 'static, { let path = { let mut state = state.borrow_mut(); - let path = state - .borrow_mut::

() - .check_read_with_api_name(&path, Some("node:fs.statfs"))?; + let path = state.borrow_mut::

().check_read_with_api_name( + &path, + Some("node:fs.statfs"), + stack.clone(), + )?; state .borrow_mut::

() - .check_sys("statfs", "node:fs.statfs")?; + .check_sys("statfs", "node:fs.statfs", stack)?; path }; #[cfg(unix)] @@ -258,7 +277,7 @@ where } } -#[op2(fast)] +#[op2(reentrant)] pub fn op_node_lutimes_sync

( state: &mut OpState, #[string] path: &str, @@ -266,20 +285,23 @@ pub fn op_node_lutimes_sync

( #[smi] atime_nanos: u32, #[number] mtime_secs: i64, #[smi] mtime_nanos: u32, + #[stack_trace] stack: Option>, ) -> Result<(), FsError> where P: NodePermissions + 'static, { - let path = state - .borrow_mut::

() - .check_write_with_api_name(path, Some("node:fs.lutimes"))?; + let path = state.borrow_mut::

().check_write_with_api_name( + path, + Some("node:fs.lutimes"), + stack, + )?; let fs = state.borrow::(); fs.lutime_sync(&path, atime_secs, atime_nanos, mtime_secs, mtime_nanos)?; Ok(()) } -#[op2(async)] +#[op2(async, reentrant)] pub async fn op_node_lutimes

( state: Rc>, #[string] path: String, @@ -287,15 +309,18 @@ pub async fn op_node_lutimes

( #[smi] atime_nanos: u32, #[number] mtime_secs: i64, #[smi] mtime_nanos: u32, + #[stack_trace] stack: Option>, ) -> Result<(), FsError> where P: NodePermissions + 'static, { let (fs, path) = { let mut state = state.borrow_mut(); - let path = state - .borrow_mut::

() - .check_write_with_api_name(&path, Some("node:fs.lutimesSync"))?; + let path = state.borrow_mut::

().check_write_with_api_name( + &path, + Some("node:fs.lutimesSync"), + stack, + )?; (state.borrow::().clone(), path) }; @@ -305,39 +330,45 @@ where Ok(()) } -#[op2] +#[op2(reentrant)] pub fn op_node_lchown_sync

( state: &mut OpState, #[string] path: String, uid: Option, gid: Option, + #[stack_trace] stack: Option>, ) -> Result<(), FsError> where P: NodePermissions + 'static, { - let path = state - .borrow_mut::

() - .check_write_with_api_name(&path, Some("node:fs.lchownSync"))?; + let path = state.borrow_mut::

().check_write_with_api_name( + &path, + Some("node:fs.lchownSync"), + stack, + )?; let fs = state.borrow::(); fs.lchown_sync(&path, uid, gid)?; Ok(()) } -#[op2(async)] +#[op2(async, reentrant)] pub async fn op_node_lchown

( state: Rc>, #[string] path: String, uid: Option, gid: Option, + #[stack_trace] stack: Option>, ) -> Result<(), FsError> where P: NodePermissions + 'static, { let (fs, path) = { let mut state = state.borrow_mut(); - let path = state - .borrow_mut::

() - .check_write_with_api_name(&path, Some("node:fs.lchown"))?; + let path = state.borrow_mut::

().check_write_with_api_name( + &path, + Some("node:fs.lchown"), + stack, + )?; (state.borrow::().clone(), path) }; fs.lchown_async(path, uid, gid).await?; diff --git a/ext/node/ops/http.rs b/ext/node/ops/http.rs index 69571078fe26e1..eaf1575f798959 100644 --- a/ext/node/ops/http.rs +++ b/ext/node/ops/http.rs @@ -8,6 +8,7 @@ use std::task::Context; use std::task::Poll; use bytes::Bytes; +use deno_core::error::JsStackFrame; use deno_core::futures::stream::Peekable; use deno_core::futures::Future; use deno_core::futures::FutureExt; @@ -49,7 +50,7 @@ use std::cmp::min; use tokio::io::AsyncReadExt; use tokio::io::AsyncWriteExt; -#[op2] +#[op2(reentrant)] #[serde] pub fn op_node_http_request

( state: &mut OpState, @@ -58,6 +59,7 @@ pub fn op_node_http_request

( #[serde] headers: Vec<(ByteString, ByteString)>, #[smi] client_rid: Option, #[smi] body: Option, + #[stack_trace] stack: Option>, ) -> Result where P: crate::NodePermissions + 'static, @@ -78,7 +80,7 @@ where { let permissions = state.borrow_mut::

(); - permissions.check_net_url(&url, "ClientRequest")?; + permissions.check_net_url(&url, "ClientRequest", stack)?; } let mut header_map = HeaderMap::new(); diff --git a/ext/node/ops/os/mod.rs b/ext/node/ops/os/mod.rs index d291277ad4d896..dfb72c67c82dad 100644 --- a/ext/node/ops/os/mod.rs +++ b/ext/node/ops/os/mod.rs @@ -1,10 +1,10 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use std::mem::MaybeUninit; - use crate::NodePermissions; +use deno_core::error::JsStackFrame; use deno_core::op2; use deno_core::OpState; +use std::mem::MaybeUninit; mod cpus; pub mod priority; @@ -21,34 +21,36 @@ pub enum OsError { FailedToGetUserInfo(#[source] std::io::Error), } -#[op2(fast)] +#[op2(reentrant)] pub fn op_node_os_get_priority

( state: &mut OpState, pid: u32, + #[stack_trace] stack: Option>, ) -> Result where P: NodePermissions + 'static, { { let permissions = state.borrow_mut::

(); - permissions.check_sys("getPriority", "node:os.getPriority()")?; + permissions.check_sys("getPriority", "node:os.getPriority()", stack)?; } priority::get_priority(pid).map_err(OsError::Priority) } -#[op2(fast)] +#[op2(reentrant)] pub fn op_node_os_set_priority

( state: &mut OpState, pid: u32, priority: i32, + #[stack_trace] stack: Option>, ) -> Result<(), OsError> where P: NodePermissions + 'static, { { let permissions = state.borrow_mut::

(); - permissions.check_sys("setPriority", "node:os.setPriority()")?; + permissions.check_sys("setPriority", "node:os.setPriority()", stack)?; } priority::set_priority(pid, priority).map_err(OsError::Priority) @@ -193,11 +195,12 @@ fn get_user_info(_uid: u32) -> Result { }) } -#[op2] +#[op2(reentrant)] #[serde] pub fn op_node_os_user_info

( state: &mut OpState, #[smi] uid: u32, + #[stack_trace] stack: Option>, ) -> Result where P: NodePermissions + 'static, @@ -205,23 +208,24 @@ where { let permissions = state.borrow_mut::

(); permissions - .check_sys("userInfo", "node:os.userInfo()") + .check_sys("userInfo", "node:os.userInfo()", stack) .map_err(OsError::Permission)?; } get_user_info(uid) } -#[op2(fast)] +#[op2(reentrant)] pub fn op_geteuid

( state: &mut OpState, + #[stack_trace] stack: Option>, ) -> Result where P: NodePermissions + 'static, { { let permissions = state.borrow_mut::

(); - permissions.check_sys("uid", "node:os.geteuid()")?; + permissions.check_sys("uid", "node:os.geteuid()", stack)?; } #[cfg(windows)] @@ -233,16 +237,17 @@ where Ok(euid) } -#[op2(fast)] +#[op2(reentrant)] pub fn op_getegid

( state: &mut OpState, + #[stack_trace] stack: Option>, ) -> Result where P: NodePermissions + 'static, { { let permissions = state.borrow_mut::

(); - permissions.check_sys("getegid", "node:os.getegid()")?; + permissions.check_sys("getegid", "node:os.getegid()", stack)?; } #[cfg(windows)] @@ -254,31 +259,35 @@ where Ok(egid) } -#[op2] +#[op2(reentrant)] #[serde] -pub fn op_cpus

(state: &mut OpState) -> Result, OsError> +pub fn op_cpus

( + state: &mut OpState, + #[stack_trace] stack: Option>, +) -> Result, OsError> where P: NodePermissions + 'static, { { let permissions = state.borrow_mut::

(); - permissions.check_sys("cpus", "node:os.cpus()")?; + permissions.check_sys("cpus", "node:os.cpus()", stack)?; } cpus::cpu_info().ok_or(OsError::FailedToGetCpuInfo) } -#[op2] +#[op2(reentrant)] #[string] pub fn op_homedir

( state: &mut OpState, + #[stack_trace] stack: Option>, ) -> Result, deno_core::error::AnyError> where P: NodePermissions + 'static, { { let permissions = state.borrow_mut::

(); - permissions.check_sys("homedir", "node:os.homedir()")?; + permissions.check_sys("homedir", "node:os.homedir()", stack)?; } Ok(home::home_dir().map(|path| path.to_string_lossy().to_string())) diff --git a/ext/node/ops/process.rs b/ext/node/ops/process.rs index 282567226ea6cc..c16913ba2c2c73 100644 --- a/ext/node/ops/process.rs +++ b/ext/node/ops/process.rs @@ -45,15 +45,16 @@ fn kill(pid: i32, _sig: i32) -> i32 { } } -#[op2(fast)] +#[op2(reentrant)] pub fn op_node_process_kill( state: &mut OpState, #[smi] pid: i32, #[smi] sig: i32, + #[stack_trace] stack: Option>, ) -> Result { state .borrow_mut::() - .check_run_all("process.kill")?; + .check_run_all("process.kill", stack)?; Ok(kill(pid, sig)) } diff --git a/ext/websocket/lib.rs b/ext/websocket/lib.rs index e466ef19ac68f6..ad3050c489870b 100644 --- a/ext/websocket/lib.rs +++ b/ext/websocket/lib.rs @@ -114,6 +114,7 @@ pub trait WebSocketPermissions { &mut self, _url: &url::Url, _api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError>; } @@ -123,8 +124,11 @@ impl WebSocketPermissions for deno_permissions::PermissionsContainer { &mut self, url: &url::Url, api_name: &str, + stack: Option>, ) -> Result<(), PermissionCheckError> { - deno_permissions::PermissionsContainer::check_net_url(self, url, api_name, todo!()) + deno_permissions::PermissionsContainer::check_net_url( + self, url, api_name, stack, + ) } } @@ -149,13 +153,14 @@ impl Resource for WsCancelResource { // This op is needed because creating a WS instance in JavaScript is a sync // operation and should throw error when permissions are not fulfilled, // but actual op that connects WS is async. -#[op2] +#[op2(reentrant)] #[smi] pub fn op_ws_check_permission_and_cancel_handle( state: &mut OpState, #[string] api_name: String, #[string] url: String, cancel_handle: bool, + #[stack_trace] stack: Option>, ) -> Result, WebsocketError> where WP: WebSocketPermissions + 'static, @@ -163,6 +168,7 @@ where state.borrow_mut::().check_net_url( &url::Url::parse(&url).map_err(WebsocketError::Url)?, &api_name, + stack, )?; if cancel_handle { @@ -444,7 +450,7 @@ fn populate_common_request_headers( Ok(request) } -#[op2(async)] +#[op2(async, reentrant)] #[serde] pub async fn op_ws_create( state: Rc>, @@ -453,6 +459,7 @@ pub async fn op_ws_create( #[string] protocols: String, #[smi] cancel_handle: Option, #[serde] headers: Option>, + #[stack_trace] stack: Option>, ) -> Result where WP: WebSocketPermissions + 'static, @@ -463,6 +470,7 @@ where .check_net_url( &url::Url::parse(&url).map_err(WebsocketError::Url)?, &api_name, + stack, ) .expect( "Permission check should have been done in op_ws_check_permission", From 659d5333336f0c7966f7f281779e5d8d76ca1ba0 Mon Sep 17 00:00:00 2001 From: crowlkats Date: Thu, 7 Nov 2024 16:59:38 +0100 Subject: [PATCH 3/4] update deno_core --- Cargo.lock | 53 +++++++---------------------- Cargo.toml | 2 +- cli/file_fetcher.rs | 2 ++ cli/module_loader.rs | 5 ++- cli/npm/byonm.rs | 3 +- cli/npm/managed/mod.rs | 5 ++- cli/npm/managed/resolvers/common.rs | 4 ++- cli/npm/managed/resolvers/global.rs | 3 +- cli/npm/managed/resolvers/local.rs | 3 +- cli/npm/mod.rs | 1 + cli/ops/bench.rs | 7 ++-- cli/ops/testing.rs | 6 ++-- cli/standalone/mod.rs | 3 +- ext/ffi/repr.rs | 34 +++++++++--------- ext/fs/ops.rs | 20 +++++------ ext/node/lib.rs | 1 + ext/node/ops/fs.rs | 6 ++-- ext/node/ops/os/mod.rs | 8 ++--- ext/node/ops/process.rs | 2 +- ext/node/ops/require.rs | 28 +++++++++------ ext/node/ops/worker_threads.rs | 8 +++-- runtime/ops/os/mod.rs | 4 +-- runtime/ops/process.rs | 2 +- runtime/snapshot.rs | 37 ++++++++++++++++++-- 24 files changed, 140 insertions(+), 107 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 29fe91641d57df..3326fce6e591e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -435,29 +435,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bindgen" -version = "0.69.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" -dependencies = [ - "bitflags 2.6.0", - "cexpr", - "clang-sys", - "itertools 0.10.5", - "lazy_static", - "lazycell", - "log", - "prettyplease 0.2.17", - "proc-macro2", - "quote", - "regex", - "rustc-hash 1.1.0", - "shlex", - "syn 2.0.72", - "which 4.4.2", -] - [[package]] name = "bindgen" version = "0.70.1" @@ -1418,9 +1395,9 @@ dependencies = [ [[package]] name = "deno_core" -version = "0.318.0" +version = "0.319.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10cae2393219ff9278123f7b24799cdfab37c7d6561b69ca06ced115cac92111" +checksum = "e9dbb841f9850534320d8927dce53ca8d64bafbab5576c2a98f03f9e08534215" dependencies = [ "anyhow", "bincode", @@ -1450,9 +1427,9 @@ dependencies = [ [[package]] name = "deno_core_icudata" -version = "0.0.73" +version = "0.74.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a13951ea98c0a4c372f162d669193b4c9d991512de9f2381dd161027f34b26b1" +checksum = "fe4dccb6147bb3f3ba0c7a48e993bfeb999d2c2e47a81badee80e2b370c8d695" [[package]] name = "deno_cron" @@ -1921,9 +1898,9 @@ dependencies = [ [[package]] name = "deno_ops" -version = "0.194.0" +version = "0.195.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f760b492bd638c1dc3e992d11672c259fbe9a233162099a8347591c9e22d0391" +checksum = "797f348c38c07a5398bf790b280077c698e13fb49252f61ca6f6c5c616060292" dependencies = [ "proc-macro-rules", "proc-macro2", @@ -4115,12 +4092,6 @@ dependencies = [ "spin", ] -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "libc" version = "0.2.153" @@ -4212,7 +4183,7 @@ version = "1.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca8dfd1a173826d193e3b955e07c22765829890f62c677a59c4a410cb4f47c01" dependencies = [ - "bindgen 0.70.1", + "bindgen", "libloading 0.8.5", ] @@ -6170,9 +6141,9 @@ dependencies = [ [[package]] name = "serde_v8" -version = "0.227.0" +version = "0.228.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a8294c2223c53bed343be8b80564ece4dc0d03b643b06fa86c4ccc0e064eda0" +checksum = "bfe23e75c9a167f4e9d67a90d9fcaa622d1eec9aecad526c270e99a92f6915ff" dependencies = [ "num-bigint", "serde", @@ -7794,11 +7765,11 @@ dependencies = [ [[package]] name = "v8" -version = "0.106.0" +version = "130.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a381badc47c6f15acb5fe0b5b40234162349ed9d4e4fd7c83a7f5547c0fc69c5" +checksum = "c23b5c2caff00209b03a716609b275acae94b02dd3b63c4648e7232a84a8402f" dependencies = [ - "bindgen 0.69.4", + "bindgen", "bitflags 2.6.0", "fslock", "gzip-header", diff --git a/Cargo.toml b/Cargo.toml index 28ef2829e0f55f..209e8baf27316e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,7 +46,7 @@ repository = "https://github.com/denoland/deno" [workspace.dependencies] deno_ast = { version = "=0.43.3", features = ["transpiling"] } -deno_core = { version = "0.318.0" } +deno_core = { version = "0.319.0" } deno_bench_util = { version = "0.169.0", path = "./bench_util" } deno_lockfile = "=0.23.1" diff --git a/cli/file_fetcher.rs b/cli/file_fetcher.rs index 95d778f0bbc49f..4457048a49bfbf 100644 --- a/cli/file_fetcher.rs +++ b/cli/file_fetcher.rs @@ -656,12 +656,14 @@ impl FileFetcher { permissions.check_specifier( specifier, deno_runtime::deno_permissions::CheckSpecifierKind::Static, + None, )?; } FetchPermissionsOptionRef::DynamicContainer(permissions) => { permissions.check_specifier( specifier, deno_runtime::deno_permissions::CheckSpecifierKind::Dynamic, + None, )?; } } diff --git a/cli/module_loader.rs b/cli/module_loader.rs index 43c9e1aa0750e0..dc725141c91178 100644 --- a/cli/module_loader.rs +++ b/cli/module_loader.rs @@ -1065,6 +1065,7 @@ impl NodeRequireLoader &self, permissions: &mut dyn deno_runtime::deno_node::NodePermissions, path: &'a Path, + stack: Option>, ) -> Result, AnyError> { if let Ok(url) = deno_path_util::url_from_file_path(path) { // allow reading if it's in the module graph @@ -1072,7 +1073,9 @@ impl NodeRequireLoader return Ok(std::borrow::Cow::Borrowed(path)); } } - self.npm_resolver.ensure_read_permission(permissions, path) + self + .npm_resolver + .ensure_read_permission(permissions, path, stack) } fn load_text_file_lossy(&self, path: &Path) -> Result { diff --git a/cli/npm/byonm.rs b/cli/npm/byonm.rs index 45fa4cfd1f528c..ae2dbdfe73cf07 100644 --- a/cli/npm/byonm.rs +++ b/cli/npm/byonm.rs @@ -84,12 +84,13 @@ impl CliNpmResolver for CliByonmNpmResolver { &self, permissions: &mut dyn NodePermissions, path: &'a Path, + stack: Option>, ) -> Result, AnyError> { if !path .components() .any(|c| c.as_os_str().to_ascii_lowercase() == "node_modules") { - permissions.check_read_path(path).map_err(Into::into) + permissions.check_read_path(path, stack).map_err(Into::into) } else { Ok(Cow::Borrowed(path)) } diff --git a/cli/npm/managed/mod.rs b/cli/npm/managed/mod.rs index 4a91bc34746ee5..d93ade606a20a7 100644 --- a/cli/npm/managed/mod.rs +++ b/cli/npm/managed/mod.rs @@ -704,8 +704,11 @@ impl CliNpmResolver for ManagedCliNpmResolver { &self, permissions: &mut dyn NodePermissions, path: &'a Path, + stack: Option>, ) -> Result, AnyError> { - self.fs_resolver.ensure_read_permission(permissions, path) + self + .fs_resolver + .ensure_read_permission(permissions, path, stack) } fn check_state_hash(&self) -> Option { diff --git a/cli/npm/managed/resolvers/common.rs b/cli/npm/managed/resolvers/common.rs index eee11c7604952f..677b1e7a26b30f 100644 --- a/cli/npm/managed/resolvers/common.rs +++ b/cli/npm/managed/resolvers/common.rs @@ -64,6 +64,7 @@ pub trait NpmPackageFsResolver: Send + Sync { &self, permissions: &mut dyn NodePermissions, path: &'a Path, + stack: Option>, ) -> Result, AnyError>; } @@ -87,6 +88,7 @@ impl RegistryReadPermissionChecker { &self, permissions: &mut dyn NodePermissions, path: &'a Path, + stack: Option>, ) -> Result, AnyError> { if permissions.query_read_all() { return Ok(Cow::Borrowed(path)); // skip permissions checks below @@ -133,7 +135,7 @@ impl RegistryReadPermissionChecker { } } - permissions.check_read_path(path).map_err(Into::into) + permissions.check_read_path(path, stack).map_err(Into::into) } } diff --git a/cli/npm/managed/resolvers/global.rs b/cli/npm/managed/resolvers/global.rs index f0193e78e95cf2..50f9a08c8f5683 100644 --- a/cli/npm/managed/resolvers/global.rs +++ b/cli/npm/managed/resolvers/global.rs @@ -182,10 +182,11 @@ impl NpmPackageFsResolver for GlobalNpmPackageResolver { &self, permissions: &mut dyn NodePermissions, path: &'a Path, + stack: Option>, ) -> Result, AnyError> { self .registry_read_permission_checker - .ensure_registry_read_permission(permissions, path) + .ensure_registry_read_permission(permissions, path, stack) } } diff --git a/cli/npm/managed/resolvers/local.rs b/cli/npm/managed/resolvers/local.rs index eddb0dc9b65628..fe9e68d7756d14 100644 --- a/cli/npm/managed/resolvers/local.rs +++ b/cli/npm/managed/resolvers/local.rs @@ -257,10 +257,11 @@ impl NpmPackageFsResolver for LocalNpmPackageResolver { &self, permissions: &mut dyn NodePermissions, path: &'a Path, + stack: Option>, ) -> Result, AnyError> { self .registry_read_permission_checker - .ensure_registry_read_permission(permissions, path) + .ensure_registry_read_permission(permissions, path, stack) } } diff --git a/cli/npm/mod.rs b/cli/npm/mod.rs index 0d434ca27fb540..92d5b247cd291a 100644 --- a/cli/npm/mod.rs +++ b/cli/npm/mod.rs @@ -131,6 +131,7 @@ pub trait CliNpmResolver: NpmResolver { &self, permissions: &mut dyn NodePermissions, path: &'a Path, + stack: Option>, ) -> Result, AnyError>; /// Returns a hash returning the state of the npm resolver diff --git a/cli/ops/bench.rs b/cli/ops/bench.rs index 5d1e6e746d8edf..31fc4025599dfc 100644 --- a/cli/ops/bench.rs +++ b/cli/ops/bench.rs @@ -7,6 +7,7 @@ use std::time; use deno_core::error::generic_error; use deno_core::error::type_error; use deno_core::error::AnyError; +use deno_core::error::JsStackFrame; use deno_core::op2; use deno_core::v8; use deno_core::ModuleSpecifier; @@ -51,15 +52,17 @@ fn op_bench_get_origin(state: &mut OpState) -> String { #[derive(Clone)] struct PermissionsHolder(Uuid, PermissionsContainer); -#[op2] +#[op2(reentrant)] #[serde] pub fn op_pledge_test_permissions( state: &mut OpState, #[serde] args: ChildPermissionsArg, + #[stack_trace] stack: Option>, ) -> Result { let token = Uuid::new_v4(); let parent_permissions = state.borrow_mut::(); - let worker_permissions = parent_permissions.create_child_permissions(args)?; + let worker_permissions = + parent_permissions.create_child_permissions(args, stack)?; let parent_permissions = parent_permissions.clone(); if state.try_take::().is_some() { diff --git a/cli/ops/testing.rs b/cli/ops/testing.rs index c3f469656c4b72..ec4dec6e81e06b 100644 --- a/cli/ops/testing.rs +++ b/cli/ops/testing.rs @@ -46,15 +46,17 @@ deno_core::extension!(deno_test, #[derive(Clone)] struct PermissionsHolder(Uuid, PermissionsContainer); -#[op2] +#[op2(reentrant)] #[serde] pub fn op_pledge_test_permissions( state: &mut OpState, #[serde] args: ChildPermissionsArg, + #[stack_trace] stack: Option>, ) -> Result { let token = Uuid::new_v4(); let parent_permissions = state.borrow_mut::(); - let worker_permissions = parent_permissions.create_child_permissions(args)?; + let worker_permissions = + parent_permissions.create_child_permissions(args, stack)?; let parent_permissions = parent_permissions.clone(); if state.try_take::().is_some() { diff --git a/cli/standalone/mod.rs b/cli/standalone/mod.rs index 85610f4c20f1f7..2b7b1e6e9295c1 100644 --- a/cli/standalone/mod.rs +++ b/cli/standalone/mod.rs @@ -411,6 +411,7 @@ impl NodeRequireLoader for EmbeddedModuleLoader { &self, permissions: &mut dyn deno_runtime::deno_node::NodePermissions, path: &'a std::path::Path, + stack: Option>, ) -> Result, AnyError> { if self.shared.modules.has_file(path) { // allow reading if the file is in the snapshot @@ -420,7 +421,7 @@ impl NodeRequireLoader for EmbeddedModuleLoader { self .shared .npm_resolver - .ensure_read_permission(permissions, path) + .ensure_read_permission(permissions, path, stack) } fn load_text_file_lossy( diff --git a/ext/ffi/repr.rs b/ext/ffi/repr.rs index 3f9b2b8abe7948..79fb64a4209f6e 100644 --- a/ext/ffi/repr.rs +++ b/ext/ffi/repr.rs @@ -50,7 +50,7 @@ pub enum ReprError { Permission(#[from] deno_permissions::PermissionCheckError), } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_ffi_ptr_create( state: &mut OpState, #[bigint] ptr_number: usize, @@ -65,7 +65,7 @@ where Ok(ptr_number as *mut c_void) } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_ffi_ptr_equals( state: &mut OpState, a: *const c_void, @@ -96,7 +96,7 @@ where Ok(buf as *mut c_void) } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_ffi_ptr_of_exact( state: &mut OpState, buf: v8::Local, @@ -117,7 +117,7 @@ where Ok(buf.as_ptr() as _) } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_ffi_ptr_offset( state: &mut OpState, ptr: *mut c_void, @@ -148,7 +148,7 @@ unsafe extern "C" fn noop_deleter_callback( ) { } -#[op2(reentrant)] +#[op2(fast, reentrant)] #[bigint] pub fn op_ffi_ptr_value( state: &mut OpState, @@ -254,7 +254,7 @@ where Ok(value) } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_ffi_read_bool( state: &mut OpState, ptr: *mut c_void, @@ -275,7 +275,7 @@ where Ok(unsafe { ptr::read_unaligned::(ptr.offset(offset) as *const bool) }) } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_ffi_read_u8( state: &mut OpState, ptr: *mut c_void, @@ -298,7 +298,7 @@ where }) } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_ffi_read_i8( state: &mut OpState, ptr: *mut c_void, @@ -321,7 +321,7 @@ where }) } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_ffi_read_u16( state: &mut OpState, ptr: *mut c_void, @@ -344,7 +344,7 @@ where }) } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_ffi_read_i16( state: &mut OpState, ptr: *mut c_void, @@ -367,7 +367,7 @@ where }) } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_ffi_read_u32( state: &mut OpState, ptr: *mut c_void, @@ -388,7 +388,7 @@ where Ok(unsafe { ptr::read_unaligned::(ptr.offset(offset) as *const u32) }) } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_ffi_read_i32( state: &mut OpState, ptr: *mut c_void, @@ -409,7 +409,7 @@ where Ok(unsafe { ptr::read_unaligned::(ptr.offset(offset) as *const i32) }) } -#[op2(reentrant)] +#[op2(fast, reentrant)] #[bigint] pub fn op_ffi_read_u64( state: &mut OpState, @@ -436,7 +436,7 @@ where Ok(value) } -#[op2(reentrant)] +#[op2(fast, reentrant)] #[bigint] pub fn op_ffi_read_i64( state: &mut OpState, @@ -463,7 +463,7 @@ where Ok(value) } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_ffi_read_f32( state: &mut OpState, ptr: *mut c_void, @@ -484,7 +484,7 @@ where Ok(unsafe { ptr::read_unaligned::(ptr.offset(offset) as *const f32) }) } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_ffi_read_f64( state: &mut OpState, ptr: *mut c_void, @@ -505,7 +505,7 @@ where Ok(unsafe { ptr::read_unaligned::(ptr.offset(offset) as *const f64) }) } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_ffi_read_ptr( state: &mut OpState, ptr: *mut c_void, diff --git a/ext/fs/ops.rs b/ext/fs/ops.rs index 017deb268173d6..0287c10a32c33b 100644 --- a/ext/fs/ops.rs +++ b/ext/fs/ops.rs @@ -164,7 +164,7 @@ where Ok(path_str) } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_fs_chdir

( state: &mut OpState, #[string] directory: &str, @@ -304,7 +304,7 @@ where Ok(()) } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_fs_chmod_sync

( state: &mut OpState, #[string] path: String, @@ -393,7 +393,7 @@ where Ok(()) } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_fs_remove_sync

( state: &mut OpState, #[string] path: &str, @@ -449,7 +449,7 @@ where Ok(()) } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_fs_copy_file_sync

( state: &mut OpState, #[string] from: &str, @@ -497,7 +497,7 @@ where Ok(()) } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_fs_stat_sync

( state: &mut OpState, #[string] path: String, @@ -541,7 +541,7 @@ where Ok(SerializableStat::from(stat)) } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_fs_lstat_sync

( state: &mut OpState, #[string] path: String, @@ -698,7 +698,7 @@ where Ok(entries) } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_fs_rename_sync

( state: &mut OpState, #[string] oldpath: String, @@ -750,7 +750,7 @@ where Ok(()) } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_fs_link_sync

( state: &mut OpState, #[string] oldpath: &str, @@ -905,7 +905,7 @@ where Ok(target_string) } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_fs_truncate_sync

( state: &mut OpState, #[string] path: &str, @@ -953,7 +953,7 @@ where Ok(()) } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_fs_utime_sync

( state: &mut OpState, #[string] path: &str, diff --git a/ext/node/lib.rs b/ext/node/lib.rs index f4a95180ce9d59..8922a4ae572d8b 100644 --- a/ext/node/lib.rs +++ b/ext/node/lib.rs @@ -159,6 +159,7 @@ pub trait NodeRequireLoader { &self, permissions: &mut dyn NodePermissions, path: &'a Path, + stack: Option>, ) -> Result, AnyError>; fn load_text_file_lossy(&self, path: &Path) -> Result; diff --git a/ext/node/ops/fs.rs b/ext/node/ops/fs.rs index 681fa9445fade6..239c4254748216 100644 --- a/ext/node/ops/fs.rs +++ b/ext/node/ops/fs.rs @@ -26,7 +26,7 @@ pub enum FsError { Fs(#[from] deno_io::fs::FsError), } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_node_fs_exists_sync

( state: &mut OpState, #[string] path: String, @@ -66,7 +66,7 @@ where Ok(fs.exists_async(path).await?) } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_node_cp_sync

( state: &mut OpState, #[string] path: &str, @@ -277,7 +277,7 @@ where } } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_node_lutimes_sync

( state: &mut OpState, #[string] path: &str, diff --git a/ext/node/ops/os/mod.rs b/ext/node/ops/os/mod.rs index dfb72c67c82dad..e471ed283b26da 100644 --- a/ext/node/ops/os/mod.rs +++ b/ext/node/ops/os/mod.rs @@ -21,7 +21,7 @@ pub enum OsError { FailedToGetUserInfo(#[source] std::io::Error), } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_node_os_get_priority

( state: &mut OpState, pid: u32, @@ -38,7 +38,7 @@ where priority::get_priority(pid).map_err(OsError::Priority) } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_node_os_set_priority

( state: &mut OpState, pid: u32, @@ -215,7 +215,7 @@ where get_user_info(uid) } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_geteuid

( state: &mut OpState, #[stack_trace] stack: Option>, @@ -237,7 +237,7 @@ where Ok(euid) } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_getegid

( state: &mut OpState, #[stack_trace] stack: Option>, diff --git a/ext/node/ops/process.rs b/ext/node/ops/process.rs index c16913ba2c2c73..3f1e68c3cc5db8 100644 --- a/ext/node/ops/process.rs +++ b/ext/node/ops/process.rs @@ -45,7 +45,7 @@ fn kill(pid: i32, _sig: i32) -> i32 { } } -#[op2(reentrant)] +#[op2(fast, reentrant)] pub fn op_node_process_kill( state: &mut OpState, #[smi] pid: i32, diff --git a/ext/node/ops/require.rs b/ext/node/ops/require.rs index 30db8b629325d8..e94d22761181f8 100644 --- a/ext/node/ops/require.rs +++ b/ext/node/ops/require.rs @@ -29,13 +29,14 @@ use crate::PackageJsonResolverRc; fn ensure_read_permission<'a, P>( state: &mut OpState, file_path: &'a Path, + stack: Option>, ) -> Result, deno_core::error::AnyError> where P: NodePermissions + 'static, { let loader = state.borrow::().clone(); let permissions = state.borrow_mut::

(); - loader.ensure_read_permission(permissions, file_path) + loader.ensure_read_permission(permissions, file_path, stack) } #[derive(Debug, thiserror::Error)] @@ -289,16 +290,17 @@ pub fn op_require_path_is_absolute(#[string] p: String) -> bool { PathBuf::from(p).is_absolute() } -#[op2(fast)] +#[op2(fast, reentrant)] pub fn op_require_stat

( state: &mut OpState, #[string] path: String, + #[stack_trace] stack: Option>, ) -> Result where P: NodePermissions + 'static, { let path = PathBuf::from(path); - let path = ensure_read_permission::

(state, &path)?; + let path = ensure_read_permission::

(state, &path, stack)?; let fs = state.borrow::(); if let Ok(metadata) = fs.stat_sync(&path) { if metadata.is_file { @@ -311,17 +313,18 @@ where Ok(-1) } -#[op2] +#[op2(reentrant)] #[string] pub fn op_require_real_path

( state: &mut OpState, #[string] request: String, + #[stack_trace] stack: Option>, ) -> Result where P: NodePermissions + 'static, { let path = PathBuf::from(request); - let path = ensure_read_permission::

(state, &path) + let path = ensure_read_permission::

(state, &path, stack) .map_err(RequireError::Permission)?; let fs = state.borrow::(); let canonicalized_path = @@ -375,13 +378,14 @@ pub fn op_require_path_basename( } } -#[op2] +#[op2(reentrant)] #[string] pub fn op_require_try_self_parent_path

( state: &mut OpState, has_parent: bool, #[string] maybe_parent_filename: Option, #[string] maybe_parent_id: Option, + #[stack_trace] stack: Option>, ) -> Result, deno_core::error::AnyError> where P: NodePermissions + 'static, @@ -398,7 +402,7 @@ where if parent_id == "" || parent_id == "internal/preload" { let fs = state.borrow::(); if let Ok(cwd) = fs.cwd() { - let cwd = ensure_read_permission::

(state, &cwd)?; + let cwd = ensure_read_permission::

(state, &cwd, stack)?; return Ok(Some(cwd.to_string_lossy().into_owned())); } } @@ -470,18 +474,19 @@ where } } -#[op2] +#[op2(reentrant)] #[string] pub fn op_require_read_file

( state: &mut OpState, #[string] file_path: String, + #[stack_trace] stack: Option>, ) -> Result where P: NodePermissions + 'static, { let file_path = PathBuf::from(file_path); // todo(dsherret): there's multiple borrows to NodeRequireLoaderRc here - let file_path = ensure_read_permission::

(state, &file_path) + let file_path = ensure_read_permission::

(state, &file_path, stack) .map_err(RequireError::Permission)?; let loader = state.borrow::(); loader @@ -600,18 +605,19 @@ where .flatten() } -#[op2] +#[op2(reentrant)] #[string] pub fn op_require_package_imports_resolve

( state: &mut OpState, #[string] referrer_filename: String, #[string] request: String, + #[stack_trace] stack: Option>, ) -> Result, RequireError> where P: NodePermissions + 'static, { let referrer_path = PathBuf::from(&referrer_filename); - let referrer_path = ensure_read_permission::

(state, &referrer_path) + let referrer_path = ensure_read_permission::

(state, &referrer_path, stack) .map_err(RequireError::Permission)?; let pkg_json_resolver = state.borrow::(); let Some(pkg) = diff --git a/ext/node/ops/worker_threads.rs b/ext/node/ops/worker_threads.rs index d2e57588265360..bcee62e80c0852 100644 --- a/ext/node/ops/worker_threads.rs +++ b/ext/node/ops/worker_threads.rs @@ -15,13 +15,14 @@ use crate::NodeRequireLoaderRc; fn ensure_read_permission<'a, P>( state: &mut OpState, file_path: &'a Path, + stack: Option>, ) -> Result, deno_core::error::AnyError> where P: NodePermissions + 'static, { let loader = state.borrow::().clone(); let permissions = state.borrow_mut::

(); - loader.ensure_read_permission(permissions, file_path) + loader.ensure_read_permission(permissions, file_path, stack) } #[derive(Debug, thiserror::Error)] @@ -50,6 +51,7 @@ pub enum WorkerThreadsFilenameError { pub fn op_worker_threads_filename

( state: &mut OpState, #[string] specifier: String, + #[stack_trace] stack: Option>, ) -> Result where P: NodePermissions + 'static, @@ -64,7 +66,7 @@ where if path.is_relative() && !specifier.starts_with('.') { return Err(WorkerThreadsFilenameError::InvalidRelativeUrl); } - let path = ensure_read_permission::

(state, &path) + let path = ensure_read_permission::

(state, &path, stack.clone()) .map_err(WorkerThreadsFilenameError::Permission)?; let fs = state.borrow::(); let canonicalized_path = @@ -75,7 +77,7 @@ where let url_path = url .to_file_path() .map_err(|_| WorkerThreadsFilenameError::UrlToPathString)?; - let url_path = ensure_read_permission::

(state, &url_path) + let url_path = ensure_read_permission::

(state, &url_path, stack) .map_err(WorkerThreadsFilenameError::Permission)?; let fs = state.borrow::(); if !fs.exists_sync(&url_path) { diff --git a/runtime/ops/os/mod.rs b/runtime/ops/os/mod.rs index ba456673627323..23ff8341410816 100644 --- a/runtime/ops/os/mod.rs +++ b/runtime/ops/os/mod.rs @@ -108,7 +108,7 @@ fn op_exec_path( .map_err(OsError::InvalidUtf8) } -#[op2(reentrant)] +#[op2(fast, reentrant)] fn op_set_env( state: &mut OpState, #[string] key: &str, @@ -568,7 +568,7 @@ fn os_uptime( Ok(sys_info::os_uptime()) } -#[op2(reentrant)] +#[op2(fast, reentrant)] #[number] fn op_os_uptime( state: &mut OpState, diff --git a/runtime/ops/process.rs b/runtime/ops/process.rs index 87a65d937d713b..2f8fb9ec60a97d 100644 --- a/runtime/ops/process.rs +++ b/runtime/ops/process.rs @@ -1136,7 +1136,7 @@ mod deprecated { } } - #[op2(reentrant)] + #[op2(fast, reentrant)] pub fn op_kill( state: &mut OpState, #[smi] pid: i32, diff --git a/runtime/snapshot.rs b/runtime/snapshot.rs index 0d81af6e74c66b..c55077fef4d7b5 100644 --- a/runtime/snapshot.rs +++ b/runtime/snapshot.rs @@ -5,6 +5,7 @@ use crate::ops::bootstrap::SnapshotOptions; use crate::shared::maybe_transpile_source; use crate::shared::runtime; use deno_cache::SqliteBackedCache; +use deno_core::error::JsStackFrame; use deno_core::snapshot::*; use deno_core::v8; use deno_core::Extension; @@ -26,6 +27,7 @@ impl deno_websocket::WebSocketPermissions for Permissions { &mut self, _url: &deno_core::url::Url, _api_name: &str, + _stack: Option>, ) -> Result<(), PermissionCheckError> { unreachable!("snapshotting!") } @@ -42,6 +44,7 @@ impl deno_fetch::FetchPermissions for Permissions { &mut self, _url: &deno_core::url::Url, _api_name: &str, + _stack: Option>, ) -> Result<(), PermissionCheckError> { unreachable!("snapshotting!") } @@ -50,26 +53,35 @@ impl deno_fetch::FetchPermissions for Permissions { &mut self, _p: &'a Path, _api_name: &str, + _stack: Option>, ) -> Result, PermissionCheckError> { unreachable!("snapshotting!") } } impl deno_ffi::FfiPermissions for Permissions { - fn check_partial_no_path(&mut self) -> Result<(), PermissionCheckError> { + fn check_partial_no_path( + &mut self, + _stack: Option>, + ) -> Result<(), PermissionCheckError> { unreachable!("snapshotting!") } fn check_partial_with_path( &mut self, _path: &str, + _stack: Option>, ) -> Result { unreachable!("snapshotting!") } } impl deno_napi::NapiPermissions for Permissions { - fn check(&mut self, _path: &str) -> Result { + fn check( + &mut self, + _path: &str, + _stack: Option>, + ) -> Result { unreachable!("snapshotting!") } } @@ -79,12 +91,14 @@ impl deno_node::NodePermissions for Permissions { &mut self, _url: &deno_core::url::Url, _api_name: &str, + _stack: Option>, ) -> Result<(), PermissionCheckError> { unreachable!("snapshotting!") } fn check_read_path<'a>( &mut self, _path: &'a Path, + _stack: Option>, ) -> Result, PermissionCheckError> { unreachable!("snapshotting!") } @@ -92,6 +106,7 @@ impl deno_node::NodePermissions for Permissions { &mut self, _p: &str, _api_name: Option<&str>, + _stack: Option>, ) -> Result { unreachable!("snapshotting!") } @@ -102,6 +117,7 @@ impl deno_node::NodePermissions for Permissions { &mut self, _p: &str, _api_name: Option<&str>, + _stack: Option>, ) -> Result { unreachable!("snapshotting!") } @@ -109,6 +125,7 @@ impl deno_node::NodePermissions for Permissions { &mut self, _kind: &str, _api_name: &str, + _stack: Option>, ) -> Result<(), PermissionCheckError> { unreachable!("snapshotting!") } @@ -119,6 +136,7 @@ impl deno_net::NetPermissions for Permissions { &mut self, _host: &(T, Option), _api_name: &str, + _stack: Option>, ) -> Result<(), PermissionCheckError> { unreachable!("snapshotting!") } @@ -127,6 +145,7 @@ impl deno_net::NetPermissions for Permissions { &mut self, _p: &str, _api_name: &str, + _stack: Option>, ) -> Result { unreachable!("snapshotting!") } @@ -135,6 +154,7 @@ impl deno_net::NetPermissions for Permissions { &mut self, _p: &str, _api_name: &str, + _stack: Option>, ) -> Result { unreachable!("snapshotting!") } @@ -143,6 +163,7 @@ impl deno_net::NetPermissions for Permissions { &mut self, _p: &'a Path, _api_name: &str, + _stack: Option>, ) -> Result, PermissionCheckError> { unreachable!("snapshotting!") } @@ -156,6 +177,7 @@ impl deno_fs::FsPermissions for Permissions { _write: bool, _path: &'a Path, _api_name: &str, + _stack: Option>, ) -> Result, FsError> { unreachable!("snapshotting!") } @@ -164,6 +186,7 @@ impl deno_fs::FsPermissions for Permissions { &mut self, _path: &str, _api_name: &str, + _stack: Option>, ) -> Result { unreachable!("snapshotting!") } @@ -171,6 +194,7 @@ impl deno_fs::FsPermissions for Permissions { fn check_read_all( &mut self, _api_name: &str, + _stack: Option>, ) -> Result<(), PermissionCheckError> { unreachable!("snapshotting!") } @@ -180,6 +204,7 @@ impl deno_fs::FsPermissions for Permissions { _path: &Path, _display: &str, _api_name: &str, + _stack: Option>, ) -> Result<(), PermissionCheckError> { unreachable!("snapshotting!") } @@ -188,6 +213,7 @@ impl deno_fs::FsPermissions for Permissions { &mut self, _path: &str, _api_name: &str, + _stack: Option>, ) -> Result { unreachable!("snapshotting!") } @@ -196,6 +222,7 @@ impl deno_fs::FsPermissions for Permissions { &mut self, _path: &str, _api_name: &str, + _stack: Option>, ) -> Result { unreachable!("snapshotting!") } @@ -203,6 +230,7 @@ impl deno_fs::FsPermissions for Permissions { fn check_write_all( &mut self, _api_name: &str, + _stack: Option>, ) -> Result<(), PermissionCheckError> { unreachable!("snapshotting!") } @@ -212,6 +240,7 @@ impl deno_fs::FsPermissions for Permissions { _path: &Path, _display: &str, _api_name: &str, + _stack: Option>, ) -> Result<(), PermissionCheckError> { unreachable!("snapshotting!") } @@ -220,6 +249,7 @@ impl deno_fs::FsPermissions for Permissions { &mut self, _path: &'a Path, _api_name: &str, + _stack: Option>, ) -> Result, PermissionCheckError> { unreachable!("snapshotting!") } @@ -228,6 +258,7 @@ impl deno_fs::FsPermissions for Permissions { &mut self, _path: &'a Path, _api_name: &str, + _stack: Option>, ) -> Result, PermissionCheckError> { unreachable!("snapshotting!") } @@ -238,6 +269,7 @@ impl deno_kv::sqlite::SqliteDbHandlerPermissions for Permissions { &mut self, _path: &str, _api_name: &str, + _stack: Option>, ) -> Result { unreachable!("snapshotting!") } @@ -246,6 +278,7 @@ impl deno_kv::sqlite::SqliteDbHandlerPermissions for Permissions { &mut self, _path: &'a Path, _api_name: &str, + _stack: Option>, ) -> Result, PermissionCheckError> { unreachable!("snapshotting!") } From b37ef2f7d4e63977d231d392f59a4556e3147e0a Mon Sep 17 00:00:00 2001 From: crowlkats Date: Thu, 7 Nov 2024 17:06:10 +0100 Subject: [PATCH 4/4] fix --- ext/fs/ops.rs | 3 ++- ext/napi/lib.rs | 1 + ext/node/ops/worker_threads.rs | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ext/fs/ops.rs b/ext/fs/ops.rs index 0287c10a32c33b..9118d8fbb623e6 100644 --- a/ext/fs/ops.rs +++ b/ext/fs/ops.rs @@ -878,7 +878,7 @@ where Ok(target_string) } -#[op2(async)] +#[op2(async, reentrant)] #[string] pub async fn op_fs_read_link_async

( state: Rc>, @@ -1329,6 +1329,7 @@ fn tmp_name( Ok(path) } +#[allow(clippy::too_many_arguments)] #[op2(reentrant)] pub fn op_fs_write_file_sync

( state: &mut OpState, diff --git a/ext/napi/lib.rs b/ext/napi/lib.rs index 9d0745a74955db..f48412aacfbe83 100644 --- a/ext/napi/lib.rs +++ b/ext/napi/lib.rs @@ -539,6 +539,7 @@ static NAPI_LOADED_MODULES: std::sync::LazyLock< RwLock>, > = std::sync::LazyLock::new(|| RwLock::new(HashMap::new())); +#[allow(clippy::too_many_arguments)] #[op2(reentrant)] fn op_napi_open( scope: &mut v8::HandleScope<'scope>, diff --git a/ext/node/ops/worker_threads.rs b/ext/node/ops/worker_threads.rs index bcee62e80c0852..6fc49c6ccf241b 100644 --- a/ext/node/ops/worker_threads.rs +++ b/ext/node/ops/worker_threads.rs @@ -46,7 +46,7 @@ pub enum WorkerThreadsFilenameError { } // todo(dsherret): we should remove this and do all this work inside op_create_worker -#[op2] +#[op2(reentrant)] #[string] pub fn op_worker_threads_filename

( state: &mut OpState,