> From: Keith Packard <[email protected]> > Date: Sun, 3 Nov 2013 13:17:00 -0800 > > If a client passes a section of memory via file descriptor and then > subsequently truncates that file, the underlying pages will be freed > and the addresses invalidated. Subsequent accesses to the page will > fail with a SIGBUS error. > > Trap that SIGBUS, figure out which segment was causing the error and > then allocate new pages to fill in for that region. Mark the offending > shared segment as invalid and free the resource ID so that the client > will be able to tell when subsequently attempting to use the segment. > > diff --git a/os/busfault.c b/os/busfault.c > new file mode 100644 > index 0000000..05f610e > --- /dev/null > +++ b/os/busfault.c > @@ -0,0 +1,154 @@ > +/* > + * Copyright © 2013 Keith Packard > + * > + * Permission to use, copy, modify, distribute, and sell this software and > its > + * documentation for any purpose is hereby granted without fee, provided that > + * the above copyright notice appear in all copies and that both that > copyright > + * notice and this permission notice appear in supporting documentation, and > + * that the name of the copyright holders not be used in advertising or > + * publicity pertaining to distribution of the software without specific, > + * written prior permission. The copyright holders make no representations > + * about the suitability of this software for any purpose. It is provided > "as > + * is" without express or implied warranty. > + * > + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS > SOFTWARE, > + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO > + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR > + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF > USE, > + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER > + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR > PERFORMANCE > + * OF THIS SOFTWARE. > + */ > + > +#ifdef HAVE_DIX_CONFIG_H > +#include <dix-config.h> > +#endif > + > +#include <X11/Xos.h> > +#include <X11/Xdefs.h> > +#include "misc.h" > +#include <busfault.h> > +#include <list.h> > +#include <stddef.h> > +#include <stdlib.h> > +#include <stdint.h> > +#include <sys/mman.h> > +#include <signal.h> > + > +struct busfault { > + struct xorg_list list; > + > + void *addr; > + size_t size; > + > + Bool valid; > + > + busfault_notify_ptr notify; > + void *context; > +}; > + > +static Bool busfaulted; > +static struct xorg_list busfaults; > + > +struct busfault * > +busfault_register_mmap(void *addr, size_t size, busfault_notify_ptr notify, > void *context) > +{ > + struct busfault *busfault; > + > + busfault = calloc(1, sizeof (struct busfault)); > + if (!busfault) > + return NULL; > + > + busfault->addr = addr; > + busfault->size = size; > + busfault->notify = notify; > + busfault->context = context; > + busfault->valid = TRUE; > + > + xorg_list_add(&busfault->list, &busfaults); > + return busfault; > +} > + > +void > +busfault_unregister(struct busfault *busfault) > +{ > + xorg_list_del(&busfault->list); > + free(busfault); > +} > + > +void > +busfault_check(void) > +{ > + struct busfault *busfault, *tmp; > + > + if (!busfaulted) > + return; > + > + busfaulted = FALSE; > + > + xorg_list_for_each_entry_safe(busfault, tmp, &busfaults, list) { > + if (!busfault->valid) > + (*busfault->notify)(busfault->context); > + } > +} > + > +static void (*previous_busfault_sigaction)(int sig, siginfo_t *info, void > *param); > + > +static void > +busfault_sigaction(int sig, siginfo_t *info, void *param) > +{ > + void *fault = info->si_addr; > + struct busfault *busfault = NULL; > + void *new_addr; > + > + /* Locate the faulting address in our list of shared segments > + */ > + xorg_list_for_each_entry(busfault, &busfaults, list) { > + if ((char *) busfault->addr <= (char *) fault && (char *) fault < > (char *) busfault->addr + busfault->size) { > + break; > + } > + } > + if (!busfault) > + goto panic; > + > + if (!busfault->valid) > + goto panic; > + > + busfault->valid = FALSE; > + busfaulted = TRUE; > + > + /* The client truncated the file; unmap the shared file, map > + * /dev/zero over that area and keep going > + */ > + > + if (munmap(busfault->addr, busfault->size) < 0) > + goto panic; > + > + new_addr = mmap(busfault->addr, busfault->size, PROT_READ|PROT_WRITE, > MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); > + > + if (new_addr != busfault->addr) { > + munmap(new_addr, busfault->size); > + goto panic; > + }
Any reason why you're not using MAP_FIXED instead of doing this munmap/mmap dance?
_______________________________________________ [email protected]: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel
