busfault.c revision 35c4bbdf
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 *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(busfault, &busfaults, list) { 107 if ((char *) busfault->addr <= (char *) fault && (char *) fault < (char *) busfault->addr + busfault->size) { 108 break; 109 } 110 } 111 if (!busfault) 112 goto panic; 113 114 if (!busfault->valid) 115 goto panic; 116 117 busfault->valid = FALSE; 118 busfaulted = TRUE; 119 120 /* The client truncated the file; unmap the shared file, map 121 * /dev/zero over that area and keep going 122 */ 123 124 new_addr = mmap(busfault->addr, busfault->size, PROT_READ|PROT_WRITE, 125 MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0); 126 127 if (new_addr == MAP_FAILED) 128 goto panic; 129 130 return; 131panic: 132 if (previous_busfault_sigaction) 133 (*previous_busfault_sigaction)(sig, info, param); 134 else 135 FatalError("bus error"); 136} 137 138Bool 139busfault_init(void) 140{ 141 struct sigaction act, old_act; 142 143 act.sa_sigaction = busfault_sigaction; 144 act.sa_flags = SA_SIGINFO; 145 sigemptyset(&act.sa_mask); 146 if (sigaction(SIGBUS, &act, &old_act) < 0) 147 return FALSE; 148 previous_busfault_sigaction = old_act.sa_sigaction; 149 xorg_list_init(&busfaults); 150 return TRUE; 151} 152