1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-22 15:24:46 -05:00

feat(unstable): allow specifing gid and uid for subprocess (#11586)

This commit is contained in:
Leo K 2021-09-13 19:26:23 +02:00 committed by GitHub
parent 274ff6c469
commit a655a0f3e4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 90 additions and 0 deletions

View file

@ -2034,6 +2034,12 @@ declare namespace Deno {
* Environmental variables for subprocess can be specified using `opt.env` * Environmental variables for subprocess can be specified using `opt.env`
* mapping. * mapping.
* *
* `opt.uid` sets the child processs 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 * By default subprocess inherits stdio of parent process. To change that
* `opt.stdout`, `opt.stderr` and `opt.stdin` can be specified independently - * `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" * they can be set to either an rid of open file or set to "inherit" "piped"

View file

@ -713,8 +713,12 @@ declare namespace Deno {
export function run< export function run<
T extends RunOptions & { T extends RunOptions & {
clearEnv?: boolean; clearEnv?: boolean;
gid?: number;
uid?: number;
} = RunOptions & { } = RunOptions & {
clearEnv?: boolean; clearEnv?: boolean;
gid?: number;
uid?: number;
}, },
>(opt: T): Process<T>; >(opt: T): Process<T>;

View file

@ -537,3 +537,59 @@ unitTest(
p.close(); 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);
}
},
);

View file

@ -102,6 +102,8 @@
cwd = undefined, cwd = undefined,
clearEnv = false, clearEnv = false,
env = {}, env = {},
gid = undefined,
uid = undefined,
stdout = "inherit", stdout = "inherit",
stderr = "inherit", stderr = "inherit",
stdin = "inherit", stdin = "inherit",
@ -114,6 +116,8 @@
cwd, cwd,
clearEnv, clearEnv,
env: ObjectEntries(env), env: ObjectEntries(env),
gid,
uid,
stdin: isRid(stdin) ? "" : stdin, stdin: isRid(stdin) ? "" : stdin,
stdout: isRid(stdout) ? "" : stdout, stdout: isRid(stdout) ? "" : stdout,
stderr: isRid(stderr) ? "" : stderr, stderr: isRid(stderr) ? "" : stderr,

View file

@ -63,6 +63,8 @@ pub struct RunArgs {
cwd: Option<String>, cwd: Option<String>,
clear_env: bool, clear_env: bool,
env: Vec<(String, String)>, env: Vec<(String, String)>,
gid: Option<u32>,
uid: Option<u32>,
stdin: String, stdin: String,
stdout: String, stdout: String,
stderr: String, stderr: String,
@ -123,6 +125,24 @@ fn op_run(
c.env(key, value); 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 // TODO: make this work with other resources, eg. sockets
if !run_args.stdin.is_empty() { if !run_args.stdin.is_empty() {
c.stdin(subprocess_stdio_map(run_args.stdin.as_ref())?); c.stdin(subprocess_stdio_map(run_args.stdin.as_ref())?);