mem.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2021 Benjamin Berg <benjamin@sipsolutions.net>
  4. * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  5. */
  6. #include <stddef.h>
  7. #include <unistd.h>
  8. #include <errno.h>
  9. #include <string.h>
  10. #include <sys/mman.h>
  11. #include <init.h>
  12. #include <as-layout.h>
  13. #include <mm_id.h>
  14. #include <os.h>
  15. #include <ptrace_user.h>
  16. #include <registers.h>
  17. #include <skas.h>
  18. #include <sysdep/ptrace.h>
  19. #include <sysdep/stub.h>
  20. #include "../internal.h"
  21. extern char __syscall_stub_start[];
  22. void syscall_stub_dump_error(struct mm_id *mm_idp)
  23. {
  24. struct stub_data *proc_data = (void *)mm_idp->stack;
  25. struct stub_syscall *sc;
  26. if (proc_data->syscall_data_len < 0 ||
  27. proc_data->syscall_data_len >= ARRAY_SIZE(proc_data->syscall_data))
  28. panic("Syscall data was corrupted by stub (len is: %d, expected maximum: %d)!",
  29. proc_data->syscall_data_len,
  30. mm_idp->syscall_data_len);
  31. sc = &proc_data->syscall_data[proc_data->syscall_data_len];
  32. printk(UM_KERN_ERR "%s : length = %d, last offset = %d",
  33. __func__, mm_idp->syscall_data_len,
  34. proc_data->syscall_data_len);
  35. printk(UM_KERN_ERR "%s : stub syscall type %d failed, return value = 0x%lx\n",
  36. __func__, sc->syscall, proc_data->err);
  37. print_hex_dump(UM_KERN_ERR, " syscall data: ", 0,
  38. 16, 4, sc, sizeof(*sc), 0);
  39. if (using_seccomp) {
  40. printk(UM_KERN_ERR "%s: FD map num: %d", __func__,
  41. mm_idp->syscall_fd_num);
  42. print_hex_dump(UM_KERN_ERR,
  43. " FD map: ", 0, 16,
  44. sizeof(mm_idp->syscall_fd_map[0]),
  45. mm_idp->syscall_fd_map,
  46. sizeof(mm_idp->syscall_fd_map), 0);
  47. }
  48. }
  49. static inline unsigned long *check_init_stack(struct mm_id * mm_idp,
  50. unsigned long *stack)
  51. {
  52. if (stack == NULL) {
  53. stack = (unsigned long *) mm_idp->stack + 2;
  54. *stack = 0;
  55. }
  56. return stack;
  57. }
  58. static unsigned long syscall_regs[MAX_REG_NR];
  59. static int __init init_syscall_regs(void)
  60. {
  61. get_safe_registers(syscall_regs, NULL);
  62. syscall_regs[REGS_IP_INDEX] = STUB_CODE +
  63. ((unsigned long) stub_syscall_handler -
  64. (unsigned long) __syscall_stub_start);
  65. syscall_regs[REGS_SP_INDEX] = STUB_DATA +
  66. offsetof(struct stub_data, sigstack) +
  67. sizeof(((struct stub_data *) 0)->sigstack) -
  68. sizeof(void *);
  69. return 0;
  70. }
  71. __initcall(init_syscall_regs);
  72. static inline long do_syscall_stub(struct mm_id *mm_idp)
  73. {
  74. struct stub_data *proc_data = (void *)mm_idp->stack;
  75. int n, i;
  76. int err, pid = mm_idp->pid;
  77. /* Inform process how much we have filled in. */
  78. proc_data->syscall_data_len = mm_idp->syscall_data_len;
  79. if (using_seccomp) {
  80. proc_data->restart_wait = 1;
  81. wait_stub_done_seccomp(mm_idp, 0, 1);
  82. } else {
  83. n = ptrace_setregs(pid, syscall_regs);
  84. if (n < 0) {
  85. printk(UM_KERN_ERR "Registers -\n");
  86. for (i = 0; i < MAX_REG_NR; i++)
  87. printk(UM_KERN_ERR "\t%d\t0x%lx\n", i, syscall_regs[i]);
  88. panic("%s : PTRACE_SETREGS failed, errno = %d\n",
  89. __func__, -n);
  90. }
  91. err = ptrace(PTRACE_CONT, pid, 0, 0);
  92. if (err)
  93. panic("Failed to continue stub, pid = %d, errno = %d\n",
  94. pid, errno);
  95. wait_stub_done(pid);
  96. }
  97. /*
  98. * proc_data->err will be negative if there was an (unexpected) error.
  99. * In that case, syscall_data_len points to the last executed syscall,
  100. * otherwise it will be zero (but we do not need to rely on that).
  101. */
  102. if (proc_data->err < 0) {
  103. syscall_stub_dump_error(mm_idp);
  104. /* Store error code in case someone tries to add more syscalls */
  105. mm_idp->syscall_data_len = proc_data->err;
  106. } else {
  107. mm_idp->syscall_data_len = 0;
  108. }
  109. if (using_seccomp)
  110. mm_idp->syscall_fd_num = 0;
  111. return mm_idp->syscall_data_len;
  112. }
  113. int syscall_stub_flush(struct mm_id *mm_idp)
  114. {
  115. int res;
  116. if (mm_idp->syscall_data_len == 0)
  117. return 0;
  118. /* If an error happened already, report it and reset the state. */
  119. if (mm_idp->syscall_data_len < 0) {
  120. res = mm_idp->syscall_data_len;
  121. mm_idp->syscall_data_len = 0;
  122. return res;
  123. }
  124. res = do_syscall_stub(mm_idp);
  125. mm_idp->syscall_data_len = 0;
  126. return res;
  127. }
  128. struct stub_syscall *syscall_stub_alloc(struct mm_id *mm_idp)
  129. {
  130. struct stub_syscall *sc;
  131. struct stub_data *proc_data = (struct stub_data *) mm_idp->stack;
  132. if (mm_idp->syscall_data_len > 0 &&
  133. mm_idp->syscall_data_len == ARRAY_SIZE(proc_data->syscall_data))
  134. do_syscall_stub(mm_idp);
  135. if (mm_idp->syscall_data_len < 0) {
  136. /* Return dummy to retain error state. */
  137. sc = &proc_data->syscall_data[0];
  138. } else {
  139. sc = &proc_data->syscall_data[mm_idp->syscall_data_len];
  140. mm_idp->syscall_data_len += 1;
  141. }
  142. memset(sc, 0, sizeof(*sc));
  143. return sc;
  144. }
  145. static struct stub_syscall *syscall_stub_get_previous(struct mm_id *mm_idp,
  146. int syscall_type,
  147. unsigned long virt)
  148. {
  149. if (mm_idp->syscall_data_len > 0) {
  150. struct stub_data *proc_data = (void *) mm_idp->stack;
  151. struct stub_syscall *sc;
  152. sc = &proc_data->syscall_data[mm_idp->syscall_data_len - 1];
  153. if (sc->syscall == syscall_type &&
  154. sc->mem.addr + sc->mem.length == virt)
  155. return sc;
  156. }
  157. return NULL;
  158. }
  159. static int get_stub_fd(struct mm_id *mm_idp, int fd)
  160. {
  161. int i;
  162. /* Find an FD slot (or flush and use first) */
  163. if (!using_seccomp)
  164. return fd;
  165. /* Already crashed, value does not matter */
  166. if (mm_idp->syscall_data_len < 0)
  167. return 0;
  168. /* Find existing FD in map if we can allocate another syscall */
  169. if (mm_idp->syscall_data_len <
  170. ARRAY_SIZE(((struct stub_data *)NULL)->syscall_data)) {
  171. for (i = 0; i < mm_idp->syscall_fd_num; i++) {
  172. if (mm_idp->syscall_fd_map[i] == fd)
  173. return i;
  174. }
  175. if (mm_idp->syscall_fd_num < STUB_MAX_FDS) {
  176. i = mm_idp->syscall_fd_num;
  177. mm_idp->syscall_fd_map[i] = fd;
  178. mm_idp->syscall_fd_num++;
  179. return i;
  180. }
  181. }
  182. /* FD map full or no syscall space available, continue after flush */
  183. do_syscall_stub(mm_idp);
  184. mm_idp->syscall_fd_map[0] = fd;
  185. mm_idp->syscall_fd_num = 1;
  186. return 0;
  187. }
  188. int map(struct mm_id *mm_idp, unsigned long virt, unsigned long len, int prot,
  189. int phys_fd, unsigned long long offset)
  190. {
  191. struct stub_syscall *sc;
  192. /* Compress with previous syscall if that is possible */
  193. sc = syscall_stub_get_previous(mm_idp, STUB_SYSCALL_MMAP, virt);
  194. if (sc && sc->mem.prot == prot &&
  195. sc->mem.offset == MMAP_OFFSET(offset - sc->mem.length)) {
  196. int prev_fd = sc->mem.fd;
  197. if (using_seccomp)
  198. prev_fd = mm_idp->syscall_fd_map[sc->mem.fd];
  199. if (phys_fd == prev_fd) {
  200. sc->mem.length += len;
  201. return 0;
  202. }
  203. }
  204. phys_fd = get_stub_fd(mm_idp, phys_fd);
  205. sc = syscall_stub_alloc(mm_idp);
  206. sc->syscall = STUB_SYSCALL_MMAP;
  207. sc->mem.addr = virt;
  208. sc->mem.length = len;
  209. sc->mem.prot = prot;
  210. sc->mem.fd = phys_fd;
  211. sc->mem.offset = MMAP_OFFSET(offset);
  212. return 0;
  213. }
  214. int unmap(struct mm_id *mm_idp, unsigned long addr, unsigned long len)
  215. {
  216. struct stub_syscall *sc;
  217. /* Compress with previous syscall if that is possible */
  218. sc = syscall_stub_get_previous(mm_idp, STUB_SYSCALL_MUNMAP, addr);
  219. if (sc) {
  220. sc->mem.length += len;
  221. return 0;
  222. }
  223. sc = syscall_stub_alloc(mm_idp);
  224. sc->syscall = STUB_SYSCALL_MUNMAP;
  225. sc->mem.addr = addr;
  226. sc->mem.length = len;
  227. return 0;
  228. }