summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo K <crowlkats@toaxl.com>2021-09-13 19:26:23 +0200
committerGitHub <noreply@github.com>2021-09-13 19:26:23 +0200
commita655a0f3e4201840eda94938fc8d6222c2b94a99 (patch)
tree9b065e3e2e4fcfd7f59ef004e2cd2bc2b6c785de
parent274ff6c469656bfe527fa644c24dfecc79e90ce4 (diff)
feat(unstable): allow specifing gid and uid for subprocess (#11586)
-rw-r--r--cli/dts/lib.deno.ns.d.ts6
-rw-r--r--cli/dts/lib.deno.unstable.d.ts4
-rw-r--r--cli/tests/unit/process_test.ts56
-rw-r--r--runtime/js/40_process.js4
-rw-r--r--runtime/ops/process.rs20
5 files changed, 90 insertions, 0 deletions
diff --git a/cli/dts/lib.deno.ns.d.ts b/cli/dts/lib.deno.ns.d.ts
index 5b6849bfd..05e600ed7 100644
--- a/cli/dts/lib.deno.ns.d.ts
+++ b/cli/dts/lib.deno.ns.d.ts
@@ -2034,6 +2034,12 @@ declare namespace Deno {
* Environmental variables for subprocess can be specified using `opt.env`
* mapping.
*
+ * `opt.uid` sets the child process’s user ID. This translates to a setuid call
+ * in the child process. Failure in the setuid call will cause the spawn to fail.
+ *
+ * `opt.gid` is similar to `opt.uid`, but sets the group ID of the child process.
+ * This has the same semantics as the uid field.
+ *
* By default subprocess inherits stdio of parent process. To change that
* `opt.stdout`, `opt.stderr` and `opt.stdin` can be specified independently -
* they can be set to either an rid of open file or set to "inherit" "piped"
diff --git a/cli/dts/lib.deno.unstable.d.ts b/cli/dts/lib.deno.unstable.d.ts
index 5854a5181..1a27f2b38 100644
--- a/cli/dts/lib.deno.unstable.d.ts
+++ b/cli/dts/lib.deno.unstable.d.ts
@@ -713,8 +713,12 @@ declare namespace Deno {
export function run<
T extends RunOptions & {
clearEnv?: boolean;
+ gid?: number;
+ uid?: number;
} = RunOptions & {
clearEnv?: boolean;
+ gid?: number;
+ uid?: number;
},
>(opt: T): Process<T>;
diff --git a/cli/tests/unit/process_test.ts b/cli/tests/unit/process_test.ts
index 371521e33..9f8e9cd9f 100644
--- a/cli/tests/unit/process_test.ts
+++ b/cli/tests/unit/process_test.ts
@@ -537,3 +537,59 @@ unitTest(
p.close();
},
);
+
+unitTest(
+ { perms: { run: true, read: true }, ignore: Deno.build.os === "windows" },
+ async function uid(): Promise<void> {
+ const p = Deno.run({
+ cmd: [
+ "id",
+ "-u",
+ ],
+ stdout: "piped",
+ });
+
+ const currentUid = new TextDecoder().decode(await p.output());
+ p.close();
+
+ if (currentUid !== "0") {
+ assertThrows(() => {
+ Deno.run({
+ cmd: [
+ "echo",
+ "fhqwhgads",
+ ],
+ uid: 0,
+ });
+ }, Deno.errors.PermissionDenied);
+ }
+ },
+);
+
+unitTest(
+ { perms: { run: true, read: true }, ignore: Deno.build.os === "windows" },
+ async function gid(): Promise<void> {
+ const p = Deno.run({
+ cmd: [
+ "id",
+ "-g",
+ ],
+ stdout: "piped",
+ });
+
+ const currentGid = new TextDecoder().decode(await p.output());
+ p.close();
+
+ if (currentGid !== "0") {
+ assertThrows(() => {
+ Deno.run({
+ cmd: [
+ "echo",
+ "fhqwhgads",
+ ],
+ gid: 0,
+ });
+ }, Deno.errors.PermissionDenied);
+ }
+ },
+);
diff --git a/runtime/js/40_process.js b/runtime/js/40_process.js
index 543c53c27..782dfe476 100644
--- a/runtime/js/40_process.js
+++ b/runtime/js/40_process.js
@@ -102,6 +102,8 @@
cwd = undefined,
clearEnv = false,
env = {},
+ gid = undefined,
+ uid = undefined,
stdout = "inherit",
stderr = "inherit",
stdin = "inherit",
@@ -114,6 +116,8 @@
cwd,
clearEnv,
env: ObjectEntries(env),
+ gid,
+ uid,
stdin: isRid(stdin) ? "" : stdin,
stdout: isRid(stdout) ? "" : stdout,
stderr: isRid(stderr) ? "" : stderr,
diff --git a/runtime/ops/process.rs b/runtime/ops/process.rs
index b47492e58..e40a15b4b 100644
--- a/runtime/ops/process.rs
+++ b/runtime/ops/process.rs
@@ -63,6 +63,8 @@ pub struct RunArgs {
cwd: Option<String>,
clear_env: bool,
env: Vec<(String, String)>,
+ gid: Option<u32>,
+ uid: Option<u32>,
stdin: String,
stdout: String,
stderr: String,
@@ -123,6 +125,24 @@ fn op_run(
c.env(key, value);
}
+ #[cfg(unix)]
+ if let Some(gid) = run_args.gid {
+ super::check_unstable(state, "Deno.run.gid");
+ c.gid(gid);
+ }
+ #[cfg(unix)]
+ if let Some(uid) = run_args.uid {
+ super::check_unstable(state, "Deno.run.uid");
+ c.uid(uid);
+ }
+ #[cfg(unix)]
+ unsafe {
+ c.pre_exec(|| {
+ libc::setgroups(0, std::ptr::null());
+ Ok(())
+ });
+ }
+
// TODO: make this work with other resources, eg. sockets
if !run_args.stdin.is_empty() {
c.stdin(subprocess_stdio_map(run_args.stdin.as_ref())?);