11#include " env-inl.h"
2+ #include " node_errors.h"
23#include " node_external_reference.h"
34#include " node_internals.h"
45#include " util-inl.h"
1213#include < unistd.h> // setuid, getuid
1314#endif
1415#ifdef __linux__
16+ #include < dlfcn.h> // dlsym()
1517#include < linux/capability.h>
1618#include < sys/auxv.h>
1719#include < sys/syscall.h>
@@ -231,6 +233,45 @@ static gid_t gid_by_name(Isolate* isolate, Local<Value> value) {
231233 }
232234}
233235
236+ #ifdef __linux__
237+ extern " C" {
238+ int uv__node_patch_is_using_io_uring (void );
239+
240+ int uv__node_patch_is_using_io_uring (void ) __attribute__((weak));
241+
242+ typedef int (*is_using_io_uring_fn)(void );
243+ }
244+ #endif // __linux__
245+
246+ static bool UvMightBeUsingIoUring () {
247+ #ifdef __linux__
248+ // Support for io_uring is only included in libuv 1.45.0 and later, and only
249+ // on Linux (and Android, but there it is always disabled). The patch that we
250+ // apply to libuv to work around the io_uring security issue adds a function
251+ // that tells us whether io_uring is being used. If that function is not
252+ // present, we assume that we are dynamically linking against an unpatched
253+ // version.
254+ static std::atomic<is_using_io_uring_fn> check =
255+ uv__node_patch_is_using_io_uring;
256+ if (check == nullptr ) {
257+ check = reinterpret_cast <is_using_io_uring_fn>(
258+ dlsym (RTLD_DEFAULT, " uv__node_patch_is_using_io_uring" ));
259+ }
260+ return uv_version () >= 0x012d00u && (check == nullptr || (*check)());
261+ #else
262+ return false ;
263+ #endif
264+ }
265+
266+ static bool ThrowIfUvMightBeUsingIoUring (Environment* env, const char * fn) {
267+ if (UvMightBeUsingIoUring ()) {
268+ node::THROW_ERR_INVALID_STATE (
269+ env, " %s() disabled: io_uring may be enabled. See CVE-2024-22017." , fn);
270+ return true ;
271+ }
272+ return false ;
273+ }
274+
234275static void GetUid (const FunctionCallbackInfo<Value>& args) {
235276 Environment* env = Environment::GetCurrent (args);
236277 CHECK (env->has_run_bootstrapping_code ());
@@ -266,6 +307,8 @@ static void SetGid(const FunctionCallbackInfo<Value>& args) {
266307 CHECK_EQ (args.Length (), 1 );
267308 CHECK (args[0 ]->IsUint32 () || args[0 ]->IsString ());
268309
310+ if (ThrowIfUvMightBeUsingIoUring (env, " setgid" )) return ;
311+
269312 gid_t gid = gid_by_name (env->isolate (), args[0 ]);
270313
271314 if (gid == gid_not_found) {
@@ -285,6 +328,8 @@ static void SetEGid(const FunctionCallbackInfo<Value>& args) {
285328 CHECK_EQ (args.Length (), 1 );
286329 CHECK (args[0 ]->IsUint32 () || args[0 ]->IsString ());
287330
331+ if (ThrowIfUvMightBeUsingIoUring (env, " setegid" )) return ;
332+
288333 gid_t gid = gid_by_name (env->isolate (), args[0 ]);
289334
290335 if (gid == gid_not_found) {
@@ -304,6 +349,8 @@ static void SetUid(const FunctionCallbackInfo<Value>& args) {
304349 CHECK_EQ (args.Length (), 1 );
305350 CHECK (args[0 ]->IsUint32 () || args[0 ]->IsString ());
306351
352+ if (ThrowIfUvMightBeUsingIoUring (env, " setuid" )) return ;
353+
307354 uid_t uid = uid_by_name (env->isolate (), args[0 ]);
308355
309356 if (uid == uid_not_found) {
@@ -323,6 +370,8 @@ static void SetEUid(const FunctionCallbackInfo<Value>& args) {
323370 CHECK_EQ (args.Length (), 1 );
324371 CHECK (args[0 ]->IsUint32 () || args[0 ]->IsString ());
325372
373+ if (ThrowIfUvMightBeUsingIoUring (env, " seteuid" )) return ;
374+
326375 uid_t uid = uid_by_name (env->isolate (), args[0 ]);
327376
328377 if (uid == uid_not_found) {
@@ -363,6 +412,8 @@ static void SetGroups(const FunctionCallbackInfo<Value>& args) {
363412 CHECK_EQ (args.Length (), 1 );
364413 CHECK (args[0 ]->IsArray ());
365414
415+ if (ThrowIfUvMightBeUsingIoUring (env, " setgroups" )) return ;
416+
366417 Local<Array> groups_list = args[0 ].As <Array>();
367418 size_t size = groups_list->Length ();
368419 MaybeStackBuffer<gid_t , 64 > groups (size);
@@ -394,6 +445,8 @@ static void InitGroups(const FunctionCallbackInfo<Value>& args) {
394445 CHECK (args[0 ]->IsUint32 () || args[0 ]->IsString ());
395446 CHECK (args[1 ]->IsUint32 () || args[1 ]->IsString ());
396447
448+ if (ThrowIfUvMightBeUsingIoUring (env, " initgroups" )) return ;
449+
397450 Utf8Value arg0 (env->isolate (), args[0 ]);
398451 gid_t extra_group;
399452 bool must_free;
0 commit comments