]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/sigbus.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2014 Lennart Poettering
17 #define SIGBUS_QUEUE_MAX 64
19 static struct sigaction old_sigaction
;
20 static unsigned n_installed
= 0;
22 /* We maintain a fixed size list of page addresses that triggered a
23 SIGBUS. We access with list with atomic operations, so that we
24 don't have to deal with locks between signal handler and main
25 programs in possibly multiple threads. */
27 static void* volatile sigbus_queue
[SIGBUS_QUEUE_MAX
];
28 static volatile sig_atomic_t n_sigbus_queue
= 0;
30 static void sigbus_push(void *addr
) {
35 /* Find a free place, increase the number of entries and leave, if we can */
36 for (u
= 0; u
< SIGBUS_QUEUE_MAX
; u
++)
37 if (__sync_bool_compare_and_swap(&sigbus_queue
[u
], NULL
, addr
)) {
38 __sync_fetch_and_add(&n_sigbus_queue
, 1);
42 /* If we can't, make sure the queue size is out of bounds, to
43 * mark it as overflow */
50 if (c
> SIGBUS_QUEUE_MAX
) /* already overflow */
53 if (__sync_bool_compare_and_swap(&n_sigbus_queue
, c
, c
+ SIGBUS_QUEUE_MAX
))
58 int sigbus_pop(void **ret
) {
70 if (_unlikely_(c
>= SIGBUS_QUEUE_MAX
))
73 for (u
= 0; u
< SIGBUS_QUEUE_MAX
; u
++) {
76 addr
= sigbus_queue
[u
];
80 if (__sync_bool_compare_and_swap(&sigbus_queue
[u
], addr
, NULL
)) {
81 __sync_fetch_and_sub(&n_sigbus_queue
, 1);
89 static void sigbus_handler(int sn
, siginfo_t
*si
, void *data
) {
96 if (si
->si_code
!= BUS_ADRERR
|| !si
->si_addr
) {
97 assert_se(sigaction(SIGBUS
, &old_sigaction
, NULL
) == 0);
102 ul
= (unsigned long) si
->si_addr
;
103 ul
= ul
/ page_size();
104 ul
= ul
* page_size();
105 aligned
= (void*) ul
;
107 /* Let's remember which address failed */
108 sigbus_push(aligned
);
110 /* Replace mapping with an anonymous page, so that the
111 * execution can continue, however with a zeroed out page */
112 assert_se(mmap(aligned
, page_size(), PROT_READ
|PROT_WRITE
, MAP_PRIVATE
|MAP_ANONYMOUS
|MAP_FIXED
, -1, 0) == aligned
);
115 void sigbus_install(void) {
116 struct sigaction sa
= {
117 .sa_sigaction
= sigbus_handler
,
118 .sa_flags
= SA_SIGINFO
,
123 if (n_installed
== 1)
124 assert_se(sigaction(SIGBUS
, &sa
, &old_sigaction
) == 0);
129 void sigbus_reset(void) {
131 if (n_installed
<= 0)
136 if (n_installed
== 0)
137 assert_se(sigaction(SIGBUS
, &old_sigaction
, NULL
) == 0);