|
27 | 27 | #if defined(_MSC_VER)
|
28 | 28 | #include <direct.h>
|
29 | 29 | #include <io.h>
|
| 30 | +#include <process.h> |
30 | 31 | #define umask _umask
|
31 | 32 | typedef int mode_t;
|
32 | 33 | #else
|
33 | 34 | #include <pthread.h>
|
34 | 35 | #include <sys/resource.h> // getrlimit, setrlimit
|
35 | 36 | #include <termios.h> // tcgetattr, tcsetattr
|
| 37 | +#include <unistd.h> |
36 | 38 | #endif
|
37 | 39 |
|
38 | 40 | namespace node {
|
@@ -495,6 +497,95 @@ static void ReallyExit(const FunctionCallbackInfo<Value>& args) {
|
495 | 497 | env->Exit(code);
|
496 | 498 | }
|
497 | 499 |
|
| 500 | +#ifdef __POSIX__ |
| 501 | +inline int persist_standard_stream(int fd) { |
| 502 | + int flags = fcntl(fd, F_GETFD, 0); |
| 503 | + |
| 504 | + if (flags < 0) { |
| 505 | + return flags; |
| 506 | + } |
| 507 | + |
| 508 | + flags &= ~FD_CLOEXEC; |
| 509 | + return fcntl(fd, F_SETFD, flags); |
| 510 | +} |
| 511 | + |
| 512 | +static void Execve(const FunctionCallbackInfo<Value>& args) { |
| 513 | + Environment* env = Environment::GetCurrent(args); |
| 514 | + Isolate* isolate = env->isolate(); |
| 515 | + Local<Context> context = env->context(); |
| 516 | + |
| 517 | + THROW_IF_INSUFFICIENT_PERMISSIONS( |
| 518 | + env, permission::PermissionScope::kChildProcess, ""); |
| 519 | + |
| 520 | + CHECK(args[0]->IsString()); |
| 521 | + CHECK(args[1]->IsArray()); |
| 522 | + CHECK(args[2]->IsArray()); |
| 523 | + |
| 524 | + Local<Array> argv_array = args[1].As<Array>(); |
| 525 | + Local<Array> envp_array = args[2].As<Array>(); |
| 526 | + |
| 527 | + // Copy arguments and environment |
| 528 | + Utf8Value executable(isolate, args[0]); |
| 529 | + std::vector<std::string> argv_strings(argv_array->Length()); |
| 530 | + std::vector<std::string> envp_strings(envp_array->Length()); |
| 531 | + std::vector<char*> argv(argv_array->Length() + 1); |
| 532 | + std::vector<char*> envp(envp_array->Length() + 1); |
| 533 | + |
| 534 | + for (unsigned int i = 0; i < argv_array->Length(); i++) { |
| 535 | + Local<Value> str; |
| 536 | + if (!argv_array->Get(context, i).ToLocal(&str)) { |
| 537 | + THROW_ERR_INVALID_ARG_VALUE(env, "Failed to deserialize argument."); |
| 538 | + return; |
| 539 | + } |
| 540 | + |
| 541 | + argv_strings[i] = Utf8Value(isolate, str).ToString(); |
| 542 | + argv[i] = argv_strings[i].data(); |
| 543 | + } |
| 544 | + argv[argv_array->Length()] = nullptr; |
| 545 | + |
| 546 | + for (unsigned int i = 0; i < envp_array->Length(); i++) { |
| 547 | + Local<Value> str; |
| 548 | + if (!envp_array->Get(context, i).ToLocal(&str)) { |
| 549 | + THROW_ERR_INVALID_ARG_VALUE( |
| 550 | + env, "Failed to deserialize environment variable."); |
| 551 | + return; |
| 552 | + } |
| 553 | + |
| 554 | + envp_strings[i] = Utf8Value(isolate, str).ToString(); |
| 555 | + envp[i] = envp_strings[i].data(); |
| 556 | + } |
| 557 | + |
| 558 | + envp[envp_array->Length()] = nullptr; |
| 559 | + |
| 560 | + // Set stdin, stdout and stderr to be non-close-on-exec |
| 561 | + // so that the new process will inherit it. |
| 562 | + if (persist_standard_stream(0) < 0 || persist_standard_stream(1) < 0 || |
| 563 | + persist_standard_stream(2) < 0) { |
| 564 | + env->ThrowErrnoException(errno, "fcntl"); |
| 565 | + return; |
| 566 | + } |
| 567 | + |
| 568 | + // Perform the execve operation. |
| 569 | + RunAtExit(env); |
| 570 | + execve(*executable, argv.data(), envp.data()); |
| 571 | + |
| 572 | + // If it returns, it means that the execve operation failed. |
| 573 | + // In that case we abort the process. |
| 574 | + auto error_message = std::string("process.execve failed with error code ") + |
| 575 | + errors::errno_string(errno); |
| 576 | + |
| 577 | + // Abort the process |
| 578 | + Local<v8::Value> exception = |
| 579 | + ErrnoException(isolate, errno, "execve", *executable); |
| 580 | + Local<v8::Message> message = v8::Exception::CreateMessage(isolate, exception); |
| 581 | + |
| 582 | + std::string info = FormatErrorMessage( |
| 583 | + isolate, context, error_message.c_str(), message, true); |
| 584 | + FPrintF(stderr, "%s\n", info); |
| 585 | + ABORT(); |
| 586 | +} |
| 587 | +#endif |
| 588 | + |
498 | 589 | static void LoadEnvFile(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
499 | 590 | Environment* env = Environment::GetCurrent(args);
|
500 | 591 | std::string path = ".env";
|
@@ -687,6 +778,10 @@ static void CreatePerIsolateProperties(IsolateData* isolate_data,
|
687 | 778 | SetMethodNoSideEffect(isolate, target, "cwd", Cwd);
|
688 | 779 | SetMethod(isolate, target, "dlopen", binding::DLOpen);
|
689 | 780 | SetMethod(isolate, target, "reallyExit", ReallyExit);
|
| 781 | + |
| 782 | +#ifdef __POSIX__ |
| 783 | + SetMethod(isolate, target, "execve", Execve); |
| 784 | +#endif |
690 | 785 | SetMethodNoSideEffect(isolate, target, "uptime", Uptime);
|
691 | 786 | SetMethod(isolate, target, "patchProcessObject", PatchProcessObject);
|
692 | 787 |
|
@@ -730,6 +825,10 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
|
730 | 825 | registry->Register(Cwd);
|
731 | 826 | registry->Register(binding::DLOpen);
|
732 | 827 | registry->Register(ReallyExit);
|
| 828 | + |
| 829 | +#ifdef __POSIX__ |
| 830 | + registry->Register(Execve); |
| 831 | +#endif |
733 | 832 | registry->Register(Uptime);
|
734 | 833 | registry->Register(PatchProcessObject);
|
735 | 834 |
|
|
0 commit comments