Skip to content

Commit

Permalink
feat: permission stack traces in ops (#26938)
Browse files Browse the repository at this point in the history
This commit improves permission prompts by adding an option
to print a full trace of where the permissions is being requested.

Due to big performance hint of stack trace collection, this is only
enabled when `DENO_TRACE_PERMISSIONS` env var is present.

Closes #20756

---------

Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
  • Loading branch information
crowlKats and bartlomieju authored Nov 20, 2024
1 parent 8f72798 commit cf49599
Show file tree
Hide file tree
Showing 34 changed files with 294 additions and 181 deletions.
41 changes: 22 additions & 19 deletions cli/args/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1160,25 +1160,26 @@ static ENV_VARIABLES_HELP: &str = cstr!(
<y>Docs:</> <c>https://docs.deno.com/go/env-vars</>
<g>DENO_AUTH_TOKENS</> A semi-colon separated list of bearer tokens and hostnames
to use when fetching remote modules from private repositories
<p(245)>(e.g. "abcde12345@deno.land;54321edcba@github.com")</>
<g>DENO_CERT</> Load certificate authorities from PEM encoded file
<g>DENO_DIR</> Set the cache directory
<g>DENO_INSTALL_ROOT</> Set deno install's output directory
<p(245)>(defaults to $HOME/.deno/bin)</>
<g>DENO_NO_PACKAGE_JSON</> Disables auto-resolution of package.json
<g>DENO_NO_UPDATE_CHECK</> Set to disable checking if a newer Deno version is available
<g>DENO_TLS_CA_STORE</> Comma-separated list of order dependent certificate stores.
Possible values: "system", "mozilla".
<p(245)>(defaults to "mozilla")</>
<g>HTTP_PROXY</> Proxy address for HTTP requests
<p(245)>(module downloads, fetch)</>
<g>HTTPS_PROXY</> Proxy address for HTTPS requests
<p(245)>(module downloads, fetch)</>
<g>NO_COLOR</> Set to disable color
<g>NO_PROXY</> Comma-separated list of hosts which do not use a proxy
<p(245)>(module downloads, fetch)</>
<g>NPM_CONFIG_REGISTRY</> URL to use for the npm registry."#
to use when fetching remote modules from private repositories
<p(245)>(e.g. "abcde12345@deno.land;54321edcba@github.com")</>
<g>DENO_CERT</> Load certificate authorities from PEM encoded file
<g>DENO_DIR</> Set the cache directory
<g>DENO_INSTALL_ROOT</> Set deno install's output directory
<p(245)>(defaults to $HOME/.deno/bin)</>
<g>DENO_NO_PACKAGE_JSON</> Disables auto-resolution of package.json
<g>DENO_NO_UPDATE_CHECK</> Set to disable checking if a newer Deno version is available
<g>DENO_TLS_CA_STORE</> Comma-separated list of order dependent certificate stores.
<g>DENO_TRACE_PERMISSIONS</> Environmental variable to enable stack traces in permission prompts.
Possible values: "system", "mozilla".
<p(245)>(defaults to "mozilla")</>
<g>HTTP_PROXY</> Proxy address for HTTP requests
<p(245)>(module downloads, fetch)</>
<g>HTTPS_PROXY</> Proxy address for HTTPS requests
<p(245)>(module downloads, fetch)</>
<g>NO_COLOR</> Set to disable color
<g>NO_PROXY</> Comma-separated list of hosts which do not use a proxy
<p(245)>(module downloads, fetch)</>
<g>NPM_CONFIG_REGISTRY</> URL to use for the npm registry."#
);

static DENO_HELP: &str = cstr!(
Expand Down Expand Up @@ -3346,6 +3347,8 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
<p(245)>--deny-run | --deny-run="whoami,ps"</>
<g>--deny-ffi[=<<PATH>...]</> (Unstable) Deny loading dynamic libraries. Optionally specify denied directories or files.
<p(245)>--deny-ffi | --deny-ffi="./libfoo.so"</>
<g>DENO_TRACE_PERMISSIONS</> Environmental variable to enable stack traces in permission prompts.
<p(245)>DENO_TRACE_PERMISSIONS=1 deno run main.ts</>
"#))
.arg(
{
Expand Down
4 changes: 4 additions & 0 deletions cli/args/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1912,6 +1912,10 @@ pub fn resolve_no_prompt(flags: &PermissionFlags) -> bool {
flags.no_prompt || has_flag_env_var("DENO_NO_PROMPT")
}

pub fn has_trace_permissions_enabled() -> bool {
has_flag_env_var("DENO_TRACE_PERMISSIONS")
}

pub fn has_flag_env_var(name: &str) -> bool {
let value = env::var(name);
matches!(value.as_ref().map(|s| s.as_str()), Ok("1"))
Expand Down
2 changes: 1 addition & 1 deletion cli/ops/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ fn op_bench_get_origin(state: &mut OpState) -> String {
#[derive(Clone)]
struct PermissionsHolder(Uuid, PermissionsContainer);

#[op2]
#[op2(stack_trace)]
#[serde]
pub fn op_pledge_test_permissions(
state: &mut OpState,
Expand Down
2 changes: 1 addition & 1 deletion cli/ops/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ deno_core::extension!(deno_test,
#[derive(Clone)]
struct PermissionsHolder(Uuid, PermissionsContainer);

#[op2]
#[op2(stack_trace)]
#[serde]
pub fn op_pledge_test_permissions(
state: &mut OpState,
Expand Down
4 changes: 4 additions & 0 deletions cli/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,8 @@ impl CliMainWorkerFactory {
origin_storage_dir,
stdio,
skip_op_registration: shared.options.skip_op_registration,
enable_stack_trace_arg_in_ops: crate::args::has_trace_permissions_enabled(
),
};

let mut worker = MainWorker::bootstrap_from_options(
Expand Down Expand Up @@ -813,6 +815,8 @@ 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_trace_permissions_enabled(
),
};

WebWorker::bootstrap_from_options(services, options)
Expand Down
4 changes: 2 additions & 2 deletions ext/fetch/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ impl FetchPermissions for deno_permissions::PermissionsContainer {
}
}

#[op2]
#[op2(stack_trace)]
#[serde]
#[allow(clippy::too_many_arguments)]
pub fn op_fetch<FP>(
Expand Down Expand Up @@ -866,7 +866,7 @@ fn default_true() -> bool {
true
}

#[op2]
#[op2(stack_trace)]
#[smi]
pub fn op_fetch_custom_client<FP>(
state: &mut OpState,
Expand Down
4 changes: 2 additions & 2 deletions ext/ffi/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ fn ffi_call(
}
}

#[op2(async)]
#[op2(async, stack_trace)]
#[serde]
pub fn op_ffi_call_ptr_nonblocking<FP>(
scope: &mut v8::HandleScope,
Expand Down Expand Up @@ -385,7 +385,7 @@ pub fn op_ffi_call_nonblocking(
})
}

#[op2(reentrant)]
#[op2(reentrant, stack_trace)]
#[serde]
pub fn op_ffi_call_ptr<FP>(
scope: &mut v8::HandleScope,
Expand Down
2 changes: 1 addition & 1 deletion ext/ffi/callback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ pub struct RegisterCallbackArgs {
result: NativeType,
}

#[op2]
#[op2(stack_trace)]
pub fn op_ffi_unsafe_callback_create<FP, 'scope>(
state: &mut OpState,
scope: &mut v8::HandleScope<'scope>,
Expand Down
2 changes: 1 addition & 1 deletion ext/ffi/dlfcn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ pub struct FfiLoadArgs {
symbols: HashMap<String, ForeignSymbol>,
}

#[op2]
#[op2(stack_trace)]
pub fn op_ffi_load<'scope, FP>(
scope: &mut v8::HandleScope<'scope>,
state: Rc<RefCell<OpState>>,
Expand Down
42 changes: 21 additions & 21 deletions ext/ffi/repr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub enum ReprError {
Permission(#[from] deno_permissions::PermissionCheckError),
}

#[op2(fast)]
#[op2(fast, stack_trace)]
pub fn op_ffi_ptr_create<FP>(
state: &mut OpState,
#[bigint] ptr_number: usize,
Expand All @@ -63,7 +63,7 @@ where
Ok(ptr_number as *mut c_void)
}

#[op2(fast)]
#[op2(fast, stack_trace)]
pub fn op_ffi_ptr_equals<FP>(
state: &mut OpState,
a: *const c_void,
Expand All @@ -78,7 +78,7 @@ where
Ok(a == b)
}

#[op2]
#[op2(stack_trace)]
pub fn op_ffi_ptr_of<FP>(
state: &mut OpState,
#[anybuffer] buf: *const u8,
Expand All @@ -92,7 +92,7 @@ where
Ok(buf as *mut c_void)
}

#[op2(fast)]
#[op2(fast, stack_trace)]
pub fn op_ffi_ptr_of_exact<FP>(
state: &mut OpState,
buf: v8::Local<v8::ArrayBufferView>,
Expand All @@ -112,7 +112,7 @@ where
Ok(buf.as_ptr() as _)
}

#[op2(fast)]
#[op2(fast, stack_trace)]
pub fn op_ffi_ptr_offset<FP>(
state: &mut OpState,
ptr: *mut c_void,
Expand Down Expand Up @@ -142,7 +142,7 @@ unsafe extern "C" fn noop_deleter_callback(
) {
}

#[op2(fast)]
#[op2(fast, stack_trace)]
#[bigint]
pub fn op_ffi_ptr_value<FP>(
state: &mut OpState,
Expand All @@ -157,7 +157,7 @@ where
Ok(ptr as usize)
}

#[op2]
#[op2(stack_trace)]
pub fn op_ffi_get_buf<FP, 'scope>(
scope: &mut v8::HandleScope<'scope>,
state: &mut OpState,
Expand Down Expand Up @@ -189,7 +189,7 @@ where
Ok(array_buffer)
}

#[op2]
#[op2(stack_trace)]
pub fn op_ffi_buf_copy_into<FP>(
state: &mut OpState,
src: *mut c_void,
Expand Down Expand Up @@ -219,7 +219,7 @@ where
}
}

#[op2]
#[op2(stack_trace)]
pub fn op_ffi_cstr_read<FP, 'scope>(
scope: &mut v8::HandleScope<'scope>,
state: &mut OpState,
Expand All @@ -244,7 +244,7 @@ where
Ok(value)
}

#[op2(fast)]
#[op2(fast, stack_trace)]
pub fn op_ffi_read_bool<FP>(
state: &mut OpState,
ptr: *mut c_void,
Expand All @@ -264,7 +264,7 @@ where
Ok(unsafe { ptr::read_unaligned::<bool>(ptr.offset(offset) as *const bool) })
}

#[op2(fast)]
#[op2(fast, stack_trace)]
pub fn op_ffi_read_u8<FP>(
state: &mut OpState,
ptr: *mut c_void,
Expand All @@ -286,7 +286,7 @@ where
})
}

#[op2(fast)]
#[op2(fast, stack_trace)]
pub fn op_ffi_read_i8<FP>(
state: &mut OpState,
ptr: *mut c_void,
Expand All @@ -308,7 +308,7 @@ where
})
}

#[op2(fast)]
#[op2(fast, stack_trace)]
pub fn op_ffi_read_u16<FP>(
state: &mut OpState,
ptr: *mut c_void,
Expand All @@ -330,7 +330,7 @@ where
})
}

#[op2(fast)]
#[op2(fast, stack_trace)]
pub fn op_ffi_read_i16<FP>(
state: &mut OpState,
ptr: *mut c_void,
Expand All @@ -352,7 +352,7 @@ where
})
}

#[op2(fast)]
#[op2(fast, stack_trace)]
pub fn op_ffi_read_u32<FP>(
state: &mut OpState,
ptr: *mut c_void,
Expand All @@ -372,7 +372,7 @@ where
Ok(unsafe { ptr::read_unaligned::<u32>(ptr.offset(offset) as *const u32) })
}

#[op2(fast)]
#[op2(fast, stack_trace)]
pub fn op_ffi_read_i32<FP>(
state: &mut OpState,
ptr: *mut c_void,
Expand All @@ -392,7 +392,7 @@ where
Ok(unsafe { ptr::read_unaligned::<i32>(ptr.offset(offset) as *const i32) })
}

#[op2(fast)]
#[op2(fast, stack_trace)]
#[bigint]
pub fn op_ffi_read_u64<FP>(
state: &mut OpState,
Expand All @@ -418,7 +418,7 @@ where
Ok(value)
}

#[op2(fast)]
#[op2(fast, stack_trace)]
#[bigint]
pub fn op_ffi_read_i64<FP>(
state: &mut OpState,
Expand All @@ -444,7 +444,7 @@ where
Ok(value)
}

#[op2(fast)]
#[op2(fast, stack_trace)]
pub fn op_ffi_read_f32<FP>(
state: &mut OpState,
ptr: *mut c_void,
Expand All @@ -464,7 +464,7 @@ where
Ok(unsafe { ptr::read_unaligned::<f32>(ptr.offset(offset) as *const f32) })
}

#[op2(fast)]
#[op2(fast, stack_trace)]
pub fn op_ffi_read_f64<FP>(
state: &mut OpState,
ptr: *mut c_void,
Expand All @@ -484,7 +484,7 @@ where
Ok(unsafe { ptr::read_unaligned::<f64>(ptr.offset(offset) as *const f64) })
}

#[op2(fast)]
#[op2(fast, stack_trace)]
pub fn op_ffi_read_ptr<FP>(
state: &mut OpState,
ptr: *mut c_void,
Expand Down
Loading

0 comments on commit cf49599

Please sign in to comment.