Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

child_process: spawnSync crashes trying to terminate setuid child because of maxBuffer exceeded #31747

Closed
kolontsov opened this issue Feb 12, 2020 · 1 comment
Labels
child_process Issues and PRs related to the child_process subsystem. confirmed-bug Issues with confirmed bugs.

Comments

@kolontsov
Copy link

kolontsov commented Feb 12, 2020

  • Version: v13.8.0, v12.16.0
  • Platform: macOS 10.15.3, Ubuntu 16.04.6 (4.15.0-70-generic)
  • Subsystem: child_process, src/spawn_sync.c

What steps will reproduce the bug?

$ cat test.c
#include <unistd.h>
#include <stdio.h>
int main() { setuid(0); while (1) printf("hello"); }

$ gcc -o test test.c; sudo chown root test; sudo chmod 4755 test

$ node -e "require('child_process').spawnSync('./test')"

OR

$ node -e "require('child_process').spawnSync('sudo', ['bash', '-c', 'ls -lR /'])"

How often does it reproduce? Is there a required condition?

Always

What is the expected behavior?

I expect to get ENOBUF (because of maxBuffer reached) and/or EPERM (because child process cannot be killed), so I can handle it somehow - but not crash.

What do you see instead?

node[68984]: ../src/spawn_sync.cc:611:void node::SyncProcessRunner::Kill(): Assertion `r >= 0 || r == UV_ESRCH' failed.
 1: 0x100ba0c4a node::Abort() (.cold.1) [/usr/local/bin/node]
 2: 0x100084961 node::FatalError(char const*, char const*) [/usr/local/bin/node]
 3: 0x100084719 node::AppendExceptionLine(node::Environment*, v8::Local<v8::Value>, v8::Local<v8::Message>, node::ErrorHandlingMode) [/usr/local/bin/node]
 4: 0x10010657d node::SyncProcessRunner::Kill() [/usr/local/bin/node]
 5: 0x1006cb116 uv__stream_io [/usr/local/bin/node]
 6: 0x1006d23a8 uv__io_poll [/usr/local/bin/node]
 7: 0x1006c2fa2 uv_run [/usr/local/bin/node]
 8: 0x10010598f node::SyncProcessRunner::TryInitializeAndRunLoop(v8::Local<v8::Value>) [/usr/local/bin/node]
 9: 0x100105674 node::SyncProcessRunner::Run(v8::Local<v8::Value>) [/usr/local/bin/node]
10: 0x100105513 node::SyncProcessRunner::Spawn(v8::FunctionCallbackInfo<v8::Value> const&) [/usr/local/bin/node]
11: 0x1001cb578 v8::internal::FunctionCallbackArguments::Call(v8::internal::CallHandlerInfo) [/usr/local/bin/node]
12: 0x1001cac02 v8::internal::MaybeHandle<v8::internal::Object> v8::internal::(anonymous namespace)::HandleApiCallHelper<false>(v8::internal::Isolate*, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::FunctionTemplateInfo>, v8::internal::Handle<v8::internal::Object>, v8::internal::BuiltinArguments) [/usr/local/bin/node]
13: 0x1001ca40e v8::internal::Builtin_Impl_HandleApiCall(v8::internal::BuiltinArguments, v8::internal::Isolate*) [/usr/local/bin/node]
14: 0x1007503d9 Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_BuiltinExit [/usr/local/bin/node]
zsh: abort      node -e "require('child_process').spawnSync('./test')"

Additional information

According to documentation, child_process.spawnSync() terminates child process if it's output is larger than maxBuffer. If child process can't be killed (because of setuid call), node crashes in CHECK() below https://github.com/nodejs/node/blob/master/src/spawn_sync.cc#L611:

    // If uv_kill failed with an error that isn't ESRCH, the user probably
    // specified an invalid or unsupported signal. Signal this to the user as
    // and error and kill the process with SIGKILL instead.
    if (r < 0 && r != UV_ESRCH) {
      SetError(r);

      r = uv_process_kill(&uv_process_, SIGKILL);
      CHECK(r >= 0 || r == UV_ESRCH);
    }

Shouldn't we also check for UV_EPERM?

bnoordhuis added a commit to bnoordhuis/io.js that referenced this issue Feb 13, 2020
We might not have sufficient privileges to signal the child process
so don't make assumptions about the return value of `uv_process_kill()`.

Example:

    node -e 'child_process.spawnSync("sudo", ["ls"], { maxBuffer: 1 })'

No test because:

1. The test needs to run as root (can't invoke sudo), and

2. The parent needs to drop privileges but can't, because
   then the child process won't have sufficient privileges.

Fixes: nodejs#31747
@bnoordhuis
Copy link
Member

#31768

@bnoordhuis bnoordhuis added child_process Issues and PRs related to the child_process subsystem. confirmed-bug Issues with confirmed bugs. labels Feb 13, 2020
MylesBorins pushed a commit that referenced this issue Mar 11, 2020
We might not have sufficient privileges to signal the child process
so don't make assumptions about the return value of `uv_process_kill()`.

Example:

    node -e 'child_process.spawnSync("sudo", ["ls"], { maxBuffer: 1 })'

No test because:

1. The test needs to run as root (can't invoke sudo), and

2. The parent needs to drop privileges but can't, because
   then the child process won't have sufficient privileges.

Fixes: #31747

PR-URL: #31768
Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: David Carlier <devnexen@gmail.com>
targos pushed a commit that referenced this issue Apr 22, 2020
We might not have sufficient privileges to signal the child process
so don't make assumptions about the return value of `uv_process_kill()`.

Example:

    node -e 'child_process.spawnSync("sudo", ["ls"], { maxBuffer: 1 })'

No test because:

1. The test needs to run as root (can't invoke sudo), and

2. The parent needs to drop privileges but can't, because
   then the child process won't have sufficient privileges.

Fixes: #31747

PR-URL: #31768
Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: David Carlier <devnexen@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
child_process Issues and PRs related to the child_process subsystem. confirmed-bug Issues with confirmed bugs.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants