[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>
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index d232daa..d837223 100644
--- a/arch/um/kernel/skas/mmu.c
+++ b/arch/um/kernel/skas/mmu.c
@@ -77,23 +77,14 @@
 	struct mm_struct *cur_mm = current->mm;
 	struct mm_id *cur_mm_id = &cur_mm->context.skas.id;
 	struct mm_id *mm_id = &mm->context.skas.id;
-	unsigned long stack;
-	int from, ret;
+	unsigned long stack = 0;
+	int from, ret = -ENOMEM;
 
-	if(proc_mm){
-		if((cur_mm != NULL) && (cur_mm != &init_mm))
-			from = cur_mm->context.skas.id.u.mm_fd;
-		else from = -1;
+	if(!proc_mm || !ptrace_faultinfo){
+		stack = get_zeroed_page(GFP_KERNEL);
+		if(stack == 0)
+			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
 		 * we are about to reinitialize it, and want mm.nr_ptes to
 		 * be accurate.
@@ -103,20 +94,30 @@
 		ret = init_stub_pte(mm, CONFIG_STUB_CODE,
 				    (unsigned long) &__syscall_stub_start);
 		if(ret)
-			goto out;
-
-		ret = -ENOMEM;
-		stack = get_zeroed_page(GFP_KERNEL);
-		if(stack == 0)
-			goto out;
-		mm_id->stack = stack;
+			goto out_free;
 
 		ret = init_stub_pte(mm, CONFIG_STUB_DATA, stack);
 		if(ret)
 			goto out_free;
 
 		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))
 			mm_id->u.pid = copy_context_skas0(stack,
 							  cur_mm_id->u.pid);
@@ -126,7 +127,8 @@
 	return 0;
 
  out_free:
-	free_page(mm_id->stack);
+	if(mm_id->stack != 0)
+		free_page(mm_id->stack);
  out:
 	return ret;
 }
@@ -137,8 +139,10 @@
 
 	if(proc_mm)
 		os_close_file(mmu->id.u.mm_fd);
-	else {
+	else
 		os_kill_ptraced_process(mmu->id.u.pid, 1);
+
+	if(!proc_mm || !ptrace_faultinfo){
 		free_page(mmu->id.stack);
 		free_page(mmu->last_page_table);
 	}