This commit is contained in:
bryopsida 2025-02-27 10:06:53 -05:00 committed by GitHub
commit 21f3e159ba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 144 additions and 9 deletions

View File

@ -34,6 +34,8 @@ Data types
uv_gid_t gid; uv_gid_t gid;
char* cpumask; char* cpumask;
size_t cpumask_size; size_t cpumask_size;
uv_gid_t* gids;
size_t gids_size;
} uv_process_options_t; } uv_process_options_t;
.. c:type:: void (*uv_exit_cb)(uv_process_t*, int64_t exit_status, int term_signal) .. c:type:: void (*uv_exit_cb)(uv_process_t*, int64_t exit_status, int term_signal)
@ -94,7 +96,20 @@ Data types
* search for the exact file name before trying variants with * search for the exact file name before trying variants with
* extensions like '.exe' or '.cmd'. * extensions like '.exe' or '.cmd'.
*/ */
UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME = (1 << 7) UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME = (1 << 7),
/*
* Spawn the child process with the error mode of its parent.
* This option is only meaningful on Windows systems. On Unix
* it is silently ignored.
*/
UV_PROCESS_WINDOWS_USE_PARENT_ERROR_MODE = (1 << 8),
/*
* Set the child process' supplementary group ids. The group ids are supplied
* in the 'gids' field in the options struct, and the number of groups is
* specified in the 'num_gids' field. This does not work on windows;
* setting this flag will cause uv_spawn() to fail.
*/
UV_PROCESS_SETGROUPS = (1 << 9)
}; };
.. c:type:: uv_stdio_container_t .. c:type:: uv_stdio_container_t
@ -221,14 +236,18 @@ Public members
.. c:member:: uv_uid_t uv_process_options_t.uid .. c:member:: uv_uid_t uv_process_options_t.uid
.. c:member:: uv_gid_t uv_process_options_t.gid .. c:member:: uv_gid_t uv_process_options_t.gid
.. c:member:: uv_gid_t* uv_process_options_t.gids
.. c:member:: size_t uv_process_options_t.gids_size
Libuv can change the child process' user/group id. This happens only when Libuv can change the child process' user/group id and supplementary group
the appropriate bits are set in the flags fields. ids. This happens only when the appropriate bits are set in the flags fields.
.. note:: .. note::
This is not supported on Windows, :c:func:`uv_spawn` will fail and set the error This is not supported on Windows, :c:func:`uv_spawn` will fail and set the error
to ``UV_ENOTSUP``. to ``UV_ENOTSUP``.
.. versionadded:: 2.0.0
.. c:member:: char* uv_process_options_t.cpumask .. c:member:: char* uv_process_options_t.cpumask
.. c:member:: size_t uv_process_options_t.cpumask_size .. c:member:: size_t uv_process_options_t.cpumask_size

View File

@ -1131,9 +1131,10 @@ typedef struct uv_process_options_s {
int stdio_count; int stdio_count;
uv_stdio_container_t* stdio; uv_stdio_container_t* stdio;
/* /*
* Libuv can change the child process' user/group id. This happens only when * Libuv can change the child process' user/group id, and supplementarty
* the appropriate bits are set in the flags fields. This is not supported on * group ids. This happens only when the appropriate bits are set in the
* windows; uv_spawn() will fail and set the error to UV_ENOTSUP. * flags fields. This is not supported on windows; uv_spawn() will fail and
* set the error to UV_ENOTSUP.
*/ */
uv_uid_t uid; uv_uid_t uid;
uv_gid_t gid; uv_gid_t gid;
@ -1150,6 +1151,8 @@ typedef struct uv_process_options_s {
*/ */
char* cpumask; char* cpumask;
size_t cpumask_size; size_t cpumask_size;
uv_gid_t* gids;
size_t gids_size;
} uv_process_options_t; } uv_process_options_t;
/* /*
@ -1163,7 +1166,7 @@ enum uv_process_flags {
*/ */
UV_PROCESS_SETUID = (1 << 0), UV_PROCESS_SETUID = (1 << 0),
/* /*
* Set the child process' group id. The user id is supplied in the `gid` * Set the child process' group id. The group id is supplied in the `gid`
* field of the options struct. This does not work on windows; setting this * field of the options struct. This does not work on windows; setting this
* flag will cause uv_spawn() to fail. * flag will cause uv_spawn() to fail.
*/ */
@ -1211,7 +1214,14 @@ enum uv_process_flags {
* This option is only meaningful on Windows systems. On Unix * This option is only meaningful on Windows systems. On Unix
* it is silently ignored. * it is silently ignored.
*/ */
UV_PROCESS_WINDOWS_USE_PARENT_ERROR_MODE = (1 << 8) UV_PROCESS_WINDOWS_USE_PARENT_ERROR_MODE = (1 << 8),
/*
* Set the child process' supplementary group ids. The group ids are supplied
* in the 'gids' field in the options struct, and the number of groups is
* specified in the 'num_gids' field. This does not work on windows;
* setting this flag will cause uv_spawn() to fail on windows.
*/
UV_PROCESS_SETGROUPS = (1 << 9)
}; };
/* /*

View File

@ -395,6 +395,12 @@ static void uv__process_child_init(const uv_process_options_t* options,
SAVE_ERRNO(setgroups(0, NULL)); SAVE_ERRNO(setgroups(0, NULL));
} }
if (options->flags & UV_PROCESS_SETGROUPS) {
if (setgroups(options->gids_size, options->gids)) {
uv__write_errno(error_fd);
}
}
if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid))
uv__write_errno(error_fd); uv__write_errno(error_fd);
@ -1022,6 +1028,7 @@ int uv_spawn(uv_loop_t* loop,
assert(!(options->flags & ~(UV_PROCESS_DETACHED | assert(!(options->flags & ~(UV_PROCESS_DETACHED |
UV_PROCESS_SETGID | UV_PROCESS_SETGID |
UV_PROCESS_SETUID | UV_PROCESS_SETUID |
UV_PROCESS_SETGROUPS |
UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME | UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME |
UV_PROCESS_WINDOWS_HIDE | UV_PROCESS_WINDOWS_HIDE |
UV_PROCESS_WINDOWS_HIDE_CONSOLE | UV_PROCESS_WINDOWS_HIDE_CONSOLE |

View File

@ -899,7 +899,9 @@ int uv_spawn(uv_loop_t* loop,
process->exit_cb = options->exit_cb; process->exit_cb = options->exit_cb;
child_stdio_buffer = NULL; child_stdio_buffer = NULL;
if (options->flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) { if (options->flags & (UV_PROCESS_SETGID |
UV_PROCESS_SETUID |
UV_PROCESS_SETGROUPS)) {
return UV_ENOTSUP; return UV_ENOTSUP;
} }
@ -918,6 +920,7 @@ int uv_spawn(uv_loop_t* loop,
assert(!(options->flags & ~(UV_PROCESS_DETACHED | assert(!(options->flags & ~(UV_PROCESS_DETACHED |
UV_PROCESS_SETGID | UV_PROCESS_SETGID |
UV_PROCESS_SETUID | UV_PROCESS_SETUID |
UV_PROCESS_SETGROUPS |
UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME | UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME |
UV_PROCESS_WINDOWS_HIDE | UV_PROCESS_WINDOWS_HIDE |
UV_PROCESS_WINDOWS_HIDE_CONSOLE | UV_PROCESS_WINDOWS_HIDE_CONSOLE |

View File

@ -343,6 +343,7 @@ TEST_DECLARE (spawn_setuid_fails)
TEST_DECLARE (spawn_setgid_fails) TEST_DECLARE (spawn_setgid_fails)
TEST_DECLARE (spawn_affinity) TEST_DECLARE (spawn_affinity)
TEST_DECLARE (spawn_affinity_invalid_mask) TEST_DECLARE (spawn_affinity_invalid_mask)
TEST_DECLARE (spawn_setgids_fails)
TEST_DECLARE (spawn_stdout_to_file) TEST_DECLARE (spawn_stdout_to_file)
TEST_DECLARE (spawn_stdout_and_stderr_to_file) TEST_DECLARE (spawn_stdout_and_stderr_to_file)
TEST_DECLARE (spawn_stdout_and_stderr_to_file2) TEST_DECLARE (spawn_stdout_and_stderr_to_file2)
@ -541,6 +542,7 @@ TEST_DECLARE (win32_signum_number)
#else #else
TEST_DECLARE (emfile) TEST_DECLARE (emfile)
TEST_DECLARE (spawn_setuid_setgid) TEST_DECLARE (spawn_setuid_setgid)
TEST_DECLARE (spawn_setgids)
TEST_DECLARE (we_get_signal) TEST_DECLARE (we_get_signal)
TEST_DECLARE (we_get_signals) TEST_DECLARE (we_get_signals)
TEST_DECLARE (we_get_signal_one_shot) TEST_DECLARE (we_get_signal_one_shot)
@ -1039,6 +1041,7 @@ TASK_LIST_START
TEST_ENTRY (spawn_setgid_fails) TEST_ENTRY (spawn_setgid_fails)
TEST_ENTRY (spawn_affinity) TEST_ENTRY (spawn_affinity)
TEST_ENTRY (spawn_affinity_invalid_mask) TEST_ENTRY (spawn_affinity_invalid_mask)
TEST_ENTRY (spawn_setgids_fails)
TEST_ENTRY (spawn_stdout_to_file) TEST_ENTRY (spawn_stdout_to_file)
TEST_ENTRY (spawn_stdout_and_stderr_to_file) TEST_ENTRY (spawn_stdout_and_stderr_to_file)
TEST_ENTRY (spawn_stdout_and_stderr_to_file2) TEST_ENTRY (spawn_stdout_and_stderr_to_file2)
@ -1084,6 +1087,7 @@ TASK_LIST_START
#else #else
TEST_ENTRY (emfile) TEST_ENTRY (emfile)
TEST_ENTRY (spawn_setuid_setgid) TEST_ENTRY (spawn_setuid_setgid)
TEST_ENTRY (spawn_setgids)
TEST_ENTRY (we_get_signal) TEST_ENTRY (we_get_signal)
TEST_ENTRY (we_get_signals) TEST_ENTRY (we_get_signals)
TEST_ENTRY (we_get_signal_one_shot) TEST_ENTRY (we_get_signal_one_shot)

View File

@ -1498,6 +1498,44 @@ TEST_IMPL(spawn_setuid_setgid) {
} }
#endif #endif
#ifndef _WIN32
TEST_IMPL(spawn_setgids) {
int r;
struct passwd* pw;
uv_gid_t gids[1];
/* if not root, then this will fail. */
uv_uid_t uid = getuid();
if (uid != 0)
RETURN_SKIP("spawn_setgids skipped: not root\n");
init_process_options("spawn_helper1", exit_cb);
pw = getpwnam("nobody");
ASSERT(pw != NULL);
gids[0] = pw->pw_gid;
options.gids = gids;
options.gids_size = 1;
options.flags = UV_PROCESS_SETGROUPS;
r = uv_spawn(uv_default_loop(), &process, &options);
if (r == UV_EACCES)
RETURN_SKIP("user 'nobody' cannot access the test runner");
ASSERT(r == 0);
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT(r == 0);
ASSERT(exit_cb_called == 1);
ASSERT(close_cb_called == 1);
MAKE_VALGRIND_HAPPY(uv_default_loop());
return 0;
}
#endif
#ifndef _WIN32 #ifndef _WIN32
TEST_IMPL(spawn_setuid_fails) { TEST_IMPL(spawn_setuid_fails) {
@ -1594,6 +1632,39 @@ TEST_IMPL(spawn_setgid_fails) {
MAKE_VALGRIND_HAPPY(uv_default_loop()); MAKE_VALGRIND_HAPPY(uv_default_loop());
return 0; return 0;
} }
TEST_IMPL(spawn_setgids_fails) {
int r;
uv_gid_t gids[1] = {0};
/* if root, become nobody. */
uv_uid_t uid = getuid();
if (uid == 0) {
struct passwd* pw;
pw = getpwnam("nobody");
ASSERT(pw != NULL);
ASSERT(0 == setgid(pw->pw_gid));
ASSERT(0 == setuid(pw->pw_uid));
}
init_process_options("spawn_helper1", fail_cb);
options.flags |= UV_PROCESS_SETGROUPS;
options.gids = gids;
options.gids_size = 1;
r = uv_spawn(uv_default_loop(), &process, &options);
ASSERT(r == UV_EPERM);
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT(r == 0);
ASSERT(close_cb_called == 0);
MAKE_VALGRIND_HAPPY(uv_default_loop());
return 0;
}
#endif #endif
TEST_IMPL(spawn_affinity) { TEST_IMPL(spawn_affinity) {
@ -1757,6 +1828,27 @@ TEST_IMPL(spawn_setgid_fails) {
MAKE_VALGRIND_HAPPY(uv_default_loop()); MAKE_VALGRIND_HAPPY(uv_default_loop());
return 0; return 0;
} }
TEST_IMPL(spawn_setgids_fails) {
int r;
uv_gid_t gids[1] = {0};
init_process_options("spawn_helper1", exit_cb_unexpected);
options.flags |= UV_PROCESS_SETGROUPS;
options.gids = gids;
options.gids_size = 1;
r = uv_spawn(uv_default_loop(), &process, &options);
ASSERT_EQ(r, UV_ENOTSUP);
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT_OK(r);
ASSERT_OK(close_cb_called);
MAKE_VALGRIND_HAPPY(uv_default_loop());
return 0;
}
#endif #endif