Branch data Line data Source code
1 : : /***
2 : : This file is part of PulseAudio.
3 : :
4 : : Copyright 2009 Lennart Poettering
5 : :
6 : : PulseAudio is free software; you can redistribute it and/or modify
7 : : it under the terms of the GNU Lesser General Public License as
8 : : published by the Free Software Foundation; either version 2.1 of the
9 : : License, or (at your option) any later version.
10 : :
11 : : PulseAudio is distributed in the hope that it will be useful, but
12 : : WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : : General Public License for more details.
15 : :
16 : : You should have received a copy of the GNU Lesser General Public
17 : : License along with PulseAudio; if not, write to the Free Software
18 : : Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 : : USA.
20 : : ***/
21 : :
22 : : #ifdef HAVE_CONFIG_H
23 : : #include <config.h>
24 : : #endif
25 : :
26 : : #include <signal.h>
27 : :
28 : : #ifdef HAVE_SYS_MMAN_H
29 : : #include <sys/mman.h>
30 : : #endif
31 : :
32 : : /* This is deprecated on glibc but is still used by FreeBSD */
33 : : #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
34 : : # define MAP_ANONYMOUS MAP_ANON
35 : : #endif
36 : :
37 : : #include <pulse/xmalloc.h>
38 : :
39 : : #include <pulsecore/core-util.h>
40 : : #include <pulsecore/aupdate.h>
41 : : #include <pulsecore/atomic.h>
42 : : #include <pulsecore/once.h>
43 : : #include <pulsecore/mutex.h>
44 : :
45 : : #include "memtrap.h"
46 : :
47 : : struct pa_memtrap {
48 : : void *start;
49 : : size_t size;
50 : : pa_atomic_t bad;
51 : : pa_memtrap *next[2], *prev[2];
52 : : };
53 : :
54 : : static pa_memtrap *memtraps[2] = { NULL, NULL };
55 : : static pa_aupdate *aupdate;
56 : : static pa_static_mutex mutex = PA_STATIC_MUTEX_INIT; /* only required to serialize access to the write side */
57 : :
58 : 19 : static void allocate_aupdate(void) {
59 [ + + ]: 19 : PA_ONCE_BEGIN {
60 : 2 : aupdate = pa_aupdate_new();
61 : 2 : } PA_ONCE_END;
62 : 19 : }
63 : :
64 : 2 : pa_bool_t pa_memtrap_is_good(pa_memtrap *m) {
65 [ - + ]: 2 : pa_assert(m);
66 : :
67 : 2 : return !pa_atomic_load(&m->bad);
68 : : }
69 : :
70 : : #ifdef HAVE_SIGACTION
71 : 0 : static void sigsafe_error(const char *s) {
72 : : size_t ret PA_GCC_UNUSED;
73 : 0 : ret = write(STDERR_FILENO, s, strlen(s));
74 : 0 : }
75 : :
76 : 1 : static void signal_handler(int sig, siginfo_t* si, void *data) {
77 : : unsigned j;
78 : : pa_memtrap *m;
79 : : void *r;
80 : :
81 : 1 : j = pa_aupdate_read_begin(aupdate);
82 : :
83 [ + - ]: 1 : for (m = memtraps[j]; m; m = m->next[j])
84 [ + - ][ - + ]: 1 : if (si->si_addr >= m->start &&
85 : 1 : (uint8_t*) si->si_addr < (uint8_t*) m->start + m->size)
86 : : break;
87 : :
88 [ + - ]: 1 : if (!m)
89 : : goto fail;
90 : :
91 : 1 : pa_atomic_store(&m->bad, 1);
92 : :
93 : : /* Remap anonymous memory into the bad segment */
94 [ - + ]: 1 : if ((r = mmap(m->start, m->size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_FIXED|MAP_PRIVATE, -1, 0)) == MAP_FAILED) {
95 : 0 : sigsafe_error("mmap() failed.\n");
96 : 0 : goto fail;
97 : : }
98 : :
99 [ - + ]: 1 : pa_assert(r == m->start);
100 : :
101 : 1 : pa_aupdate_read_end(aupdate);
102 : 1 : return;
103 : :
104 : : fail:
105 : 0 : pa_aupdate_read_end(aupdate);
106 : :
107 : 0 : sigsafe_error("Failed to handle SIGBUS.\n");
108 : 0 : abort();
109 : : }
110 : : #endif
111 : :
112 : 18 : static void memtrap_link(pa_memtrap *m, unsigned j) {
113 [ - + ]: 18 : pa_assert(m);
114 : :
115 : 18 : m->prev[j] = NULL;
116 : :
117 [ + + ]: 18 : if ((m->next[j] = memtraps[j]))
118 : 8 : m->next[j]->prev[j] = m;
119 : :
120 : 18 : memtraps[j] = m;
121 : 18 : }
122 : :
123 : 18 : static void memtrap_unlink(pa_memtrap *m, unsigned j) {
124 [ - + ]: 18 : pa_assert(m);
125 : :
126 [ - + ]: 18 : if (m->next[j])
127 : 0 : m->next[j]->prev[j] = m->prev[j];
128 : :
129 [ + + ]: 18 : if (m->prev[j])
130 : 8 : m->prev[j]->next[j] = m->next[j];
131 : : else
132 : 10 : memtraps[j] = m->next[j];
133 : 18 : }
134 : :
135 : 9 : pa_memtrap* pa_memtrap_add(const void *start, size_t size) {
136 : 9 : pa_memtrap *m = NULL;
137 : : unsigned j;
138 : : pa_mutex *mx;
139 : :
140 [ - + ]: 9 : pa_assert(start);
141 [ - + ]: 9 : pa_assert(size > 0);
142 : :
143 : 9 : start = PA_PAGE_ALIGN_PTR(start);
144 : 9 : size = PA_PAGE_ALIGN(size);
145 : :
146 : 9 : m = pa_xnew(pa_memtrap, 1);
147 : 9 : m->start = (void*) start;
148 : 9 : m->size = size;
149 : 9 : pa_atomic_store(&m->bad, 0);
150 : :
151 : 9 : allocate_aupdate();
152 : :
153 : 9 : mx = pa_static_mutex_get(&mutex, FALSE, TRUE);
154 : 9 : pa_mutex_lock(mx);
155 : :
156 : 9 : j = pa_aupdate_write_begin(aupdate);
157 : 9 : memtrap_link(m, j);
158 : 9 : j = pa_aupdate_write_swap(aupdate);
159 : 9 : memtrap_link(m, j);
160 : 9 : pa_aupdate_write_end(aupdate);
161 : :
162 : 9 : pa_mutex_unlock(mx);
163 : :
164 : 9 : return m;
165 : : }
166 : :
167 : 9 : void pa_memtrap_remove(pa_memtrap *m) {
168 : : unsigned j;
169 : : pa_mutex *mx;
170 : :
171 [ - + ]: 9 : pa_assert(m);
172 : :
173 : 9 : allocate_aupdate();
174 : :
175 : 9 : mx = pa_static_mutex_get(&mutex, FALSE, TRUE);
176 : 9 : pa_mutex_lock(mx);
177 : :
178 : 9 : j = pa_aupdate_write_begin(aupdate);
179 : 9 : memtrap_unlink(m, j);
180 : 9 : j = pa_aupdate_write_swap(aupdate);
181 : 9 : memtrap_unlink(m, j);
182 : 9 : pa_aupdate_write_end(aupdate);
183 : :
184 : 9 : pa_mutex_unlock(mx);
185 : :
186 : 9 : pa_xfree(m);
187 : 9 : }
188 : :
189 : 0 : pa_memtrap *pa_memtrap_update(pa_memtrap *m, const void *start, size_t size) {
190 : : unsigned j;
191 : : pa_mutex *mx;
192 : :
193 [ # # ]: 0 : pa_assert(m);
194 : :
195 [ # # ]: 0 : pa_assert(start);
196 [ # # ]: 0 : pa_assert(size > 0);
197 : :
198 : 0 : start = PA_PAGE_ALIGN_PTR(start);
199 : 0 : size = PA_PAGE_ALIGN(size);
200 : :
201 : 0 : allocate_aupdate();
202 : :
203 : 0 : mx = pa_static_mutex_get(&mutex, FALSE, TRUE);
204 : 0 : pa_mutex_lock(mx);
205 : :
206 : 0 : j = pa_aupdate_write_begin(aupdate);
207 : :
208 [ # # ][ # # ]: 0 : if (m->start == start && m->size == size)
209 : : goto unlock;
210 : :
211 : 0 : memtrap_unlink(m, j);
212 : 0 : pa_aupdate_write_swap(aupdate);
213 : :
214 : 0 : m->start = (void*) start;
215 : 0 : m->size = size;
216 : 0 : pa_atomic_store(&m->bad, 0);
217 : :
218 [ # # ]: 0 : pa_assert_se(pa_aupdate_write_swap(aupdate) == j);
219 : 0 : memtrap_link(m, j);
220 : :
221 : : unlock:
222 : 0 : pa_aupdate_write_end(aupdate);
223 : :
224 : 0 : pa_mutex_unlock(mx);
225 : :
226 : 0 : return m;
227 : : }
228 : :
229 : 1 : void pa_memtrap_install(void) {
230 : : #ifdef HAVE_SIGACTION
231 : : struct sigaction sa;
232 : :
233 : 1 : allocate_aupdate();
234 : :
235 : : memset(&sa, 0, sizeof(sa));
236 : 1 : sa.sa_sigaction = signal_handler;
237 : 1 : sa.sa_flags = SA_RESTART|SA_SIGINFO;
238 : :
239 [ - + ]: 1 : pa_assert_se(sigaction(SIGBUS, &sa, NULL) == 0);
240 : : #endif
241 : 1 : }
|