diff --git a/runtime/permissions/lib.rs b/runtime/permissions/lib.rs index 0d9d37a362..b0fa9eb101 100644 --- a/runtime/permissions/lib.rs +++ b/runtime/permissions/lib.rs @@ -2241,7 +2241,50 @@ pub fn create_child_permissions( main_perms: &mut Permissions, child_permissions_arg: ChildPermissionsArg, ) -> Result { + fn is_granted_unary(arg: &ChildUnaryPermissionArg) -> bool { + match arg { + ChildUnaryPermissionArg::Inherit | ChildUnaryPermissionArg::Granted => { + true + } + ChildUnaryPermissionArg::NotGranted + | ChildUnaryPermissionArg::GrantedList(_) => false, + } + } + + fn is_granted_unit(arg: &ChildUnitPermissionArg) -> bool { + match arg { + ChildUnitPermissionArg::Inherit | ChildUnitPermissionArg::Granted => true, + ChildUnitPermissionArg::NotGranted => false, + } + } + let mut worker_perms = Permissions::none_without_prompt(); + + worker_perms.all = main_perms + .all + .create_child_permissions(ChildUnitPermissionArg::Inherit)?; + + // downgrade the `worker_perms.all` based on the other values + if worker_perms.all.query() == PermissionState::Granted { + let unary_perms = [ + &child_permissions_arg.read, + &child_permissions_arg.write, + &child_permissions_arg.net, + &child_permissions_arg.env, + &child_permissions_arg.sys, + &child_permissions_arg.run, + &child_permissions_arg.ffi, + ]; + let unit_perms = [&child_permissions_arg.hrtime]; + let allow_all = unary_perms.into_iter().all(is_granted_unary) + && unit_perms.into_iter().all(is_granted_unit); + if !allow_all { + worker_perms.all.revoke(); + } + } + + // WARNING: When adding a permission here, ensure it is handled + // in the worker_perms.all block above worker_perms.read = main_perms .read .create_child_permissions(child_permissions_arg.read)?; @@ -2266,9 +2309,6 @@ pub fn create_child_permissions( worker_perms.hrtime = main_perms .hrtime .create_child_permissions(child_permissions_arg.hrtime)?; - worker_perms.all = main_perms - .all - .create_child_permissions(ChildUnitPermissionArg::Inherit)?; Ok(worker_perms) } diff --git a/tests/unit/os_test.ts b/tests/unit/os_test.ts index 80b421e63d..42b5985111 100644 --- a/tests/unit/os_test.ts +++ b/tests/unit/os_test.ts @@ -3,7 +3,6 @@ import { assert, assertEquals, assertNotEquals, - assertStringIncludes, assertThrows, } from "./test_util.ts"; @@ -197,36 +196,21 @@ Deno.test({ permissions: { read: false } }, function execPathPerm() { ); }); -Deno.test(async function execPathPerm() { - if (Deno.build.os !== "linux") return; - // This is hack to bypass a bug in deno test runner, - // Currently if you specify {read: true} permission, it will stil pass --allow-all (tests are run with deno test --allow-all) implicitly, so this test won't work - // The workaround is to spawn a deno executable with the needed permissions - // TODO(#25085): remove this hack when the bug is fixed - const cmd = new Deno.Command(Deno.execPath(), { - args: ["run", "--allow-read", "-"], - stdin: "piped", - stderr: "piped", - }).spawn(); - const stdinWriter = cmd.stdin.getWriter(); - await stdinWriter - .write( - new TextEncoder().encode('Deno.readTextFileSync("/proc/net/dev")'), +Deno.test( + { + ignore: Deno.build.os !== "linux", + permissions: { read: true, run: false }, + }, + function procRequiresAllowAll() { + assertThrows( + () => { + Deno.readTextFileSync("/proc/net/dev"); + }, + Deno.errors.PermissionDenied, + `Requires all access to "/proc/net/dev", run again with the --allow-all flag`, ); - await stdinWriter.close(); - await cmd.status; - - const stderrReder = cmd.stderr.getReader(); - const error = await stderrReder - .read() - .then((r) => new TextDecoder().decode(r.value)); - await stderrReder.cancel(); - - assertStringIncludes( - error, - `PermissionDenied: Requires all access to "/proc/net/dev", run again with the --allow-all flag`, - ); -}); + }, +); Deno.test( { permissions: { sys: ["loadavg"] } }, diff --git a/tests/unit/read_file_test.ts b/tests/unit/read_file_test.ts index 562bf99698..67944813bb 100644 --- a/tests/unit/read_file_test.ts +++ b/tests/unit/read_file_test.ts @@ -148,7 +148,7 @@ Deno.test( ); Deno.test( - { permissions: { read: true }, ignore: Deno.build.os !== "linux" }, + { ignore: Deno.build.os !== "linux" }, async function readFileProcFs() { const data = await Deno.readFile("/proc/self/stat"); assert(data.byteLength > 0); diff --git a/tests/unit/read_text_file_test.ts b/tests/unit/read_text_file_test.ts index 94aa5f0a85..cab75fd47b 100644 --- a/tests/unit/read_text_file_test.ts +++ b/tests/unit/read_text_file_test.ts @@ -146,7 +146,7 @@ Deno.test( ); Deno.test( - { permissions: { read: true }, ignore: Deno.build.os !== "linux" }, + { ignore: Deno.build.os !== "linux" }, async function readTextFileProcFs() { const data = await Deno.readTextFile("/proc/self/stat"); assert(data.length > 0);