Add close_range wrapper to liblttng-ust-fd.so
[lttng-ust.git] / src / lib / lttng-ust-fd / lttng-ust-fd.c
index d2ebcfbc38be862b6effffdc490f7a7d0ce968cb..0360b6f269a85eca5db049bacf258492b7c97249 100644 (file)
@@ -21,6 +21,8 @@
 
 static int (*__lttng_ust_fd_plibc_close)(int fd) = NULL;
 static int (*__lttng_ust_fd_plibc_fclose)(FILE *stream) = NULL;
+static int (*__lttng_ust_fd_plibc_close_range)(unsigned int first,
+               unsigned int last, int flags) = NULL;
 
 /*
  * Use dlsym to find the original libc close() symbol and store it in
@@ -60,6 +62,24 @@ void *_lttng_ust_fd_init_plibc_fclose(void)
        return __lttng_ust_fd_plibc_fclose;
 }
 
+/*
+ * Use dlsym to find the original libc close_range() symbol and store it
+ * in __lttng_ust_fd_plibc_close_range. The close_range symbol only
+ * appears in glibc 2.34, so it is considered optional.
+ */
+static
+void *_lttng_ust_fd_init_plibc_close_range(void)
+{
+       if (__lttng_ust_fd_plibc_close_range == NULL) {
+               __lttng_ust_fd_plibc_close_range = dlsym(RTLD_NEXT, "close_range");
+
+               if (__lttng_ust_fd_plibc_close_range == NULL)
+                       __lttng_ust_fd_plibc_close_range = (void *) LTTNG_UST_DLSYM_FAILED_PTR;
+       }
+
+       return __lttng_ust_fd_plibc_close_range;
+}
+
 static
 void _lttng_ust_fd_ctor(void)
        __attribute__((constructor));
@@ -75,6 +95,7 @@ void _lttng_ust_fd_ctor(void)
         */
        (void) _lttng_ust_fd_init_plibc_close();
        (void) _lttng_ust_fd_init_plibc_fclose();
+       (void) _lttng_ust_fd_init_plibc_close_range();
 }
 
 /*
@@ -127,6 +148,30 @@ int fclose(FILE *stream)
                        __lttng_ust_fd_plibc_fclose);
 }
 
+/*
+ * Override the libc close_range() symbol with our own, allowing
+ * applications to close arbitrary file descriptors. If the fd is owned
+ * by lttng-ust, return -1, errno=EBADF instead of closing it.
+ *
+ * If dlsym failed to find the original libc close_range() symbol,
+ * return -1, errno=ENOSYS.
+ *
+ * There is a short window before the library constructor has executed where
+ * this wrapper could call dlsym() and thus not be async-signal-safe.
+ */
+int close_range(unsigned int first, unsigned int last, int flags)
+{
+       /*
+        * We can't retry dlsym here since close is async-signal-safe.
+        */
+       if (_lttng_ust_fd_init_plibc_close_range() == (void *) LTTNG_UST_DLSYM_FAILED_PTR) {
+               errno = ENOSYS;
+               return -1;
+       }
+
+       return lttng_ust_safe_close_range_fd(first, last, flags, __lttng_ust_fd_plibc_close_range);
+}
+
 #if defined(__sun__) || defined(__FreeBSD__)
 /* Solaris and FreeBSD. */
 void closefrom(int lowfd)
This page took 0.023726 seconds and 4 git commands to generate.