@@ -23,7 +23,7 @@
#define STUB_START stub_start
#define STUB_CODE STUB_START
#define STUB_DATA (STUB_CODE + UM_KERN_PAGE_SIZE)
-#define STUB_END (STUB_DATA + UM_KERN_PAGE_SIZE)
+#define STUB_END (STUB_DATA + 2*UM_KERN_PAGE_SIZE)
#ifndef __ASSEMBLY__
@@ -8,10 +8,22 @@
#ifndef __STUB_DATA_H
#define __STUB_DATA_H
+#include <linux/compiler_types.h>
+#include <as-layout.h>
+
struct stub_data {
unsigned long offset;
int fd;
long parent_err, child_err;
+
+ /* 128 leaves enough room for additional fields in the struct */
+ unsigned char syscall_data[UM_KERN_PAGE_SIZE - 128] __aligned(16);
+
+ /* Stack for our signal handlers and for calling into . */
+ unsigned char sigstack[UM_KERN_PAGE_SIZE] __aligned(UM_KERN_PAGE_SIZE);
};
+typedef char stub_data_sizecheck
+ [sizeof(struct stub_data) == 2*UM_KERN_PAGE_SIZE ? 1 : -1] __always_unused;
+
#endif
@@ -24,11 +24,14 @@
void __attribute__ ((__section__ (".__syscall_stub")))
stub_clone_handler(void)
{
- struct stub_data *data = get_stub_page();
+ struct stub_data *data = get_stub_page() + UM_KERN_PAGE_SIZE;
long err;
+ /* syscall data as a temporary stack area (bottom half). */
err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD,
- (unsigned long)data + UM_KERN_PAGE_SIZE / 2);
+ (unsigned long) data->syscall_data +
+ sizeof(data->syscall_data) / 2 -
+ sizeof(void *));
if (err) {
data->parent_err = err;
goto done;
@@ -21,7 +21,7 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm)
unsigned long stack = 0;
int ret = -ENOMEM;
- stack = get_zeroed_page(GFP_KERNEL);
+ stack = __get_free_pages(GFP_KERNEL|__GFP_ZERO, 1);
if (stack == 0)
goto out;
@@ -52,7 +52,7 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm)
out_free:
if (to_mm->id.stack != 0)
- free_page(to_mm->id.stack);
+ free_pages(to_mm->id.stack, 1);
out:
return ret;
}
@@ -74,6 +74,6 @@ void destroy_context(struct mm_struct *mm)
}
os_kill_ptraced_process(mmu->id.u.pid, 1);
- free_page(mmu->id.stack);
+ free_pages(mmu->id.stack, 1);
free_ldt(mmu);
}
@@ -205,6 +205,7 @@ extern char __syscall_stub_start[];
static int userspace_tramp(void *stack)
{
struct sigaction sa;
+ struct stub_data *data;
void *addr;
int fd;
unsigned long long offset;
@@ -228,15 +229,16 @@ static int userspace_tramp(void *stack)
fd = phys_mapping(uml_to_phys(stack), &offset);
addr = mmap((void *) STUB_DATA,
- UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE,
+ sizeof(struct stub_data), PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_SHARED, fd, offset);
if (addr == MAP_FAILED) {
os_info("mapping segfault stack at 0x%lx failed, errno = %d\n",
STUB_DATA, errno);
exit(1);
}
+ data = (void *) addr;
- set_sigstack((void *) STUB_DATA, UM_KERN_PAGE_SIZE);
+ set_sigstack((void *) &data->sigstack, sizeof(data->sigstack));
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_ONSTACK | SA_NODEFER | SA_SIGINFO;
sa.sa_sigaction = (void *) segv_handler;
@@ -470,11 +472,12 @@ static int __init init_thread_regs(void)
thread_regs[REGS_IP_INDEX] = STUB_CODE +
(unsigned long) stub_clone_handler -
(unsigned long) __syscall_stub_start;
- thread_regs[REGS_SP_INDEX] = STUB_DATA + UM_KERN_PAGE_SIZE -
- sizeof(void *);
-#ifdef __SIGNAL_FRAMESIZE
- thread_regs[REGS_SP_INDEX] -= __SIGNAL_FRAMESIZE;
-#endif
+
+ /* syscall data as a temporary stack area (top half). */
+ thread_regs[REGS_SP_INDEX] = STUB_DATA +
+ offsetof(struct stub_data, syscall_data) +
+ sizeof(((struct stub_data *) 0)->syscall_data) -
+ sizeof(void *);
return 0;
}
@@ -87,6 +87,7 @@ static __always_inline void trap_myself(void)
static __always_inline void remap_stack_and_trap(void)
{
+ /* The stack here is in syscall data (i.e. on the first page) */
__asm__ volatile (
"movl %%esp,%%ebx ;"
"andl %0,%%ebx ;"
@@ -102,7 +103,7 @@ static __always_inline void remap_stack_and_trap(void)
"g" (offsetof(struct stub_data, fd)),
"g" (offsetof(struct stub_data, offset)),
"g" (offsetof(struct stub_data, child_err)),
- "c" (UM_KERN_PAGE_SIZE),
+ "c" (2*UM_KERN_PAGE_SIZE),
"d" (PROT_READ | PROT_WRITE),
"S" (MAP_FIXED | MAP_SHARED)
:
@@ -87,6 +87,7 @@ static __always_inline void trap_myself(void)
static __always_inline void remap_stack_and_trap(void)
{
+ /* The stack here is in syscall data (i.e. on the first page) */
__asm__ volatile (
"movq %0,%%rax ;"
"movq %%rsp,%%rdi ;"
@@ -105,7 +106,7 @@ static __always_inline void remap_stack_and_trap(void)
"g" (offsetof(struct stub_data, fd)),
"g" (offsetof(struct stub_data, offset)),
"g" (offsetof(struct stub_data, child_err)),
- "S" (UM_KERN_PAGE_SIZE),
+ "S" (2*UM_KERN_PAGE_SIZE),
"d" (PROT_READ | PROT_WRITE)
:
__syscall_clobber, "r10", "r8", "r9");
@@ -121,6 +122,6 @@ static __always_inline void *get_stub_page(void)
: "=a" (ret)
: "g" (~(UM_KERN_PAGE_SIZE - 1)));
- return (void *)ret;
+ return (void *)ret - UM_KERN_PAGE_SIZE;
}
#endif