From 52a20dc78a372394471e3394a8d335ef00cebad3 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Tue, 7 Nov 2017 15:33:40 -0500 Subject: [PATCH] Fix: liblttng-ust-fd.so: override fclose symbol fclose() invoked from application or libraries end up calling close() from within the libc, which bypasses our file descriptor tracking. Signed-off-by: Mathieu Desnoyers --- include/ust-fd.h | 3 +++ liblttng-ust-comm/lttng-ust-fd-tracker.c | 32 ++++++++++++++++++++++++ liblttng-ust-fd/lttng-ust-fd.c | 25 ++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/include/ust-fd.h b/include/ust-fd.h index 7cbcf47c..032cac53 100644 --- a/include/ust-fd.h +++ b/include/ust-fd.h @@ -24,6 +24,8 @@ * These declarations should NOT be considered stable API. */ +#include + void lttng_ust_init_fd_tracker(void); void lttng_ust_add_fd_to_tracker(int fd); void lttng_ust_delete_fd_from_tracker(int fd); @@ -31,6 +33,7 @@ void lttng_ust_lock_fd_tracker(void); void lttng_ust_unlock_fd_tracker(void); int lttng_ust_safe_close_fd(int fd, int (*close_cb)(int)); +int lttng_ust_safe_fclose_stream(FILE *stream, int (*fclose_cb)(FILE *stream)); int lttng_ust_safe_closefrom_fd(int lowfd, int (*close_cb)(int)); #endif /* _LTTNG_UST_FD_H */ diff --git a/liblttng-ust-comm/lttng-ust-fd-tracker.c b/liblttng-ust-comm/lttng-ust-fd-tracker.c index 5a763ff2..d56288e3 100644 --- a/liblttng-ust-comm/lttng-ust-fd-tracker.c +++ b/liblttng-ust-comm/lttng-ust-fd-tracker.c @@ -197,6 +197,38 @@ int lttng_ust_safe_close_fd(int fd, int (*close_cb)(int fd)) return ret; } +/* + * Interface allowing applications to close arbitrary streams. + * We check if it is owned by lttng-ust, and return -1, errno=EBADF + * instead of closing it if it is the case. + */ +int lttng_ust_safe_fclose_stream(FILE *stream, int (*fclose_cb)(FILE *stream)) +{ + int ret = 0, fd; + + lttng_ust_fixup_fd_tracker_tls(); + + /* + * If called from lttng-ust, we directly call fclose without + * validating whether the FD is part of the tracked set. + */ + if (URCU_TLS(thread_fd_tracking)) + return fclose_cb(stream); + + fd = fileno(stream); + + lttng_ust_lock_fd_tracker(); + if (IS_FD_VALID(fd) && IS_FD_SET(fd, lttng_fd_set)) { + ret = -1; + errno = EBADF; + } else { + ret = fclose_cb(stream); + } + lttng_ust_unlock_fd_tracker(); + + return ret; +} + #ifdef __OpenBSD__ static void set_close_success(int *p) { diff --git a/liblttng-ust-fd/lttng-ust-fd.c b/liblttng-ust-fd/lttng-ust-fd.c index 6a095db6..863f0618 100644 --- a/liblttng-ust-fd/lttng-ust-fd.c +++ b/liblttng-ust-fd/lttng-ust-fd.c @@ -31,6 +31,7 @@ volatile enum ust_loglevel ust_loglevel; static int (*__lttng_ust_fd_plibc_close)(int fd); +static int (*__lttng_ust_fd_plibc_fclose)(FILE *stream); static int _lttng_ust_fd_libc_close(int fd) @@ -45,11 +46,35 @@ int _lttng_ust_fd_libc_close(int fd) return lttng_ust_safe_close_fd(fd, __lttng_ust_fd_plibc_close); } +static +int _lttng_ust_fd_libc_fclose(FILE *stream) +{ + if (!__lttng_ust_fd_plibc_fclose) { + __lttng_ust_fd_plibc_fclose = dlsym(RTLD_NEXT, "fclose"); + if (!__lttng_ust_fd_plibc_fclose) { + fprintf(stderr, "%s\n", dlerror()); + return -1; + } + } + return lttng_ust_safe_fclose_stream(stream, + __lttng_ust_fd_plibc_fclose); +} + int close(int fd) { return _lttng_ust_fd_libc_close(fd); } +/* + * Note: fcloseall() is not an issue because it fcloses only the + * streams it knows about, which differs from the problems caused by + * gnulib close_stdout(), which does an explicit fclose(stdout). + */ +int fclose(FILE *stream) +{ + return _lttng_ust_fd_libc_fclose(stream); +} + #if defined(__sun__) || defined(__FreeBSD__) /* Solaris and FreeBSD. */ void closefrom(int lowfd) -- 2.34.1