busfault.c revision 1b5d61b8
1/* 2 * Copyright © 2013 Keith Packard 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that copyright 7 * notice and this permission notice appear in supporting documentation, and 8 * that the name of the copyright holders not be used in advertising or 9 * publicity pertaining to distribution of the software without specific, 10 * written prior permission. The copyright holders make no representations 11 * about the suitability of this software for any purpose. It is provided "as 12 * is" without express or implied warranty. 13 * 14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 * OF THIS SOFTWARE. 21 */ 22 23#ifdef HAVE_DIX_CONFIG_H 24#include <dix-config.h> 25#endif 26 27#include <X11/Xos.h> 28#include <X11/Xdefs.h> 29#include "misc.h" 30#include <busfault.h> 31#include <list.h> 32#include <stddef.h> 33#include <stdlib.h> 34#include <stdint.h> 35#include <sys/mman.h> 36#include <signal.h> 37 38struct busfault { 39 struct xorg_list list; 40 41 void *addr; 42 size_t size; 43 44 Bool valid; 45 46 busfault_notify_ptr notify; 47 void *context; 48}; 49 50static Bool busfaulted; 51static struct xorg_list busfaults; 52 53struct busfault * 54busfault_register_mmap(void *addr, size_t size, busfault_notify_ptr notify, void *context) 55{ 56 struct busfault *busfault; 57 58 busfault = calloc(1, sizeof (struct busfault)); 59 if (!busfault) 60 return NULL; 61 62 busfault->addr = addr; 63 busfault->size = size; 64 busfault->notify = notify; 65 busfault->context = context; 66 busfault->valid = TRUE; 67 68 xorg_list_add(&busfault->list, &busfaults); 69 return busfault; 70} 71 72void 73busfault_unregister(struct busfault *busfault) 74{ 75 xorg_list_del(&busfault->list); 76 free(busfault); 77} 78 79void 80busfault_check(void) 81{ 82 struct busfault *busfault, *tmp; 83 84 if (!busfaulted) 85 return; 86 87 busfaulted = FALSE; 88 89 xorg_list_for_each_entry_safe(busfault, tmp, &busfaults, list) { 90 if (!busfault->valid) 91 (*busfault->notify)(busfault->context); 92 } 93} 94 95static void (*previous_busfault_sigaction)(int sig, siginfo_t *info, void *param); 96 97static void 98busfault_sigaction(int sig, siginfo_t *info, void *param) 99{ 100 void *fault = info->si_addr; 101 struct busfault *iter, *busfault = NULL; 102 void *new_addr; 103 104 /* Locate the faulting address in our list of shared segments 105 */ 106 xorg_list_for_each_entry(iter, &busfaults, list) { 107 if ((char *) iter->addr <= (char *) fault && (char *) fault < (char *) iter->addr + iter->size) { 108 busfault = iter; 109 break; 110 } 111 } 112 if (!busfault) 113 goto panic; 114 115 if (!busfault->valid) 116 goto panic; 117 118 busfault->valid = FALSE; 119 busfaulted = TRUE; 120 121 /* The client truncated the file; unmap the shared file, map 122 * /dev/zero over that area and keep going 123 */ 124 125 new_addr = mmap(busfault->addr, busfault->size, PROT_READ|PROT_WRITE, 126 MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0); 127 128 if (new_addr == MAP_FAILED) 129 goto panic; 130 131 return; 132panic: 133 if (previous_busfault_sigaction) 134 (*previous_busfault_sigaction)(sig, info, param); 135 else 136 FatalError("bus error\n"); 137} 138 139Bool 140busfault_init(void) 141{ 142 struct sigaction act, old_act; 143 144 act.sa_sigaction = busfault_sigaction; 145 act.sa_flags = SA_SIGINFO; 146 sigemptyset(&act.sa_mask); 147 if (sigaction(SIGBUS, &act, &old_act) < 0) 148 return FALSE; 149 previous_busfault_sigaction = old_act.sa_sigaction; 150 xorg_list_init(&busfaults); 151 return TRUE; 152} 153