]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/sigbus.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
9 #include "memory-util.h"
12 #define SIGBUS_QUEUE_MAX 64
14 static struct sigaction old_sigaction
;
15 static unsigned n_installed
= 0;
17 /* We maintain a fixed size list of page addresses that triggered a
18 SIGBUS. We access with list with atomic operations, so that we
19 don't have to deal with locks between signal handler and main
20 programs in possibly multiple threads. */
22 static void* volatile sigbus_queue
[SIGBUS_QUEUE_MAX
];
23 static volatile sig_atomic_t n_sigbus_queue
= 0;
25 static void sigbus_push(void *addr
) {
30 /* Find a free place, increase the number of entries and leave, if we can */
31 for (u
= 0; u
< SIGBUS_QUEUE_MAX
; u
++)
32 if (__sync_bool_compare_and_swap(&sigbus_queue
[u
], NULL
, addr
)) {
33 __sync_fetch_and_add(&n_sigbus_queue
, 1);
37 /* If we can't, make sure the queue size is out of bounds, to
38 * mark it as overflow */
45 if (c
> SIGBUS_QUEUE_MAX
) /* already overflow */
48 if (__sync_bool_compare_and_swap(&n_sigbus_queue
, c
, c
+ SIGBUS_QUEUE_MAX
))
53 int sigbus_pop(void **ret
) {
65 if (_unlikely_(c
>= SIGBUS_QUEUE_MAX
))
68 for (u
= 0; u
< SIGBUS_QUEUE_MAX
; u
++) {
71 addr
= sigbus_queue
[u
];
75 if (__sync_bool_compare_and_swap(&sigbus_queue
[u
], addr
, NULL
)) {
76 __sync_fetch_and_sub(&n_sigbus_queue
, 1);
84 static void sigbus_handler(int sn
, siginfo_t
*si
, void *data
) {
91 if (si
->si_code
!= BUS_ADRERR
|| !si
->si_addr
) {
92 assert_se(sigaction(SIGBUS
, &old_sigaction
, NULL
) == 0);
97 ul
= (unsigned long) si
->si_addr
;
98 ul
= ul
/ page_size();
99 ul
= ul
* page_size();
100 aligned
= (void*) ul
;
102 /* Let's remember which address failed */
103 sigbus_push(aligned
);
105 /* Replace mapping with an anonymous page, so that the
106 * execution can continue, however with a zeroed out page */
107 assert_se(mmap(aligned
, page_size(), PROT_READ
|PROT_WRITE
, MAP_PRIVATE
|MAP_ANONYMOUS
|MAP_FIXED
, -1, 0) == aligned
);
110 void sigbus_install(void) {
111 struct sigaction sa
= {
112 .sa_sigaction
= sigbus_handler
,
113 .sa_flags
= SA_SIGINFO
,
116 /* make sure that sysconf() is not called from a signal handler because
117 * it is not guaranteed to be async-signal-safe since POSIX.1-2008 */
122 if (n_installed
== 1)
123 assert_se(sigaction(SIGBUS
, &sa
, &old_sigaction
) == 0);
128 void sigbus_reset(void) {
130 if (n_installed
<= 0)
135 if (n_installed
== 0)
136 assert_se(sigaction(SIGBUS
, &old_sigaction
, NULL
) == 0);