aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/os-Linux/process.c
diff options
context:
space:
mode:
authorRichard Weinberger <richard@nod.at>2013-08-17 12:46:00 -0400
committerRichard Weinberger <richard@nod.at>2013-09-07 04:38:34 -0400
commitf75b1b1bedfb498cc43a992ce4d7ed8df3b1e770 (patch)
treee7afc9647b9cc80fb95ee9dae7d9532b67efdc01 /arch/um/os-Linux/process.c
parent65984ff9d2179a97e5a11aaef1e86fdb276cfad5 (diff)
um: Implement probe_kernel_read()
UML needs it's own probe_kernel_read() to handle kernel mode faults correctly. The implementation uses mincore() on the host side to detect whether a page is owned by the UML kernel process. This fixes also a possible crash when sysrq-t is used. Starting with 3.10 sysrq-t calls probe_kernel_read() to read details from the kernel workers. As kernel worker are completely async pointers may turn NULL while reading them. Cc: <stian@nixia.no> Cc: <tj@kernel.org> Cc: <stable@vger.kernel.org> # 3.10.x Signed-off-by: Richard Weinberger <richard@nod.at>
Diffstat (limited to 'arch/um/os-Linux/process.c')
-rw-r--r--arch/um/os-Linux/process.c52
1 files changed, 52 insertions, 0 deletions
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c
index b8f34c9e53ae..67b9c8f5a89e 100644
--- a/arch/um/os-Linux/process.c
+++ b/arch/um/os-Linux/process.c
@@ -4,6 +4,7 @@
4 */ 4 */
5 5
6#include <stdio.h> 6#include <stdio.h>
7#include <stdlib.h>
7#include <unistd.h> 8#include <unistd.h>
8#include <errno.h> 9#include <errno.h>
9#include <signal.h> 10#include <signal.h>
@@ -232,6 +233,57 @@ out:
232 return ok; 233 return ok;
233} 234}
234 235
236static int os_page_mincore(void *addr)
237{
238 char vec[2];
239 int ret;
240
241 ret = mincore(addr, UM_KERN_PAGE_SIZE, vec);
242 if (ret < 0) {
243 if (errno == ENOMEM || errno == EINVAL)
244 return 0;
245 else
246 return -errno;
247 }
248
249 return vec[0] & 1;
250}
251
252int os_mincore(void *addr, unsigned long len)
253{
254 char *vec;
255 int ret, i;
256
257 if (len <= UM_KERN_PAGE_SIZE)
258 return os_page_mincore(addr);
259
260 vec = calloc(1, (len + UM_KERN_PAGE_SIZE - 1) / UM_KERN_PAGE_SIZE);
261 if (!vec)
262 return -ENOMEM;
263
264 ret = mincore(addr, UM_KERN_PAGE_SIZE, vec);
265 if (ret < 0) {
266 if (errno == ENOMEM || errno == EINVAL)
267 ret = 0;
268 else
269 ret = -errno;
270
271 goto out;
272 }
273
274 for (i = 0; i < ((len + UM_KERN_PAGE_SIZE - 1) / UM_KERN_PAGE_SIZE); i++) {
275 if (!(vec[i] & 1)) {
276 ret = 0;
277 goto out;
278 }
279 }
280
281 ret = 1;
282out:
283 free(vec);
284 return ret;
285}
286
235void init_new_thread_signals(void) 287void init_new_thread_signals(void)
236{ 288{
237 set_handler(SIGSEGV); 289 set_handler(SIGSEGV);