[PATCH] uml: maintain own LDT entries

Patch imlements full LDT handling in SKAS:
 * UML holds it's own LDT table, used to deliver data on
   modify_ldt(READ)
 * UML disables the default_ldt, inherited from the host (SKAS3)
   or resets LDT entries, set by host's clib and inherited in
   SKAS0
 * A new global variable skas_needs_stub is inserted, that
   can be used to decide, whether stub-pages must be supported
   or not.
 * Uses the syscall-stub to replace missing PTRACE_LDT (therefore,
   write_ldt_entry needs to be modified)

Signed-off-by: Bodo Stroesser <bstroesser@fujitsu-siemens.com>
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Cc: Paolo Giarrusso <blaisorblade@yahoo.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c
index b99ab41..553a09c 100644
--- a/arch/um/os-Linux/start_up.c
+++ b/arch/um/os-Linux/start_up.c
@@ -135,7 +135,9 @@
 }
 
 int ptrace_faultinfo = 1;
+int ptrace_ldt = 1;
 int proc_mm = 1;
+int skas_needs_stub = 0;
 
 static int __init skas0_cmd_param(char *str, int* add)
 {
@@ -352,14 +354,26 @@
 "    it. To support PTRACE_FAULTINFO, the host needs to be patched\n"
 "    using the current skas3 patch.\n\n");
 
+static int __init noptraceldt_cmd_param(char *str, int* add)
+{
+	ptrace_ldt = 0;
+	return 0;
+}
+
+__uml_setup("noptraceldt", noptraceldt_cmd_param,
+"noptraceldt\n"
+"    Turns off usage of PTRACE_LDT, even if host supports it.\n"
+"    To support PTRACE_LDT, the host needs to be patched using\n"
+"    the current skas3 patch.\n\n");
+
 #ifdef UML_CONFIG_MODE_SKAS
-static inline void check_skas3_ptrace_support(void)
+static inline void check_skas3_ptrace_faultinfo(void)
 {
 	struct ptrace_faultinfo fi;
 	void *stack;
 	int pid, n;
 
-	printf("Checking for the skas3 patch in the host...");
+	printf("  - PTRACE_FAULTINFO...");
 	pid = start_ptraced_child(&stack);
 
 	n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi);
@@ -381,9 +395,49 @@
 	stop_ptraced_child(pid, stack, 1, 1);
 }
 
-int can_do_skas(void)
+static inline void check_skas3_ptrace_ldt(void)
 {
-	printf("Checking for /proc/mm...");
+#ifdef PTRACE_LDT
+	void *stack;
+	int pid, n;
+	unsigned char ldtbuf[40];
+	struct ptrace_ldt ldt_op = (struct ptrace_ldt) {
+		.func = 2, /* read default ldt */
+		.ptr = ldtbuf,
+		.bytecount = sizeof(ldtbuf)};
+
+	printf("  - PTRACE_LDT...");
+	pid = start_ptraced_child(&stack);
+
+	n = ptrace(PTRACE_LDT, pid, 0, (unsigned long) &ldt_op);
+	if (n < 0) {
+		if(errno == EIO)
+			printf("not found\n");
+		else {
+			perror("not found");
+		}
+		ptrace_ldt = 0;
+	}
+	else {
+		if(ptrace_ldt)
+			printf("found\n");
+		else
+			printf("found, but use is disabled\n");
+	}
+
+	stop_ptraced_child(pid, stack, 1, 1);
+#else
+	/* PTRACE_LDT might be disabled via cmdline option.
+	 * We want to override this, else we might use the stub
+	 * without real need
+	 */
+	ptrace_ldt = 1;
+#endif
+}
+
+static inline void check_skas3_proc_mm(void)
+{
+	printf("  - /proc/mm...");
 	if (os_access("/proc/mm", OS_ACC_W_OK) < 0) {
  		proc_mm = 0;
 		printf("not found\n");
@@ -394,8 +448,19 @@
 		else
 			printf("found\n");
 	}
+}
 
-	check_skas3_ptrace_support();
+int can_do_skas(void)
+{
+	printf("Checking for the skas3 patch in the host:\n");
+
+	check_skas3_proc_mm();
+	check_skas3_ptrace_faultinfo();
+	check_skas3_ptrace_ldt();
+
+	if(!proc_mm || !ptrace_faultinfo || !ptrace_ldt)
+		skas_needs_stub = 1;
+
 	return 1;
 }
 #else