This is a system call introduced in Linux 5.9.
It's typically used to bulk-close file descriptors that a process inherited
without having desired so and doesn't want to pass them to its offspring
for security reasons. For this reason the sensible upper limit value tends
to be unknown and the users prefer to stay on the safe side by setting it
high.
This is a bit peculiar because, if unfiltered, the syscall could end up
closing descriptors Valgrind uses for its purposes, ending in no end of
mayhem and suffering.
This patch adjusts the upper bounds to a safe value and then skips over
the descriptor Valgrind uses by potentially calling the real system call
with sub-ranges that are safe to close.
The call can fail on negative ranges and bad flags -- we're dealing with
the first condition ourselves while letting the real call fail on bad
flags.
https://bugs.kde.org/show_bug.cgi?id=439090
have debug information
438871 unhandled instruction bytes: 0xF3 0x49 0xF 0x6F 0x9C 0x24 0x60 0x2 0x0 0x0
439046 valgrind is unusably large when linked with lld
+439090 Implement close_range(2)
439326 Valgrind 3.17.0 won't compile with Intel 2021 oneAPI compilers
439590 glibc-2.34 breaks suppressions against obj:*/lib*/libc-2.*so*
440670 unhandled ppc64le-linux syscall: 252 (statfs64) and 253 (fstatfs64)
DECL_TEMPLATE(linux, sys_io_uring_enter);
DECL_TEMPLATE(linux, sys_io_uring_register);
+// Linux-specific (new in Linux 5.9)
+DECL_TEMPLATE(linux, sys_close_range);
+
/* ---------------------------------------------------------------------
Wrappers for sockets and ipc-ery. These are split into standalone
procedures because x86-linux hides them inside multiplexors
LINXY(__NR_io_uring_register, sys_io_uring_register), // 427
GENX_(__NR_clone3, sys_ni_syscall), // 435
+ LINXY(__NR_close_range, sys_close_range), // 436
LINX_(__NR_faccessat2, sys_faccessat2), // 439
};
LINXY(__NR_io_uring_register, sys_io_uring_register), // 427
GENX_(__NR_clone3, sys_ni_syscall), // 435
+ LINXY(__NR_close_range, sys_close_range), // 436
LINX_(__NR_faccessat2, sys_faccessat2), // 439
};
LINXY(__NR_io_uring_register, sys_io_uring_register), // 427
GENX_(__NR_clone3, sys_ni_syscall), // 435
+ LINXY(__NR_close_range, sys_close_range), // 436
LINX_(__NR_faccessat2, sys_faccessat2), // 439
};
}
+PRE(sys_close_range)
+{
+ SysRes res = VG_(mk_SysRes_Success)(0);
+ unsigned int beg, end;
+ unsigned int last = ARG2;
+
+ FUSE_COMPATIBLE_MAY_BLOCK();
+ PRINT("sys_close_range ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %"
+ FMT_REGWORD "u )", ARG1, ARG2, ARG3);
+ PRE_REG_READ3(long, "close_range",
+ unsigned int, first, unsigned int, last,
+ unsigned int, flags);
+
+ if (ARG1 > last) {
+ SET_STATUS_Failure( VKI_EINVAL );
+ return;
+ }
+
+ if (last >= VG_(fd_hard_limit))
+ last = VG_(fd_hard_limit) - 1;
+
+ if (ARG1 > last) {
+ SET_STATUS_Success ( 0 );
+ return;
+ }
+
+ beg = end = ARG1;
+ do {
+ if (end > last
+ || (end == 2/*stderr*/ && VG_(debugLog_getLevel)() > 0)
+ || end == VG_(log_output_sink).fd
+ || end == VG_(xml_output_sink).fd) {
+ /* Split the range if it contains a file descriptor we're not
+ * supposed to close. */
+ if (end - 1 >= beg)
+ res = VG_(do_syscall3)(__NR_close_range, (UWord)beg, (UWord)end - 1, ARG3 );
+ beg = end + 1;
+ }
+ } while (end++ <= last);
+
+ /* If it failed along the way, it's presumably the flags being wrong. */
+ SET_STATUS_from_SysRes (res);
+}
+
+POST(sys_close_range)
+{
+ unsigned int fd;
+ unsigned int last = ARG2;
+
+ if (!VG_(clo_track_fds)
+ || (ARG3 & VKI_CLOSE_RANGE_CLOEXEC) != 0)
+ return;
+
+ if (last >= VG_(fd_hard_limit))
+ last = VG_(fd_hard_limit) - 1;
+
+ for (fd = ARG1; fd <= last; fd++)
+ if ((fd != 2/*stderr*/ || VG_(debugLog_getLevel)() == 0)
+ && fd != VG_(log_output_sink).fd
+ && fd != VG_(xml_output_sink).fd)
+ ML_(record_fd_close)(fd);
+}
#undef PRE
#undef POST
LINXY(__NR_io_uring_register, sys_io_uring_register), // 427
GENX_(__NR_clone3, sys_ni_syscall), // 435
+ LINXY(__NR_close_range, sys_close_range), // 436
LINX_ (__NR_faccessat2, sys_faccessat2), // 439
};
LINXY (__NR_io_uring_enter, sys_io_uring_enter),
LINXY (__NR_io_uring_register, sys_io_uring_register),
GENX_ (__NR_clone3, sys_ni_syscall),
+ LINXY (__NR_close_range, sys_close_range),
LINX_ (__NR_faccessat2, sys_faccessat2),
};
LINXY (__NR_io_uring_enter, sys_io_uring_enter),
LINXY (__NR_io_uring_register, sys_io_uring_register),
GENX_ (__NR_clone3, sys_ni_syscall),
+ LINXY (__NR_close_range, sys_close_range),
LINX_ (__NR_faccessat2, sys_faccessat2),
};
LINXY(__NR_io_uring_register, sys_io_uring_register), // 427
GENX_(__NR_clone3, sys_ni_syscall), // 435
+ LINXY(__NR_close_range, sys_close_range), // 436
LINX_(__NR_faccessat2, sys_faccessat2), // 439
};
LINXY(__NR_io_uring_register, sys_io_uring_register), // 427
GENX_(__NR_clone3, sys_ni_syscall), // 435
+ LINXY(__NR_close_range, sys_close_range), // 436
LINX_(__NR_faccessat2, sys_faccessat2), // 439
};
LINXY(__NR_io_uring_register, sys_io_uring_register), // 427
GENX_(__NR_clone3, sys_ni_syscall), // 435
+ LINXY(__NR_close_range, sys_close_range), // 436
LINX_(__NR_faccessat2, sys_faccessat2), // 439
};
LINXY(__NR_io_uring_register, sys_io_uring_register),// 427
GENX_(__NR_clone3, sys_ni_syscall), // 435
+ LINXY(__NR_close_range, sys_close_range), // 436
LINX_(__NR_faccessat2, sys_faccessat2), // 439
};
#define VKI_RLIM64_INFINITY (~0ULL)
+#define VKI_CLOSE_RANGE_UNSHARE (1U << 1)
+#define VKI_CLOSE_RANGE_CLOEXEC (1U << 2)
+
/*--------------------------------------------------------------------*/
/*--- end ---*/
/*--------------------------------------------------------------------*/
#define __NR_fspick 433
#define __NR_clone3 435
+#define __NR_close_range 436
#define __NR_faccessat2 439