2 * SPDX-License-Identifier: LGPL-2.1-only
4 * Copyright (C) 2016 Aravind HT <aravind.ht@gmail.com>
5 * Copyright (C) 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
12 #include <sys/types.h>
17 #include <sys/select.h>
18 #include <sys/resource.h>
25 #include <urcu/compiler.h>
26 #include <urcu/tls-compat.h>
27 #include <urcu/system.h>
29 #include "common/ust-fd.h"
30 #include "common/macros.h"
31 #include <lttng/ust-error.h>
32 #include <lttng/ust-cancelstate.h>
33 #include "common/logging.h"
35 #include "lib/lttng-ust-common/fd-tracker.h"
37 /* Operations on the fd set. */
38 #define IS_FD_VALID(fd) ((fd) >= 0 && (fd) < lttng_ust_max_fd)
39 #define GET_FD_SET_FOR_FD(fd, fd_sets) (&((fd_sets)[(fd) / FD_SETSIZE]))
40 #define CALC_INDEX_TO_SET(fd) ((fd) % FD_SETSIZE)
41 #define IS_FD_STD(fd) (IS_FD_VALID(fd) && (fd) <= STDERR_FILENO)
43 /* Check fd validity before calling these. */
44 #define ADD_FD_TO_SET(fd, fd_sets) \
45 FD_SET(CALC_INDEX_TO_SET(fd), GET_FD_SET_FOR_FD(fd, fd_sets))
46 #define IS_FD_SET(fd, fd_sets) \
47 FD_ISSET(CALC_INDEX_TO_SET(fd), GET_FD_SET_FOR_FD(fd, fd_sets))
48 #define DEL_FD_FROM_SET(fd, fd_sets) \
49 FD_CLR(CALC_INDEX_TO_SET(fd), GET_FD_SET_FOR_FD(fd, fd_sets))
52 * Protect the lttng_fd_set. Nests within the ust_lock, and therefore
53 * within the libc dl lock. Therefore, we need to allocate the TLS before
54 * nesting into this lock.
56 * The ust_safe_guard_fd_mutex nests within the ust_mutex. This mutex
57 * is also held across fork.
59 static pthread_mutex_t ust_safe_guard_fd_mutex
= PTHREAD_MUTEX_INITIALIZER
;
62 * Track whether we are within lttng-ust or application, for close
63 * system call override by LD_PRELOAD library. This also tracks whether
64 * we are invoking close() from a signal handler nested on an
67 static DEFINE_URCU_TLS(int, ust_fd_mutex_nest
);
69 /* fd_set used to book keep fd being used by lttng-ust. */
70 static fd_set
*lttng_fd_set
;
71 static int lttng_ust_max_fd
;
72 static int num_fd_sets
;
76 * Force a read (imply TLS allocation for dlopen) of TLS variables.
78 void lttng_ust_fd_tracker_alloc_tls(void)
80 asm volatile ("" : : "m" (URCU_TLS(ust_fd_mutex_nest
)));
84 * Allocate the fd set array based on the hard limit set for this
85 * process. This will be called during the constructor execution
86 * and will also be called in the child after fork via lttng_ust_init.
88 void lttng_ust_fd_tracker_init(void)
93 if (CMM_LOAD_SHARED(init_done
))
96 memset(&rlim
, 0, sizeof(rlim
));
97 /* Get the current possible max number of fd for this process. */
98 if (getrlimit(RLIMIT_NOFILE
, &rlim
) < 0)
101 * FD set array size determined using the hard limit. Even if
102 * the process wishes to increase its limit using setrlimit, it
103 * can only do so with the softlimit which will be less than the
106 lttng_ust_max_fd
= rlim
.rlim_max
;
107 num_fd_sets
= lttng_ust_max_fd
/ FD_SETSIZE
;
108 if (lttng_ust_max_fd
% FD_SETSIZE
)
110 if (lttng_fd_set
!= NULL
) {
114 lttng_fd_set
= malloc(num_fd_sets
* (sizeof(fd_set
)));
117 for (i
= 0; i
< num_fd_sets
; i
++)
118 FD_ZERO((<tng_fd_set
[i
]));
119 CMM_STORE_SHARED(init_done
, 1);
122 static void lttng_ust_lock_fd_tracker_orig(void)
124 sigset_t sig_all_blocked
, orig_mask
;
127 if (lttng_ust_cancelstate_disable_push()) {
128 ERR("lttng_ust_cancelstate_disable_push");
130 sigfillset(&sig_all_blocked
);
131 ret
= pthread_sigmask(SIG_SETMASK
, &sig_all_blocked
, &orig_mask
);
133 ERR("pthread_sigmask: %s", strerror(ret
));
135 if (!URCU_TLS(ust_fd_mutex_nest
)++) {
137 * Ensure the compiler don't move the store after the close()
138 * call in case close() would be marked as leaf.
141 pthread_mutex_lock(&ust_safe_guard_fd_mutex
);
143 ret
= pthread_sigmask(SIG_SETMASK
, &orig_mask
, NULL
);
145 ERR("pthread_sigmask: %s", strerror(ret
));
149 static void lttng_ust_unlock_fd_tracker_orig(void)
151 sigset_t sig_all_blocked
, orig_mask
;
154 sigfillset(&sig_all_blocked
);
155 ret
= pthread_sigmask(SIG_SETMASK
, &sig_all_blocked
, &orig_mask
);
157 ERR("pthread_sigmask: %s", strerror(ret
));
160 * Ensure the compiler don't move the store before the close()
161 * call, in case close() would be marked as leaf.
164 if (!--URCU_TLS(ust_fd_mutex_nest
)) {
165 pthread_mutex_unlock(&ust_safe_guard_fd_mutex
);
167 ret
= pthread_sigmask(SIG_SETMASK
, &orig_mask
, NULL
);
169 ERR("pthread_sigmask: %s", strerror(ret
));
171 if (lttng_ust_cancelstate_disable_pop()) {
172 ERR("lttng_ust_cancelstate_disable_pop");
176 static int dup_std_fd(int fd
)
179 int fd_to_close
[STDERR_FILENO
+ 1];
180 int fd_to_close_count
= 0;
181 int dup_cmd
= F_DUPFD
; /* Default command */
184 if (!(IS_FD_STD(fd
))) {
185 /* Should not be here */
190 /* Check for FD_CLOEXEC flag */
191 ret
= fcntl(fd
, F_GETFD
);
193 PERROR("fcntl on f_getfd");
198 if (ret
& FD_CLOEXEC
) {
199 dup_cmd
= F_DUPFD_CLOEXEC
;
203 for (i
= 0; i
< STDERR_FILENO
+ 1; i
++) {
204 ret
= fcntl(fd
, dup_cmd
, 0);
206 PERROR("fcntl dup fd");
210 if (!(IS_FD_STD(ret
))) {
211 /* fd is outside of STD range, use it. */
213 /* Close fd received as argument. */
219 fd_to_close
[i
] = ret
;
223 /* Close intermediary fds */
224 for (i
= 0; i
< fd_to_close_count
; i
++) {
225 ret
= close(fd_to_close
[i
]);
227 PERROR("close on temporary fd: %d.", fd_to_close
[i
]);
229 * Not using an abort here would yield a complicated
230 * error handling for the caller. If a failure occurs
231 * here, the system is already in a bad state.
243 * Needs to be called with ust_safe_guard_fd_mutex held when opening the fd.
244 * Has strict checking of fd validity.
246 * If fd <= 2, dup the fd until fd > 2. This enables us to bypass
247 * problems that can be encountered if UST uses stdin, stdout, stderr
248 * fds for internal use (daemon etc.). This can happen if the
249 * application closes either of those file descriptors. Intermediary fds
250 * are closed as needed.
252 * Return -1 on error.
255 static int lttng_ust_add_fd_to_tracker_orig(int fd
)
259 * Ensure the tracker is initialized when called from
262 lttng_ust_fd_tracker_init();
263 assert(URCU_TLS(ust_fd_mutex_nest
));
266 ret
= dup_std_fd(fd
);
273 /* Trying to add an fd which we can not accommodate. */
274 assert(IS_FD_VALID(fd
));
275 /* Setting an fd thats already set. */
276 assert(!IS_FD_SET(fd
, lttng_fd_set
));
278 ADD_FD_TO_SET(fd
, lttng_fd_set
);
285 * Needs to be called with ust_safe_guard_fd_mutex held when opening the fd.
286 * Has strict checking for fd validity.
288 static void lttng_ust_delete_fd_from_tracker_orig(int fd
)
291 * Ensure the tracker is initialized when called from
294 lttng_ust_fd_tracker_init();
296 assert(URCU_TLS(ust_fd_mutex_nest
));
297 /* Not a valid fd. */
298 assert(IS_FD_VALID(fd
));
299 /* Deleting an fd which was not set. */
300 assert(IS_FD_SET(fd
, lttng_fd_set
));
302 DEL_FD_FROM_SET(fd
, lttng_fd_set
);
305 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
306 static int (*__lttng_ust_safe_close_fd
)(int fd
, int (*close_cb
)(int fd
)) = NULL
;
309 void *_init_lttng_ust_safe_close_fd(void)
311 if (__lttng_ust_safe_close_fd
== NULL
) {
312 __lttng_ust_safe_close_fd
= dlsym(RTLD_DEFAULT
, "lttng_ust_safe_close_fd");
314 if (__lttng_ust_safe_close_fd
== NULL
) {
315 fprintf(stderr
, "%s\n", dlerror());
319 return __lttng_ust_safe_close_fd
;
322 static int lttng_ust_safe_close_fd_chain(int fd
, int (*close_cb
)(int fd
))
324 if (_init_lttng_ust_safe_close_fd()) {
325 /* Chain on ust-2.12 preload */
326 return __lttng_ust_safe_close_fd(fd
, close_cb
);
328 /* Fallback to libc symbol */
335 * Interface allowing applications to close arbitrary file descriptors.
336 * We check if it is owned by lttng-ust, and return -1, errno=EBADF
337 * instead of closing it if it is the case.
339 static int lttng_ust_safe_close_fd_orig(int fd
, int (*close_cb
)(int fd
))
343 lttng_ust_fd_tracker_alloc_tls();
346 * Ensure the tracker is initialized when called from
349 lttng_ust_fd_tracker_init();
352 * If called from lttng-ust, we directly call close without
353 * validating whether the FD is part of the tracked set.
355 if (URCU_TLS(ust_fd_mutex_nest
)) {
356 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
357 return lttng_ust_safe_close_fd_chain(fd
, close_cb
);
363 lttng_ust_lock_fd_tracker();
364 if (IS_FD_VALID(fd
) && IS_FD_SET(fd
, lttng_fd_set
)) {
368 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
369 ret
= lttng_ust_safe_close_fd_chain(fd
, close_cb
);
374 lttng_ust_unlock_fd_tracker();
379 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
380 static int (*__lttng_ust_safe_fclose_stream
)(FILE *stream
, int (*fclose_cb
)(FILE *stream
)) = NULL
;
383 void *_init_lttng_ust_safe_fclose_stream(void)
385 if (__lttng_ust_safe_fclose_stream
== NULL
) {
386 __lttng_ust_safe_fclose_stream
= dlsym(RTLD_DEFAULT
, "lttng_ust_safe_fclose_stream");
388 if (__lttng_ust_safe_fclose_stream
== NULL
) {
389 fprintf(stderr
, "%s\n", dlerror());
393 return __lttng_ust_safe_fclose_stream
;
396 static int lttng_ust_safe_fclose_stream_chain(FILE *stream
, int (*fclose_cb
)(FILE *stream
))
398 if (_init_lttng_ust_safe_fclose_stream()) {
399 /* Chain on ust-2.12 preload */
400 return __lttng_ust_safe_fclose_stream(stream
, fclose_cb
);
402 /* Fallback to libc symbol */
403 return fclose_cb(stream
);
409 * Interface allowing applications to close arbitrary streams.
410 * We check if it is owned by lttng-ust, and return -1, errno=EBADF
411 * instead of closing it if it is the case.
413 static int lttng_ust_safe_fclose_stream_orig(FILE *stream
, int (*fclose_cb
)(FILE *stream
))
417 lttng_ust_fd_tracker_alloc_tls();
420 * Ensure the tracker is initialized when called from
423 lttng_ust_fd_tracker_init();
426 * If called from lttng-ust, we directly call fclose without
427 * validating whether the FD is part of the tracked set.
429 if (URCU_TLS(ust_fd_mutex_nest
)) {
430 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
431 return lttng_ust_safe_fclose_stream_chain(stream
, fclose_cb
);
433 return fclose_cb(stream
);
439 lttng_ust_lock_fd_tracker();
440 if (IS_FD_VALID(fd
) && IS_FD_SET(fd
, lttng_fd_set
)) {
444 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
445 ret
= lttng_ust_safe_fclose_stream_chain(stream
, fclose_cb
);
447 ret
= fclose_cb(stream
);
450 lttng_ust_unlock_fd_tracker();
456 static void set_close_success(int *p
)
460 static int test_close_success(const int *p
)
465 static void set_close_success(int *p
__attribute__((unused
)))
468 static int test_close_success(const int *p
__attribute__((unused
)))
475 * Implement helper for closefrom() override.
477 static int lttng_ust_safe_closefrom_fd_orig(int lowfd
, int (*close_cb
)(int fd
))
479 int ret
= 0, close_success
= 0, i
;
481 lttng_ust_fd_tracker_alloc_tls();
484 * Ensure the tracker is initialized when called from
487 lttng_ust_fd_tracker_init();
491 * NetBSD return EBADF if fd is invalid.
498 * If called from lttng-ust, we directly call close without
499 * validating whether the FD is part of the tracked set.
501 if (URCU_TLS(ust_fd_mutex_nest
)) {
502 for (i
= lowfd
; i
< lttng_ust_max_fd
; i
++) {
503 if (close_cb(i
) < 0) {
513 set_close_success(&close_success
);
516 lttng_ust_lock_fd_tracker();
517 for (i
= lowfd
; i
< lttng_ust_max_fd
; i
++) {
518 if (IS_FD_VALID(i
) && IS_FD_SET(i
, lttng_fd_set
))
520 if (close_cb(i
) < 0) {
527 lttng_ust_unlock_fd_tracker();
531 set_close_success(&close_success
);
533 lttng_ust_unlock_fd_tracker();
535 if (!test_close_success(&close_success
)) {
537 * OpenBSD return EBADF if fd is greater than all open
547 /* Custom upgrade 2.12 to 2.13 */
549 #undef lttng_ust_add_fd_to_tracker
550 #undef lttng_ust_delete_fd_from_tracker
551 #undef lttng_ust_lock_fd_tracker
552 #undef lttng_ust_unlock_fd_tracker
553 #undef lttng_ust_safe_close_fd
554 #undef lttng_ust_safe_fclose_stream
555 #undef lttng_ust_safe_closefrom_fd
557 int lttng_ust_add_fd_to_tracker1(int fd
)
558 __attribute__ ((alias ("lttng_ust_add_fd_to_tracker_orig")));
559 void lttng_ust_delete_fd_from_tracker1(int fd
)
560 __attribute__ ((alias ("lttng_ust_delete_fd_from_tracker_orig")));
561 void lttng_ust_lock_fd_tracker1(void)
562 __attribute__ ((alias ("lttng_ust_lock_fd_tracker_orig")));
563 void lttng_ust_unlock_fd_tracker1(void)
564 __attribute__ ((alias ("lttng_ust_unlock_fd_tracker_orig")));
565 int lttng_ust_safe_close_fd1(int fd
, int (*close_cb
)(int))
566 __attribute__ ((alias ("lttng_ust_safe_close_fd_orig")));
567 int lttng_ust_safe_fclose_stream1(FILE *stream
, int (*fclose_cb
)(FILE *stream
))
568 __attribute__ ((alias ("lttng_ust_safe_fclose_stream_orig")));
569 int lttng_ust_safe_closefrom_fd1(int lowfd
, int (*close_cb
)(int))
570 __attribute__ ((alias ("lttng_ust_safe_closefrom_fd_orig")));
572 #ifdef LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS
573 int lttng_ust_add_fd_to_tracker(int fd
)
574 __attribute__ ((alias ("lttng_ust_add_fd_to_tracker_orig")));
575 void lttng_ust_delete_fd_from_tracker(int fd
)
576 __attribute__ ((alias ("lttng_ust_delete_fd_from_tracker_orig")));
577 void lttng_ust_lock_fd_tracker(void)
578 __attribute__ ((alias ("lttng_ust_lock_fd_tracker_orig")));
579 void lttng_ust_unlock_fd_tracker(void)
580 __attribute__ ((alias ("lttng_ust_unlock_fd_tracker_orig")));
581 int lttng_ust_safe_close_fd(int fd
, int (*close_cb
)(int))
582 __attribute__ ((alias ("lttng_ust_safe_close_fd_orig")));
583 int lttng_ust_safe_fclose_stream(FILE *stream
, int (*fclose_cb
)(FILE *stream
))
584 __attribute__ ((alias ("lttng_ust_safe_fclose_stream_orig")));
585 int lttng_ust_safe_closefrom_fd(int lowfd
, int (*close_cb
)(int))
586 __attribute__ ((alias ("lttng_ust_safe_closefrom_fd_orig")));