]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/sigbus.c
8ff060a8d1ea4145472eb5297f751be1648533f1
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
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
) {
28 /* Find a free place, increase the number of entries and leave, if we can */
29 for (size_t u
= 0; u
< SIGBUS_QUEUE_MAX
; u
++)
30 if (__sync_bool_compare_and_swap(&sigbus_queue
[u
], NULL
, addr
)) {
31 __sync_fetch_and_add(&n_sigbus_queue
, 1);
35 /* If we can't, make sure the queue size is out of bounds, to
36 * mark it as overflow */
43 if (c
> SIGBUS_QUEUE_MAX
) /* already overflow */
46 if (__sync_bool_compare_and_swap(&n_sigbus_queue
, c
, c
+ SIGBUS_QUEUE_MAX
))
51 int sigbus_pop(void **ret
) {
63 if (_unlikely_(c
>= SIGBUS_QUEUE_MAX
))
66 for (u
= 0; u
< SIGBUS_QUEUE_MAX
; u
++) {
69 addr
= sigbus_queue
[u
];
73 if (__sync_bool_compare_and_swap(&sigbus_queue
[u
], addr
, NULL
)) {
74 __sync_fetch_and_sub(&n_sigbus_queue
, 1);
82 static void sigbus_handler(int sn
, siginfo_t
*si
, void *data
) {
89 if (si
->si_code
!= BUS_ADRERR
|| !si
->si_addr
) {
90 assert_se(sigaction(SIGBUS
, &old_sigaction
, NULL
) == 0);
95 ul
= (unsigned long) si
->si_addr
;
96 ul
= ul
/ page_size();
97 ul
= ul
* page_size();
100 /* Let's remember which address failed */
101 sigbus_push(aligned
);
103 /* Replace mapping with an anonymous page, so that the
104 * execution can continue, however with a zeroed out page */
105 assert_se(mmap(aligned
, page_size(), PROT_READ
|PROT_WRITE
, MAP_PRIVATE
|MAP_ANONYMOUS
|MAP_FIXED
, -1, 0) == aligned
);
108 void sigbus_install(void) {
109 struct sigaction sa
= {
110 .sa_sigaction
= sigbus_handler
,
111 .sa_flags
= SA_SIGINFO
,
114 /* make sure that sysconf() is not called from a signal handler because
115 * it is not guaranteed to be async-signal-safe since POSIX.1-2008 */
120 if (n_installed
== 1)
121 assert_se(sigaction(SIGBUS
, &sa
, &old_sigaction
) == 0);
126 void sigbus_reset(void) {
128 if (n_installed
<= 0)
133 if (n_installed
== 0)
134 assert_se(sigaction(SIGBUS
, &old_sigaction
, NULL
) == 0);