[PATCH] uml: increase granularity of host capability checking
This change enables SKAS0/SKAS3 to work with all combinations of /proc/mm and PTRACE_FAULTINFO being available or not. Also it changes the initialization of proc_mm and ptrace_faultinfo slightly, to ease forcing SKAS0 on a patched host. Forcing UML to run without /proc/mm or PTRACE_FAULTINFO by cmdline parameter can be implemented with a setup resetting the related variable. Signed-off-by: Bodo Stroesser <bstroesser@fujitsu-siemens.com> Signed-off-by: Jeff Dike <jdike@addtoit.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
60d339f6fe
commit
8b51304ed3
@ -33,7 +33,7 @@ extern void *protect(struct mm_id * mm_idp, unsigned long addr,
|
|||||||
unsigned long len, int r, int w, int x, int done,
|
unsigned long len, int r, int w, int x, int done,
|
||||||
void *data);
|
void *data);
|
||||||
extern void user_signal(int sig, union uml_pt_regs *regs, int pid);
|
extern void user_signal(int sig, union uml_pt_regs *regs, int pid);
|
||||||
extern int new_mm(int from);
|
extern int new_mm(int from, unsigned long stack);
|
||||||
extern int start_userspace(unsigned long stub_stack);
|
extern int start_userspace(unsigned long stub_stack);
|
||||||
extern int copy_context_skas0(unsigned long stack, int pid);
|
extern int copy_context_skas0(unsigned long stack, int pid);
|
||||||
extern void get_skas_faultinfo(int pid, struct faultinfo * fi);
|
extern void get_skas_faultinfo(int pid, struct faultinfo * fi);
|
||||||
|
@ -77,23 +77,14 @@ int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
|
|||||||
struct mm_struct *cur_mm = current->mm;
|
struct mm_struct *cur_mm = current->mm;
|
||||||
struct mm_id *cur_mm_id = &cur_mm->context.skas.id;
|
struct mm_id *cur_mm_id = &cur_mm->context.skas.id;
|
||||||
struct mm_id *mm_id = &mm->context.skas.id;
|
struct mm_id *mm_id = &mm->context.skas.id;
|
||||||
unsigned long stack;
|
unsigned long stack = 0;
|
||||||
int from, ret;
|
int from, ret = -ENOMEM;
|
||||||
|
|
||||||
if(proc_mm){
|
if(!proc_mm || !ptrace_faultinfo){
|
||||||
if((cur_mm != NULL) && (cur_mm != &init_mm))
|
stack = get_zeroed_page(GFP_KERNEL);
|
||||||
from = cur_mm->context.skas.id.u.mm_fd;
|
if(stack == 0)
|
||||||
else from = -1;
|
goto out;
|
||||||
|
|
||||||
ret = new_mm(from);
|
|
||||||
if(ret < 0){
|
|
||||||
printk("init_new_context_skas - new_mm failed, "
|
|
||||||
"errno = %d\n", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
mm_id->u.mm_fd = ret;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* This zeros the entry that pgd_alloc didn't, needed since
|
/* This zeros the entry that pgd_alloc didn't, needed since
|
||||||
* we are about to reinitialize it, and want mm.nr_ptes to
|
* we are about to reinitialize it, and want mm.nr_ptes to
|
||||||
* be accurate.
|
* be accurate.
|
||||||
@ -103,20 +94,30 @@ int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
|
|||||||
ret = init_stub_pte(mm, CONFIG_STUB_CODE,
|
ret = init_stub_pte(mm, CONFIG_STUB_CODE,
|
||||||
(unsigned long) &__syscall_stub_start);
|
(unsigned long) &__syscall_stub_start);
|
||||||
if(ret)
|
if(ret)
|
||||||
goto out;
|
goto out_free;
|
||||||
|
|
||||||
ret = -ENOMEM;
|
|
||||||
stack = get_zeroed_page(GFP_KERNEL);
|
|
||||||
if(stack == 0)
|
|
||||||
goto out;
|
|
||||||
mm_id->stack = stack;
|
|
||||||
|
|
||||||
ret = init_stub_pte(mm, CONFIG_STUB_DATA, stack);
|
ret = init_stub_pte(mm, CONFIG_STUB_DATA, stack);
|
||||||
if(ret)
|
if(ret)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
|
|
||||||
mm->nr_ptes--;
|
mm->nr_ptes--;
|
||||||
|
}
|
||||||
|
mm_id->stack = stack;
|
||||||
|
|
||||||
|
if(proc_mm){
|
||||||
|
if((cur_mm != NULL) && (cur_mm != &init_mm))
|
||||||
|
from = cur_mm_id->u.mm_fd;
|
||||||
|
else from = -1;
|
||||||
|
|
||||||
|
ret = new_mm(from, stack);
|
||||||
|
if(ret < 0){
|
||||||
|
printk("init_new_context_skas - new_mm failed, "
|
||||||
|
"errno = %d\n", ret);
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
mm_id->u.mm_fd = ret;
|
||||||
|
}
|
||||||
|
else {
|
||||||
if((cur_mm != NULL) && (cur_mm != &init_mm))
|
if((cur_mm != NULL) && (cur_mm != &init_mm))
|
||||||
mm_id->u.pid = copy_context_skas0(stack,
|
mm_id->u.pid = copy_context_skas0(stack,
|
||||||
cur_mm_id->u.pid);
|
cur_mm_id->u.pid);
|
||||||
@ -126,7 +127,8 @@ int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_free:
|
out_free:
|
||||||
free_page(mm_id->stack);
|
if(mm_id->stack != 0)
|
||||||
|
free_page(mm_id->stack);
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -137,8 +139,10 @@ void destroy_context_skas(struct mm_struct *mm)
|
|||||||
|
|
||||||
if(proc_mm)
|
if(proc_mm)
|
||||||
os_close_file(mmu->id.u.mm_fd);
|
os_close_file(mmu->id.u.mm_fd);
|
||||||
else {
|
else
|
||||||
os_kill_ptraced_process(mmu->id.u.pid, 1);
|
os_kill_ptraced_process(mmu->id.u.pid, 1);
|
||||||
|
|
||||||
|
if(!proc_mm || !ptrace_faultinfo){
|
||||||
free_page(mmu->id.stack);
|
free_page(mmu->id.stack);
|
||||||
free_page(mmu->last_page_table);
|
free_page(mmu->last_page_table);
|
||||||
}
|
}
|
||||||
|
@ -138,6 +138,8 @@ static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern int __syscall_stub_start;
|
extern int __syscall_stub_start;
|
||||||
|
int stub_code_fd = -1;
|
||||||
|
__u64 stub_code_offset;
|
||||||
|
|
||||||
static int userspace_tramp(void *stack)
|
static int userspace_tramp(void *stack)
|
||||||
{
|
{
|
||||||
@ -152,31 +154,31 @@ static int userspace_tramp(void *stack)
|
|||||||
/* This has a pte, but it can't be mapped in with the usual
|
/* This has a pte, but it can't be mapped in with the usual
|
||||||
* tlb_flush mechanism because this is part of that mechanism
|
* tlb_flush mechanism because this is part of that mechanism
|
||||||
*/
|
*/
|
||||||
int fd;
|
|
||||||
__u64 offset;
|
|
||||||
|
|
||||||
fd = phys_mapping(to_phys(&__syscall_stub_start), &offset);
|
|
||||||
addr = mmap64((void *) UML_CONFIG_STUB_CODE, page_size(),
|
addr = mmap64((void *) UML_CONFIG_STUB_CODE, page_size(),
|
||||||
PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset);
|
PROT_EXEC, MAP_FIXED | MAP_PRIVATE,
|
||||||
|
stub_code_fd, stub_code_offset);
|
||||||
if(addr == MAP_FAILED){
|
if(addr == MAP_FAILED){
|
||||||
printk("mapping mmap stub failed, errno = %d\n",
|
printk("mapping stub code failed, errno = %d\n",
|
||||||
errno);
|
errno);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(stack != NULL){
|
if(stack != NULL){
|
||||||
|
int fd;
|
||||||
|
__u64 offset;
|
||||||
|
|
||||||
fd = phys_mapping(to_phys(stack), &offset);
|
fd = phys_mapping(to_phys(stack), &offset);
|
||||||
addr = mmap((void *) UML_CONFIG_STUB_DATA, page_size(),
|
addr = mmap((void *) UML_CONFIG_STUB_DATA, page_size(),
|
||||||
PROT_READ | PROT_WRITE,
|
PROT_READ | PROT_WRITE,
|
||||||
MAP_FIXED | MAP_SHARED, fd, offset);
|
MAP_FIXED | MAP_SHARED, fd, offset);
|
||||||
if(addr == MAP_FAILED){
|
if(addr == MAP_FAILED){
|
||||||
printk("mapping segfault stack failed, "
|
printk("mapping stub stack failed, "
|
||||||
"errno = %d\n", errno);
|
"errno = %d\n", errno);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!ptrace_faultinfo && (stack != NULL)){
|
if(!ptrace_faultinfo){
|
||||||
unsigned long v = UML_CONFIG_STUB_CODE +
|
unsigned long v = UML_CONFIG_STUB_CODE +
|
||||||
(unsigned long) stub_segv_handler -
|
(unsigned long) stub_segv_handler -
|
||||||
(unsigned long) &__syscall_stub_start;
|
(unsigned long) &__syscall_stub_start;
|
||||||
@ -202,6 +204,10 @@ int start_userspace(unsigned long stub_stack)
|
|||||||
unsigned long sp;
|
unsigned long sp;
|
||||||
int pid, status, n, flags;
|
int pid, status, n, flags;
|
||||||
|
|
||||||
|
if ( stub_code_fd == -1 )
|
||||||
|
stub_code_fd = phys_mapping(to_phys(&__syscall_stub_start),
|
||||||
|
&stub_code_offset);
|
||||||
|
|
||||||
stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
|
stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
if(stack == MAP_FAILED)
|
if(stack == MAP_FAILED)
|
||||||
@ -363,6 +369,53 @@ int copy_context_skas0(unsigned long new_stack, int pid)
|
|||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is used only, if proc_mm is available, while PTRACE_FAULTINFO
|
||||||
|
* isn't. Opening /proc/mm creates a new mm_context, which lacks the stub-pages
|
||||||
|
* Thus, we map them using /proc/mm-fd
|
||||||
|
*/
|
||||||
|
void map_stub_pages(int fd, unsigned long code,
|
||||||
|
unsigned long data, unsigned long stack)
|
||||||
|
{
|
||||||
|
struct proc_mm_op mmop;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
mmop = ((struct proc_mm_op) { .op = MM_MMAP,
|
||||||
|
.u =
|
||||||
|
{ .mmap =
|
||||||
|
{ .addr = code,
|
||||||
|
.len = PAGE_SIZE,
|
||||||
|
.prot = PROT_EXEC,
|
||||||
|
.flags = MAP_FIXED | MAP_PRIVATE,
|
||||||
|
.fd = stub_code_fd,
|
||||||
|
.offset = stub_code_offset
|
||||||
|
} } });
|
||||||
|
n = os_write_file(fd, &mmop, sizeof(mmop));
|
||||||
|
if(n != sizeof(mmop))
|
||||||
|
panic("map_stub_pages : /proc/mm map for code failed, "
|
||||||
|
"err = %d\n", -n);
|
||||||
|
|
||||||
|
if ( stack ) {
|
||||||
|
__u64 map_offset;
|
||||||
|
int map_fd = phys_mapping(to_phys((void *)stack), &map_offset);
|
||||||
|
mmop = ((struct proc_mm_op)
|
||||||
|
{ .op = MM_MMAP,
|
||||||
|
.u =
|
||||||
|
{ .mmap =
|
||||||
|
{ .addr = data,
|
||||||
|
.len = PAGE_SIZE,
|
||||||
|
.prot = PROT_READ | PROT_WRITE,
|
||||||
|
.flags = MAP_FIXED | MAP_SHARED,
|
||||||
|
.fd = map_fd,
|
||||||
|
.offset = map_offset
|
||||||
|
} } });
|
||||||
|
n = os_write_file(fd, &mmop, sizeof(mmop));
|
||||||
|
if(n != sizeof(mmop))
|
||||||
|
panic("map_stub_pages : /proc/mm map for data failed, "
|
||||||
|
"err = %d\n", -n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
|
void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
|
||||||
void (*handler)(int))
|
void (*handler)(int))
|
||||||
{
|
{
|
||||||
|
@ -129,7 +129,9 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp,
|
|||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int new_mm(int from)
|
extern void map_stub_pages(int fd, unsigned long code,
|
||||||
|
unsigned long data, unsigned long stack);
|
||||||
|
int new_mm(int from, unsigned long stack)
|
||||||
{
|
{
|
||||||
struct proc_mm_op copy;
|
struct proc_mm_op copy;
|
||||||
int n, fd;
|
int n, fd;
|
||||||
@ -148,6 +150,9 @@ int new_mm(int from)
|
|||||||
"err = %d\n", -n);
|
"err = %d\n", -n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!ptrace_faultinfo)
|
||||||
|
map_stub_pages(fd, CONFIG_STUB_CODE, CONFIG_STUB_DATA, stack);
|
||||||
|
|
||||||
return(fd);
|
return(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user