/memcheck/tests/freebsd/capsicum
/memcheck/tests/freebsd/chflags
/memcheck/tests/freebsd/chmod_chown
+/memcheck/tests/freebsd/close_range
/memcheck/tests/freebsd/delete_sized_mismatch
/memcheck/tests/freebsd/errno_aligned_allocs
/memcheck/tests/freebsd/eventfd1
* ================== PLATFORM CHANGES =================
-* support has been added for FreeBSD 14 and FreeBSD 15.
+* Support has been added for FreeBSD 14 and FreeBSD 15.
+* Add support for the FreeBSD close_range system call.
* ==================== TOOL CHANGES ===================
DECL_TEMPLATE(freebsd, sys___realpathat) // 574
#endif
-// unimpl __NR_close_range 575
+DECL_TEMPLATE(freebsd, sys_close_range) // 575
#endif
}
}
-// SYS_sigfastblock
+// SYS_sigfastblock 573
// int sigfastblock(int cmd, void *ptr);
PRE(sys_sigfastblock)
{
PRE_MEM_WRITE("__realpathat(buf)", (Addr)ARG3, ARG4);
}
+// SYS_sys_close_range 575
+// int close_range(close_range(u_int lowfd, u_int highfd, int flags);
+PRE(sys_close_range)
+{
+ SysRes res = VG_(mk_SysRes_Success)(0);
+ unsigned int lowfd = ARG1;
+ unsigned int fd_counter; // will count from lowfd to highfd
+ unsigned int highfd = ARG2;
+
+ /* on linux the may lock if futexes are used
+ * there is a lock in the kernel but I assume it's just
+ * a spinlock */
+ PRINT("sys_close_range ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %"
+ FMT_REGWORD "d )", ARG1, ARG2, SARG3);
+ PRE_REG_READ3(int, "close_range",
+ unsigned int, lowfd, unsigned int, highfd,
+ int, flags);
+
+ if (lowfd > highfd) {
+ SET_STATUS_Failure( VKI_EINVAL );
+ return;
+ }
+
+ if (highfd >= VG_(fd_hard_limit))
+ highfd = VG_(fd_hard_limit) - 1;
+
+ if (lowfd > highfd) {
+ SET_STATUS_Success ( 0 );
+ return;
+ }
+
+ fd_counter = lowfd;
+ do {
+ if (fd_counter > highfd
+ || (fd_counter == 2U/*stderr*/ && VG_(debugLog_getLevel)() > 0)
+ || fd_counter == VG_(log_output_sink).fd
+ || fd_counter == VG_(xml_output_sink).fd) {
+ /* Split the range if it contains a file descriptor we're not
+ * supposed to close. */
+ if (fd_counter - 1 >= lowfd) {
+ res = VG_(do_syscall3)(__NR_close_range, (UWord)lowfd, (UWord)fd_counter - 1, ARG3 );
+ }
+ lowfd = fd_counter + 1;
+ }
+ } while (fd_counter++ <= highfd);
+
+ /* 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);
+}
+
POST(sys___realpathat)
{
POST_MEM_WRITE((Addr)ARG3, ARG4);
BSDX_(__NR_sigfastblock, sys_sigfastblock), // 573
BSDXY( __NR___realpathat, sys___realpathat), // 574
#endif
- // unimpl __NR_close_range 575
+ BSDXY(__NR_close_range, sys_close_range), // 575
#endif
#if (FREEBSD_VERS >= FREEBSD_13_0)
#define VKI_RFSPAWN (1U<<31U)
+#define VKI_CLOSE_RANGE_CLOEXEC (1<<2)
//----------------------------------------------------------------------
// From sys/msg.h
filter_scalar filter_realpathat filter_fstat filter_eventfd2
EXTRA_DIST = \
- scalar.h \
- statfs.vgtest \
- statfs.stderr.exp \
- pdfork_pdkill.vgtest \
- pdfork_pdkill.stderr.exp \
- getfsstat.vgtest \
- getfsstat.stderr.exp \
- getfsstat.supp \
- getfsstat.stderr.exp-x86 \
- supponlyobj.vgtest \
- supponlyobj.stderr.exp \
- supponlyobj.supp \
- extattr.vgtest \
- extattr.stderr.exp \
- sigwait.vgtest \
- sigwait.stdout.exp \
- sigwait.stderr.exp \
- sigwait.stderr.exp-x86 \
+ capsicum.vgtest \
+ capsicum.stderr.exp \
chflags.vgtest\
chflags.stderr.exp \
chflags.stderr.exp-x86 \
+ close_range.vgtest close_range.stderr.exp \
+ extattr.vgtest \
+ extattr.stderr.exp \
get_set_login.vgtest \
get_set_login.stderr.exp \
+ getfsstat.vgtest \
+ getfsstat.stderr.exp \
+ getfsstat.supp \
+ getfsstat.stderr.exp-x86 \
+ pdfork_pdkill.vgtest \
+ pdfork_pdkill.stderr.exp \
revoke.vgtest \
revoke.stderr.exp \
- scalar.vgtest \
+ scalar.h scalar.vgtest \
scalar.stderr.exp \
scalar.stderr.exp-x86 \
- capsicum.vgtest \
- capsicum.stderr.exp \
- getfh.vgtest \
- getfh.stderr.exp \
- linkat.vgtest \
- linkat.stderr.exp \
- scalar_fork.vgtest \
- scalar_fork.stderr.exp \
- scalar_thr_exit.vgtest \
- scalar_thr_exit.stderr.exp \
scalar_abort2.vgtest \
scalar_abort2.stderr.exp \
+ scalar_fork.vgtest \
+ scalar_fork.stderr.exp \
scalar_pdfork.vgtest \
scalar_pdfork.stderr.exp \
+ scalar_thr_exit.vgtest \
+ scalar_thr_exit.stderr.exp \
scalar_vfork.vgtest \
scalar_vfork.stderr.exp \
+ sigwait.vgtest \
+ sigwait.stdout.exp \
+ sigwait.stderr.exp \
+ sigwait.stderr.exp-x86 \
+ statfs.vgtest \
+ statfs.stderr.exp \
+ supponlyobj.vgtest \
+ supponlyobj.stderr.exp \
+ supponlyobj.supp \
+ getfh.vgtest \
+ getfh.stderr.exp \
+ linkat.vgtest \
+ linkat.stderr.exp \
stat.vgtest \
stat.stderr.exp \
stat.stderr.exp-x86 \
delete_sized_mismatch_xml.stderr.exp
check_PROGRAMS = \
- statfs pdfork_pdkill getfsstat inlinfo inlinfo_nested.so extattr \
+ close_range statfs pdfork_pdkill getfsstat inlinfo inlinfo_nested.so extattr \
sigwait chflags get_set_login revoke scalar capsicum getfh \
linkat scalar_fork scalar_thr_exit scalar_abort2 scalar_pdfork \
scalar_vfork stat file_locking_wait6 utimens access chmod_chown \
--- /dev/null
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <fcntl.h>
+#include <assert.h>
+
+int main(void)
+{
+ struct rlimit rl;
+ // I'm assuming opens start at 3 and get recycled
+ int fd1 = open("close_range.c", O_RDONLY);
+ int fd2 = open("close_range.vgtest", O_RDONLY);
+ int fd3 = open("close_range.stderr.exp", O_RDONLY);
+
+ // all open
+ close_range(fd1, fd3, 0);
+ // all closed
+ close_range(fd1, fd3, 0);
+
+ fd1 = open("close_range.c", O_RDONLY);
+ fd2 = open("close_range.vgtest", O_RDONLY);
+
+ // 3 and 4 open 5 closed
+ close_range(fd1, fd3, 0);
+
+ fd1 = open("close_range.c", O_RDONLY);
+ fd3 = open("close_range.stderr.exp", O_RDONLY);
+
+ // 3 and 5 open 4 closed
+ close_range(fd1, fd3, 0);
+
+ fd1 = open("close_range.c", O_RDONLY);
+ fd2 = open("close_range.vgtest", O_RDONLY);
+ fd3 = open("close_range.stderr.exp", O_RDONLY);
+
+ // good flag
+ close_range(fd1, fd3, CLOSE_RANGE_CLOEXEC);
+ close_range(fd1, fd3, 0);
+
+ fd1 = open("close_range.c", O_RDONLY);
+ fd2 = open("close_range.vgtest", O_RDONLY);
+ fd3 = open("close_range.stderr.exp", O_RDONLY);
+
+ errno = 0;
+ // bad flag
+ close_range(fd1, fd3, 2);
+ assert(errno = EINVAL);
+
+ errno = 0;
+ // wrong order
+ close_range(fd3, fd1, 2);
+ assert(errno = EINVAL);
+
+ errno = 0;
+ getrlimit(RLIMIT_NOFILE, &rl);
+
+ // should do nothing
+ close_range(rl.rlim_cur+100, rl.rlim_cur+200, 0);
+
+ close_range(3, rl.rlim_cur, 0);
+
+ fd1 = open("close_range.c", O_RDONLY);
+ fd2 = open("close_range.vgtest", O_RDONLY);
+ fd3 = open("close_range.stderr.exp", O_RDONLY);
+
+ close_range(3, rl.rlim_cur+1, 0);
+
+ {
+ unsigned a;
+ unsigned b;
+ int c;
+ close_range(a, b, c);
+ }
+}
+
--- /dev/null
+Syscall param close_range(lowfd) contains uninitialised byte(s)
+ at 0x........: close_range (in /...libc...)
+ by 0x........: main (close_range.c:74)
+
+Syscall param close_range(highfd) contains uninitialised byte(s)
+ at 0x........: close_range (in /...libc...)
+ by 0x........: main (close_range.c:74)
+
+Syscall param close_range(flags) contains uninitialised byte(s)
+ at 0x........: close_range (in /...libc...)
+ by 0x........: main (close_range.c:74)
+
--- /dev/null
+prog: close_range
+vgopts: -q
/* SYS___realpathat 574 */
GO(SYS___realpathat, " 5s 2m");
SY(SYS___realpathat, x0+0xffff, x0, x0, x0+100, x0+2); FAIL;
+
+ /* SYS_close_range 575 */
+ GO(SYS_close_range, "3s 0m");
+ SY(SYS_close_range, x0+5, x0+10, x0); SUCC;
/* SYS___specialfd 577 */
GO(SYS___specialfd, "3s 1m");
...
Address 0x........ is not stack'd, malloc'd or (recently) free'd
+---------------------------------------------------------
+575: SYS_close_range 3s 0m
+---------------------------------------------------------
+Syscall param close_range(lowfd) contains uninitialised byte(s)
+ ...
+
+Syscall param close_range(highfd) contains uninitialised byte(s)
+ ...
+
+Syscall param close_range(flags) contains uninitialised byte(s)
+ ...
+
---------------------------------------------------------
577: SYS___specialfd 3s 1m
---------------------------------------------------------