|
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 {
|
@@ -471,6 +473,95 @@ static void ReallyExit(const FunctionCallbackInfo<Value>& args) {
|
471 | 473 | env->Exit(code);
|
472 | 474 | }
|
473 | 475 |
|
| 476 | +#ifdef __POSIX__ |
| 477 | +inline int persist_standard_stream(int fd) { |
| 478 | + int flags = fcntl(fd, F_GETFD, 0); |
| 479 | + |
| 480 | + if (flags < 0) { |
| 481 | + return flags; |
| 482 | + } |
| 483 | + |
| 484 | + flags &= ~FD_CLOEXEC; |
| 485 | + return fcntl(fd, F_SETFD, flags); |
| 486 | +} |
| 487 | + |
| 488 | +static void Execve(const FunctionCallbackInfo<Value>& args) { |
| 489 | + Environment* env = Environment::GetCurrent(args); |
| 490 | + Isolate* isolate = env->isolate(); |
| 491 | + Local<Context> context = env->context(); |
| 492 | + |
| 493 | + THROW_IF_INSUFFICIENT_PERMISSIONS( |
| 494 | + env, permission::PermissionScope::kChildProcess, ""); |
| 495 | + |
| 496 | + CHECK(args[0]->IsString()); |
| 497 | + CHECK(args[1]->IsArray()); |
| 498 | + CHECK(args[2]->IsArray()); |
| 499 | + |
| 500 | + Local<Array> argv_array = args[1].As<Array>(); |
| 501 | + Local<Array> envp_array = args[2].As<Array>(); |
| 502 | + |
| 503 | + // Copy arguments and environment |
| 504 | + Utf8Value executable(isolate, args[0]); |
| 505 | + std::vector<std::string> argv_strings(argv_array->Length()); |
| 506 | + std::vector<std::string> envp_strings(envp_array->Length()); |
| 507 | + std::vector<char*> argv(argv_array->Length() + 1); |
| 508 | + std::vector<char*> envp(envp_array->Length() + 1); |
| 509 | + |
| 510 | + for (unsigned int i = 0; i < argv_array->Length(); i++) { |
| 511 | + Local<Value> str; |
| 512 | + if (!argv_array->Get(context, i).ToLocal(&str)) { |
| 513 | + THROW_ERR_INVALID_ARG_VALUE(env, "Failed to deserialize argument."); |
| 514 | + return; |
| 515 | + } |
| 516 | + |
| 517 | + argv_strings[i] = Utf8Value(isolate, str).ToString(); |
| 518 | + argv[i] = argv_strings[i].data(); |
| 519 | + } |
| 520 | + argv[argv_array->Length()] = nullptr; |
| 521 | + |
| 522 | + for (unsigned int i = 0; i < envp_array->Length(); i++) { |
| 523 | + Local<Value> str; |
| 524 | + if (!envp_array->Get(context, i).ToLocal(&str)) { |
| 525 | + THROW_ERR_INVALID_ARG_VALUE( |
| 526 | + env, "Failed to deserialize environment variable."); |
| 527 | + return; |
| 528 | + } |
| 529 | + |
| 530 | + envp_strings[i] = Utf8Value(isolate, str).ToString(); |
| 531 | + envp[i] = envp_strings[i].data(); |
| 532 | + } |
| 533 | + |
| 534 | + envp[envp_array->Length()] = nullptr; |
| 535 | + |
| 536 | + // Set stdin, stdout and stderr to be non-close-on-exec |
| 537 | + // so that the new process will inherit it. |
| 538 | + if (persist_standard_stream(0) < 0 || persist_standard_stream(1) < 0 || |
| 539 | + persist_standard_stream(2) < 0) { |
| 540 | + env->ThrowErrnoException(errno, "fcntl"); |
| 541 | + return; |
| 542 | + } |
| 543 | + |
| 544 | + // Perform the execve operation. |
| 545 | + RunAtExit(env); |
| 546 | + execve(*executable, argv.data(), envp.data()); |
| 547 | + |
| 548 | + // If it returns, it means that the execve operation failed. |
| 549 | + // In that case we abort the process. |
| 550 | + auto error_message = std::string("process.execve failed with error code ") + |
| 551 | + errors::errno_string(errno); |
| 552 | + |
| 553 | + // Abort the process |
| 554 | + Local<v8::Value> exception = |
| 555 | + ErrnoException(isolate, errno, "execve", *executable); |
| 556 | + Local<v8::Message> message = v8::Exception::CreateMessage(isolate, exception); |
| 557 | + |
| 558 | + std::string info = FormatErrorMessage( |
| 559 | + isolate, context, error_message.c_str(), message, true); |
| 560 | + FPrintF(stderr, "%s\n", info); |
| 561 | + ABORT(); |
| 562 | +} |
| 563 | +#endif |
| 564 | + |
474 | 565 | static void LoadEnvFile(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
475 | 566 | Environment* env = Environment::GetCurrent(args);
|
476 | 567 | std::string path = ".env";
|
@@ -662,6 +753,10 @@ static void CreatePerIsolateProperties(IsolateData* isolate_data,
|
662 | 753 | SetMethodNoSideEffect(isolate, target, "cwd", Cwd);
|
663 | 754 | SetMethod(isolate, target, "dlopen", binding::DLOpen);
|
664 | 755 | SetMethod(isolate, target, "reallyExit", ReallyExit);
|
| 756 | + |
| 757 | +#ifdef __POSIX__ |
| 758 | + SetMethod(isolate, target, "execve", Execve); |
| 759 | +#endif |
665 | 760 | SetMethodNoSideEffect(isolate, target, "uptime", Uptime);
|
666 | 761 | SetMethod(isolate, target, "patchProcessObject", PatchProcessObject);
|
667 | 762 |
|
@@ -704,6 +799,10 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
|
704 | 799 | registry->Register(Cwd);
|
705 | 800 | registry->Register(binding::DLOpen);
|
706 | 801 | registry->Register(ReallyExit);
|
| 802 | + |
| 803 | +#ifdef __POSIX__ |
| 804 | + registry->Register(Execve); |
| 805 | +#endif |
707 | 806 | registry->Register(Uptime);
|
708 | 807 | registry->Register(PatchProcessObject);
|
709 | 808 |
|
|
0 commit comments