busfault.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  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. #ifdef HAVE_DIX_CONFIG_H
  23. #include <dix-config.h>
  24. #endif
  25. #include <X11/Xos.h>
  26. #include <X11/Xdefs.h>
  27. #include "misc.h"
  28. #include <busfault.h>
  29. #include <list.h>
  30. #include <stddef.h>
  31. #include <stdlib.h>
  32. #include <stdint.h>
  33. #include <sys/mman.h>
  34. #include <signal.h>
  35. struct busfault {
  36. struct xorg_list list;
  37. void *addr;
  38. size_t size;
  39. Bool valid;
  40. busfault_notify_ptr notify;
  41. void *context;
  42. };
  43. static Bool busfaulted;
  44. static struct xorg_list busfaults;
  45. struct busfault *
  46. busfault_register_mmap(void *addr, size_t size, busfault_notify_ptr notify, void *context)
  47. {
  48. struct busfault *busfault;
  49. busfault = calloc(1, sizeof (struct busfault));
  50. if (!busfault)
  51. return NULL;
  52. busfault->addr = addr;
  53. busfault->size = size;
  54. busfault->notify = notify;
  55. busfault->context = context;
  56. busfault->valid = TRUE;
  57. xorg_list_add(&busfault->list, &busfaults);
  58. return busfault;
  59. }
  60. void
  61. busfault_unregister(struct busfault *busfault)
  62. {
  63. xorg_list_del(&busfault->list);
  64. free(busfault);
  65. }
  66. void
  67. busfault_check(void)
  68. {
  69. struct busfault *busfault, *tmp;
  70. if (!busfaulted)
  71. return;
  72. busfaulted = FALSE;
  73. xorg_list_for_each_entry_safe(busfault, tmp, &busfaults, list) {
  74. if (!busfault->valid)
  75. (*busfault->notify)(busfault->context);
  76. }
  77. }
  78. static void (*previous_busfault_sigaction)(int sig, siginfo_t *info, void *param);
  79. static void
  80. busfault_sigaction(int sig, siginfo_t *info, void *param)
  81. {
  82. void *fault = info->si_addr;
  83. struct busfault *busfault = NULL;
  84. void *new_addr;
  85. /* Locate the faulting address in our list of shared segments
  86. */
  87. xorg_list_for_each_entry(busfault, &busfaults, list) {
  88. if ((char *) busfault->addr <= (char *) fault && (char *) fault < (char *) busfault->addr + busfault->size) {
  89. break;
  90. }
  91. }
  92. if (!busfault)
  93. goto panic;
  94. if (!busfault->valid)
  95. goto panic;
  96. busfault->valid = FALSE;
  97. busfaulted = TRUE;
  98. /* The client truncated the file; unmap the shared file, map
  99. * /dev/zero over that area and keep going
  100. */
  101. new_addr = mmap(busfault->addr, busfault->size, PROT_READ|PROT_WRITE,
  102. MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
  103. if (new_addr == MAP_FAILED)
  104. goto panic;
  105. return;
  106. panic:
  107. if (previous_busfault_sigaction)
  108. (*previous_busfault_sigaction)(sig, info, param);
  109. else
  110. FatalError("bus error");
  111. }
  112. Bool
  113. busfault_init(void)
  114. {
  115. struct sigaction act, old_act;
  116. act.sa_sigaction = busfault_sigaction;
  117. act.sa_flags = SA_SIGINFO;
  118. sigemptyset(&act.sa_mask);
  119. if (sigaction(SIGBUS, &act, &old_act) < 0)
  120. return FALSE;
  121. previous_busfault_sigaction = old_act.sa_sigaction;
  122. xorg_list_init(&busfaults);
  123. return TRUE;
  124. }