mem.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  4. */
  5. #include <stdio.h>
  6. #include <stddef.h>
  7. #include <stdlib.h>
  8. #include <unistd.h>
  9. #include <errno.h>
  10. #include <fcntl.h>
  11. #include <string.h>
  12. #include <sys/stat.h>
  13. #include <sys/mman.h>
  14. #include <sys/vfs.h>
  15. #include <linux/magic.h>
  16. #include <init.h>
  17. #include <kern_util.h>
  18. #include <os.h>
  19. #include "internal.h"
  20. /*
  21. * kasan_map_memory - maps memory from @start with a size of @len.
  22. * The allocated memory is filled with zeroes upon success.
  23. * @start: the start address of the memory to be mapped
  24. * @len: the length of the memory to be mapped
  25. *
  26. * This function is used to map shadow memory for KASAN in uml
  27. */
  28. void kasan_map_memory(void *start, size_t len)
  29. {
  30. if (mmap(start,
  31. len,
  32. PROT_READ|PROT_WRITE,
  33. MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE,
  34. -1,
  35. 0) == MAP_FAILED) {
  36. os_info("Couldn't allocate shadow memory: %s\n.",
  37. strerror(errno));
  38. exit(1);
  39. }
  40. if (madvise(start, len, MADV_DONTDUMP)) {
  41. os_info("Couldn't set MAD_DONTDUMP on shadow memory: %s\n.",
  42. strerror(errno));
  43. exit(1);
  44. }
  45. if (madvise(start, len, MADV_DONTFORK)) {
  46. os_info("Couldn't set MADV_DONTFORK on shadow memory: %s\n.",
  47. strerror(errno));
  48. exit(1);
  49. }
  50. }
  51. /* Set by make_tempfile() during early boot. */
  52. char *tempdir = NULL;
  53. /* Check if dir is on tmpfs. Return 0 if yes, -1 if no or error. */
  54. static int __init check_tmpfs(const char *dir)
  55. {
  56. struct statfs st;
  57. os_info("Checking if %s is on tmpfs...", dir);
  58. if (statfs(dir, &st) < 0) {
  59. os_info("%s\n", strerror(errno));
  60. } else if (st.f_type != TMPFS_MAGIC) {
  61. os_info("no\n");
  62. } else {
  63. os_info("OK\n");
  64. return 0;
  65. }
  66. return -1;
  67. }
  68. /*
  69. * Choose the tempdir to use. We want something on tmpfs so that our memory is
  70. * not subject to the host's vm.dirty_ratio. If a tempdir is specified in the
  71. * environment, we use that even if it's not on tmpfs, but we warn the user.
  72. * Otherwise, we try common tmpfs locations, and if no tmpfs directory is found
  73. * then we fall back to /tmp.
  74. */
  75. static char * __init choose_tempdir(void)
  76. {
  77. static const char * const vars[] = {
  78. "TMPDIR",
  79. "TMP",
  80. "TEMP",
  81. NULL
  82. };
  83. static const char fallback_dir[] = "/tmp";
  84. static const char * const tmpfs_dirs[] = {
  85. "/dev/shm",
  86. fallback_dir,
  87. NULL
  88. };
  89. int i;
  90. const char *dir;
  91. os_info("Checking environment variables for a tempdir...");
  92. for (i = 0; vars[i]; i++) {
  93. dir = getenv(vars[i]);
  94. if ((dir != NULL) && (*dir != '\0')) {
  95. os_info("%s\n", dir);
  96. if (check_tmpfs(dir) >= 0)
  97. goto done;
  98. else
  99. goto warn;
  100. }
  101. }
  102. os_info("none found\n");
  103. for (i = 0; tmpfs_dirs[i]; i++) {
  104. dir = tmpfs_dirs[i];
  105. if (check_tmpfs(dir) >= 0)
  106. goto done;
  107. }
  108. dir = fallback_dir;
  109. warn:
  110. os_warn("Warning: tempdir %s is not on tmpfs\n", dir);
  111. done:
  112. /* Make a copy since getenv results may not remain valid forever. */
  113. return strdup(dir);
  114. }
  115. /*
  116. * Create an unlinked tempfile in a suitable tempdir. template must be the
  117. * basename part of the template with a leading '/'.
  118. */
  119. static int __init make_tempfile(const char *template)
  120. {
  121. char *tempname;
  122. int fd;
  123. if (tempdir == NULL) {
  124. tempdir = choose_tempdir();
  125. if (tempdir == NULL) {
  126. os_warn("Failed to choose tempdir: %s\n",
  127. strerror(errno));
  128. return -1;
  129. }
  130. }
  131. #ifdef O_TMPFILE
  132. fd = open(tempdir, O_CLOEXEC | O_RDWR | O_EXCL | O_TMPFILE, 0700);
  133. /*
  134. * If the running system does not support O_TMPFILE flag then retry
  135. * without it.
  136. */
  137. if (fd != -1 || (errno != EINVAL && errno != EISDIR &&
  138. errno != EOPNOTSUPP))
  139. return fd;
  140. #endif
  141. tempname = malloc(strlen(tempdir) + strlen(template) + 1);
  142. if (tempname == NULL)
  143. return -1;
  144. strcpy(tempname, tempdir);
  145. strcat(tempname, template);
  146. fd = mkstemp(tempname);
  147. if (fd < 0) {
  148. os_warn("open - cannot create %s: %s\n", tempname,
  149. strerror(errno));
  150. goto out;
  151. }
  152. if (unlink(tempname) < 0) {
  153. perror("unlink");
  154. goto close;
  155. }
  156. free(tempname);
  157. return fd;
  158. close:
  159. close(fd);
  160. out:
  161. free(tempname);
  162. return -1;
  163. }
  164. #define TEMPNAME_TEMPLATE "/vm_file-XXXXXX"
  165. static int __init create_tmp_file(unsigned long long len)
  166. {
  167. int fd, err;
  168. char zero;
  169. fd = make_tempfile(TEMPNAME_TEMPLATE);
  170. if (fd < 0)
  171. exit(1);
  172. /*
  173. * Seek to len - 1 because writing a character there will
  174. * increase the file size by one byte, to the desired length.
  175. */
  176. if (lseek64(fd, len - 1, SEEK_SET) < 0) {
  177. perror("lseek64");
  178. exit(1);
  179. }
  180. zero = 0;
  181. err = write(fd, &zero, 1);
  182. if (err != 1) {
  183. perror("write");
  184. exit(1);
  185. }
  186. return fd;
  187. }
  188. int __init create_mem_file(unsigned long long len)
  189. {
  190. int err, fd;
  191. fd = create_tmp_file(len);
  192. err = os_set_exec_close(fd);
  193. if (err < 0) {
  194. errno = -err;
  195. perror("exec_close");
  196. }
  197. return fd;
  198. }
  199. void __init check_tmpexec(void)
  200. {
  201. void *addr;
  202. int err, fd = create_tmp_file(UM_KERN_PAGE_SIZE);
  203. addr = mmap(NULL, UM_KERN_PAGE_SIZE,
  204. PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0);
  205. os_info("Checking PROT_EXEC mmap in %s...", tempdir);
  206. if (addr == MAP_FAILED) {
  207. err = errno;
  208. os_warn("%s\n", strerror(err));
  209. close(fd);
  210. if (err == EPERM)
  211. os_warn("%s must be not mounted noexec\n", tempdir);
  212. exit(1);
  213. }
  214. os_info("OK\n");
  215. munmap(addr, UM_KERN_PAGE_SIZE);
  216. close(fd);
  217. }