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 #define LTTNG_UST_DLSYM_FAILED_PTR 0x1
39 /* Operations on the fd set. */
40 #define IS_FD_VALID(fd) ((fd) >= 0 && (fd) < lttng_ust_max_fd)
41 #define GET_FD_SET_FOR_FD(fd, fd_sets) (&((fd_sets)[(fd) / FD_SETSIZE]))
42 #define CALC_INDEX_TO_SET(fd) ((fd) % FD_SETSIZE)
43 #define IS_FD_STD(fd) (IS_FD_VALID(fd) && (fd) <= STDERR_FILENO)
45 /* Check fd validity before calling these. */
46 #define ADD_FD_TO_SET(fd, fd_sets) \
47 FD_SET(CALC_INDEX_TO_SET(fd), GET_FD_SET_FOR_FD(fd, fd_sets))
48 #define IS_FD_SET(fd, fd_sets) \
49 FD_ISSET(CALC_INDEX_TO_SET(fd), GET_FD_SET_FOR_FD(fd, fd_sets))
50 #define DEL_FD_FROM_SET(fd, fd_sets) \
51 FD_CLR(CALC_INDEX_TO_SET(fd), GET_FD_SET_FOR_FD(fd, fd_sets))
54 * Protect the lttng_fd_set. Nests within the ust_lock, and therefore
55 * within the libc dl lock. Therefore, we need to allocate the TLS before
56 * nesting into this lock.
58 * The ust_safe_guard_fd_mutex nests within the ust_mutex. This mutex
59 * is also held across fork.
61 static pthread_mutex_t ust_safe_guard_fd_mutex
= PTHREAD_MUTEX_INITIALIZER
;
64 * Track whether we are within lttng-ust or application, for close
65 * system call override by LD_PRELOAD library. This also tracks whether
66 * we are invoking close() from a signal handler nested on an
69 static DEFINE_URCU_TLS(int, ust_fd_mutex_nest
);
71 /* fd_set used to book keep fd being used by lttng-ust. */
72 static fd_set
*lttng_fd_set
;
73 static int lttng_ust_max_fd
;
74 static int num_fd_sets
;
78 * Force a read (imply TLS allocation for dlopen) of TLS variables.
80 void lttng_ust_fd_tracker_alloc_tls(void)
82 asm volatile ("" : : "m" (URCU_TLS(ust_fd_mutex_nest
)));
85 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
86 static int (*__lttng_ust_safe_close_fd
)(int fd
, int (*close_cb
)(int fd
)) = NULL
;
88 void *lttng_ust_safe_close_fd_init(void)
90 if (__lttng_ust_safe_close_fd
== NULL
) {
91 __lttng_ust_safe_close_fd
= dlsym(RTLD_DEFAULT
, "lttng_ust_safe_close_fd");
93 if (__lttng_ust_safe_close_fd
== NULL
) {
94 __lttng_ust_safe_close_fd
= (void *) LTTNG_UST_DLSYM_FAILED_PTR
;
95 fprintf(stderr
, "%s\n", dlerror());
99 return __lttng_ust_safe_close_fd
;
102 static int lttng_ust_safe_close_fd_chain(int fd
, int (*close_cb
)(int fd
))
104 assert(__lttng_ust_safe_close_fd
!= NULL
);
105 if (__lttng_ust_safe_close_fd
!= (void *) LTTNG_UST_DLSYM_FAILED_PTR
) {
106 /* Chain on ust-2.12 preload */
107 return __lttng_ust_safe_close_fd(fd
, close_cb
);
109 /* Fallback to libc symbol */
114 static int lttng_ust_safe_close_fd_chain(int fd
, int (*close_cb
)(int fd
))
120 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
121 static int (*__lttng_ust_safe_fclose_stream
)(FILE *stream
, int (*fclose_cb
)(FILE *stream
)) = NULL
;
123 void *lttng_ust_safe_fclose_stream_init(void)
125 if (__lttng_ust_safe_fclose_stream
== NULL
) {
126 __lttng_ust_safe_fclose_stream
= dlsym(RTLD_DEFAULT
, "lttng_ust_safe_fclose_stream");
128 if (__lttng_ust_safe_fclose_stream
== NULL
) {
129 __lttng_ust_safe_fclose_stream
= (void *) LTTNG_UST_DLSYM_FAILED_PTR
;
130 fprintf(stderr
, "%s\n", dlerror());
134 return __lttng_ust_safe_fclose_stream
;
137 static int lttng_ust_safe_fclose_stream_chain(FILE *stream
, int (*fclose_cb
)(FILE *stream
))
139 assert(__lttng_ust_safe_fclose_stream
!= NULL
);
140 if (__lttng_ust_safe_fclose_stream
!= (void *) LTTNG_UST_DLSYM_FAILED_PTR
) {
141 /* Chain on ust-2.12 preload */
142 return __lttng_ust_safe_fclose_stream(stream
, fclose_cb
);
144 /* Fallback to libc symbol */
145 return fclose_cb(stream
);
149 static int lttng_ust_safe_fclose_stream_chain(FILE *stream
, int (*fclose_cb
)(FILE *stream
))
151 return fclose_cb(stream
);
156 * Allocate the fd set array based on the hard limit set for this
157 * process. This will be called during the constructor execution
158 * and will also be called in the child after fork via lttng_ust_init.
160 void lttng_ust_fd_tracker_init(void)
165 if (CMM_LOAD_SHARED(init_done
))
168 memset(&rlim
, 0, sizeof(rlim
));
169 /* Get the current possible max number of fd for this process. */
170 if (getrlimit(RLIMIT_NOFILE
, &rlim
) < 0)
173 * FD set array size determined using the hard limit. Even if
174 * the process wishes to increase its limit using setrlimit, it
175 * can only do so with the softlimit which will be less than the
178 lttng_ust_max_fd
= rlim
.rlim_max
;
179 num_fd_sets
= lttng_ust_max_fd
/ FD_SETSIZE
;
180 if (lttng_ust_max_fd
% FD_SETSIZE
)
182 if (lttng_fd_set
!= NULL
) {
186 lttng_fd_set
= malloc(num_fd_sets
* (sizeof(fd_set
)));
189 for (i
= 0; i
< num_fd_sets
; i
++)
190 FD_ZERO((<tng_fd_set
[i
]));
191 CMM_STORE_SHARED(init_done
, 1);
194 static void lttng_ust_lock_fd_tracker_orig(void)
196 sigset_t sig_all_blocked
, orig_mask
;
199 if (lttng_ust_cancelstate_disable_push()) {
200 ERR("lttng_ust_cancelstate_disable_push");
202 sigfillset(&sig_all_blocked
);
203 ret
= pthread_sigmask(SIG_SETMASK
, &sig_all_blocked
, &orig_mask
);
205 ERR("pthread_sigmask: %s", strerror(ret
));
207 if (!URCU_TLS(ust_fd_mutex_nest
)++) {
209 * Ensure the compiler don't move the store after the close()
210 * call in case close() would be marked as leaf.
213 pthread_mutex_lock(&ust_safe_guard_fd_mutex
);
215 ret
= pthread_sigmask(SIG_SETMASK
, &orig_mask
, NULL
);
217 ERR("pthread_sigmask: %s", strerror(ret
));
221 static void lttng_ust_unlock_fd_tracker_orig(void)
223 sigset_t sig_all_blocked
, orig_mask
;
226 sigfillset(&sig_all_blocked
);
227 ret
= pthread_sigmask(SIG_SETMASK
, &sig_all_blocked
, &orig_mask
);
229 ERR("pthread_sigmask: %s", strerror(ret
));
232 * Ensure the compiler don't move the store before the close()
233 * call, in case close() would be marked as leaf.
236 if (!--URCU_TLS(ust_fd_mutex_nest
)) {
237 pthread_mutex_unlock(&ust_safe_guard_fd_mutex
);
239 ret
= pthread_sigmask(SIG_SETMASK
, &orig_mask
, NULL
);
241 ERR("pthread_sigmask: %s", strerror(ret
));
243 if (lttng_ust_cancelstate_disable_pop()) {
244 ERR("lttng_ust_cancelstate_disable_pop");
248 static int dup_std_fd(int fd
)
251 int fd_to_close
[STDERR_FILENO
+ 1];
252 int fd_to_close_count
= 0;
253 int dup_cmd
= F_DUPFD
; /* Default command */
256 if (!(IS_FD_STD(fd
))) {
257 /* Should not be here */
262 /* Check for FD_CLOEXEC flag */
263 ret
= fcntl(fd
, F_GETFD
);
265 PERROR("fcntl on f_getfd");
270 if (ret
& FD_CLOEXEC
) {
271 dup_cmd
= F_DUPFD_CLOEXEC
;
275 for (i
= 0; i
< STDERR_FILENO
+ 1; i
++) {
276 ret
= fcntl(fd
, dup_cmd
, 0);
278 PERROR("fcntl dup fd");
282 if (!(IS_FD_STD(ret
))) {
283 /* fd is outside of STD range, use it. */
285 /* Close fd received as argument. */
291 fd_to_close
[i
] = ret
;
295 /* Close intermediary fds */
296 for (i
= 0; i
< fd_to_close_count
; i
++) {
297 ret
= close(fd_to_close
[i
]);
299 PERROR("close on temporary fd: %d.", fd_to_close
[i
]);
301 * Not using an abort here would yield a complicated
302 * error handling for the caller. If a failure occurs
303 * here, the system is already in a bad state.
315 * Needs to be called with ust_safe_guard_fd_mutex held when opening the fd.
316 * Has strict checking of fd validity.
318 * If fd <= 2, dup the fd until fd > 2. This enables us to bypass
319 * problems that can be encountered if UST uses stdin, stdout, stderr
320 * fds for internal use (daemon etc.). This can happen if the
321 * application closes either of those file descriptors. Intermediary fds
322 * are closed as needed.
324 * Return -1 on error.
327 static int lttng_ust_add_fd_to_tracker_orig(int fd
)
331 * Ensure the tracker is initialized when called from
334 lttng_ust_fd_tracker_init();
335 assert(URCU_TLS(ust_fd_mutex_nest
));
338 ret
= dup_std_fd(fd
);
345 /* Trying to add an fd which we can not accommodate. */
346 assert(IS_FD_VALID(fd
));
347 /* Setting an fd thats already set. */
348 assert(!IS_FD_SET(fd
, lttng_fd_set
));
350 ADD_FD_TO_SET(fd
, lttng_fd_set
);
357 * Needs to be called with ust_safe_guard_fd_mutex held when opening the fd.
358 * Has strict checking for fd validity.
360 static void lttng_ust_delete_fd_from_tracker_orig(int fd
)
363 * Ensure the tracker is initialized when called from
366 lttng_ust_fd_tracker_init();
368 assert(URCU_TLS(ust_fd_mutex_nest
));
369 /* Not a valid fd. */
370 assert(IS_FD_VALID(fd
));
371 /* Deleting an fd which was not set. */
372 assert(IS_FD_SET(fd
, lttng_fd_set
));
374 DEL_FD_FROM_SET(fd
, lttng_fd_set
);
377 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
378 /* lttng-ust 2.12 (custom branch) getter */
379 static int (*__lttng_ust_get_fd_mutex_nest
)(void) = NULL
;
381 void *lttng_ust_get_fd_mutex_nest_init(void)
383 if (__lttng_ust_get_fd_mutex_nest
== NULL
) {
384 __lttng_ust_get_fd_mutex_nest
= dlsym(RTLD_DEFAULT
, "lttng_ust_get_fd_mutex_nest");
386 if (__lttng_ust_get_fd_mutex_nest
== NULL
) {
387 __lttng_ust_get_fd_mutex_nest
= (void *) LTTNG_UST_DLSYM_FAILED_PTR
;
388 fprintf(stderr
, "%s\n", dlerror());
392 return __lttng_ust_get_fd_mutex_nest
;
395 static int lttng_ust_get_fd_mutex_nest_chain(void)
397 assert(__lttng_ust_get_fd_mutex_nest
!= NULL
);
398 if (__lttng_ust_get_fd_mutex_nest
!= (void *) LTTNG_UST_DLSYM_FAILED_PTR
)
399 return __lttng_ust_get_fd_mutex_nest();
403 static int lttng_ust_get_fd_mutex_nest_chain(void)
410 * Interface allowing applications to close arbitrary file descriptors.
411 * We check if it is owned by lttng-ust, and return -1, errno=EBADF
412 * instead of closing it if it is the case.
414 static int lttng_ust_safe_close_fd_orig(int fd
, int (*close_cb
)(int fd
))
418 lttng_ust_fd_tracker_alloc_tls();
421 * Ensure the tracker is initialized when called from
424 lttng_ust_fd_tracker_init();
427 * If called from lttng-ust, we directly call close without
428 * validating whether the FD is part of the tracked set.
430 if (URCU_TLS(ust_fd_mutex_nest
) || lttng_ust_get_fd_mutex_nest_chain())
433 lttng_ust_lock_fd_tracker();
434 if (IS_FD_VALID(fd
) && IS_FD_SET(fd
, lttng_fd_set
)) {
438 ret
= lttng_ust_safe_close_fd_chain(fd
, close_cb
);
440 lttng_ust_unlock_fd_tracker();
446 * Interface allowing applications to close arbitrary streams.
447 * We check if it is owned by lttng-ust, and return -1, errno=EBADF
448 * instead of closing it if it is the case.
450 static int lttng_ust_safe_fclose_stream_orig(FILE *stream
, int (*fclose_cb
)(FILE *stream
))
454 lttng_ust_fd_tracker_alloc_tls();
457 * Ensure the tracker is initialized when called from
460 lttng_ust_fd_tracker_init();
463 * If called from lttng-ust, we directly call fclose without
464 * validating whether the FD is part of the tracked set.
466 if (URCU_TLS(ust_fd_mutex_nest
) || lttng_ust_get_fd_mutex_nest_chain())
467 return fclose_cb(stream
);
471 lttng_ust_lock_fd_tracker();
472 if (IS_FD_VALID(fd
) && IS_FD_SET(fd
, lttng_fd_set
)) {
476 ret
= lttng_ust_safe_fclose_stream_chain(stream
, fclose_cb
);
478 lttng_ust_unlock_fd_tracker();
484 static void set_close_success(int *p
)
488 static int test_close_success(const int *p
)
493 static void set_close_success(int *p
__attribute__((unused
)))
496 static int test_close_success(const int *p
__attribute__((unused
)))
503 * Implement helper for closefrom() override.
505 static int lttng_ust_safe_closefrom_fd_orig(int lowfd
, int (*close_cb
)(int fd
))
507 int ret
= 0, close_success
= 0, i
;
509 lttng_ust_fd_tracker_alloc_tls();
512 * Ensure the tracker is initialized when called from
515 lttng_ust_fd_tracker_init();
519 * NetBSD return EBADF if fd is invalid.
526 * If called from lttng-ust, we directly call close without
527 * validating whether the FD is part of the tracked set.
529 if (URCU_TLS(ust_fd_mutex_nest
) || lttng_ust_get_fd_mutex_nest_chain()) {
530 for (i
= lowfd
; i
< lttng_ust_max_fd
; i
++) {
531 if (close_cb(i
) < 0) {
541 set_close_success(&close_success
);
544 lttng_ust_lock_fd_tracker();
545 for (i
= lowfd
; i
< lttng_ust_max_fd
; i
++) {
546 if (IS_FD_VALID(i
) && IS_FD_SET(i
, lttng_fd_set
))
548 if (close_cb(i
) < 0) {
555 lttng_ust_unlock_fd_tracker();
559 set_close_success(&close_success
);
561 lttng_ust_unlock_fd_tracker();
563 if (!test_close_success(&close_success
)) {
565 * OpenBSD return EBADF if fd is greater than all open
575 /* Custom upgrade 2.12 to 2.13 */
577 #undef lttng_ust_add_fd_to_tracker
578 #undef lttng_ust_delete_fd_from_tracker
579 #undef lttng_ust_lock_fd_tracker
580 #undef lttng_ust_unlock_fd_tracker
581 #undef lttng_ust_safe_close_fd
582 #undef lttng_ust_safe_fclose_stream
583 #undef lttng_ust_safe_closefrom_fd
585 int lttng_ust_add_fd_to_tracker1(int fd
)
586 __attribute__ ((alias ("lttng_ust_add_fd_to_tracker_orig")));
587 void lttng_ust_delete_fd_from_tracker1(int fd
)
588 __attribute__ ((alias ("lttng_ust_delete_fd_from_tracker_orig")));
589 void lttng_ust_lock_fd_tracker1(void)
590 __attribute__ ((alias ("lttng_ust_lock_fd_tracker_orig")));
591 void lttng_ust_unlock_fd_tracker1(void)
592 __attribute__ ((alias ("lttng_ust_unlock_fd_tracker_orig")));
593 int lttng_ust_safe_close_fd1(int fd
, int (*close_cb
)(int))
594 __attribute__ ((alias ("lttng_ust_safe_close_fd_orig")));
595 int lttng_ust_safe_fclose_stream1(FILE *stream
, int (*fclose_cb
)(FILE *stream
))
596 __attribute__ ((alias ("lttng_ust_safe_fclose_stream_orig")));
597 int lttng_ust_safe_closefrom_fd1(int lowfd
, int (*close_cb
)(int))
598 __attribute__ ((alias ("lttng_ust_safe_closefrom_fd_orig")));
600 #ifdef LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS
601 int lttng_ust_add_fd_to_tracker(int fd
)
602 __attribute__ ((alias ("lttng_ust_add_fd_to_tracker_orig")));
603 void lttng_ust_delete_fd_from_tracker(int fd
)
604 __attribute__ ((alias ("lttng_ust_delete_fd_from_tracker_orig")));
605 void lttng_ust_lock_fd_tracker(void)
606 __attribute__ ((alias ("lttng_ust_lock_fd_tracker_orig")));
607 void lttng_ust_unlock_fd_tracker(void)
608 __attribute__ ((alias ("lttng_ust_unlock_fd_tracker_orig")));
609 int lttng_ust_safe_close_fd(int fd
, int (*close_cb
)(int))
610 __attribute__ ((alias ("lttng_ust_safe_close_fd_orig")));
611 int lttng_ust_safe_fclose_stream(FILE *stream
, int (*fclose_cb
)(FILE *stream
))
612 __attribute__ ((alias ("lttng_ust_safe_fclose_stream_orig")));
613 int lttng_ust_safe_closefrom_fd(int lowfd
, int (*close_cb
)(int))
614 __attribute__ ((alias ("lttng_ust_safe_closefrom_fd_orig")));