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