patch-2.3.99-pre6 linux/kernel/exec_domain.c

Next file: linux/kernel/exit.c
Previous file: linux/ipc/shm.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.99-pre5/linux/kernel/exec_domain.c linux/kernel/exec_domain.c
@@ -32,9 +32,7 @@
    * personality set incorrectly.  Check to see whether SVr4 is available,
    * and use it, otherwise give the user a SEGV.
    */
-	put_exec_domain(current->exec_domain);
-	current->personality = PER_SVR4;
-	current->exec_domain = lookup_exec_domain(current->personality);
+	set_personality(PER_SVR4);
 
 	if (current->exec_domain && current->exec_domain->handler
 	&& current->exec_domain->handler != no_lcall7) {
@@ -45,7 +43,7 @@
 	send_sig(SIGSEGV, current, 1);
 }
 
-struct exec_domain *lookup_exec_domain(unsigned long personality)
+static struct exec_domain *lookup_exec_domain(unsigned long personality)
 {
 	unsigned long pers = personality & PER_MASK;
 	struct exec_domain *it;
@@ -104,28 +102,37 @@
 	return -EINVAL;
 }
 
-asmlinkage long sys_personality(unsigned long personality)
+void __set_personality(unsigned long personality)
 {
 	struct exec_domain *it;
-	unsigned long old_personality;
-	int ret;
-
-	if (personality == 0xffffffff)
-		return current->personality;
 
-	ret = -EINVAL;
-	lock_kernel();
 	it = lookup_exec_domain(personality);
-	if (!it)
-		goto out;
+	if (it) {
+		if (atomic_read(&current->fs->count) != 1) {
+			struct fs_struct *new = copy_fs_struct(current->fs);
+			if (!new)
+				return;
+			put_fs_struct(xchg(&current->fs,new));
+		}
+		/*
+		 * At that point we are guaranteed to be the sole owner of
+		 * current->fs.
+		 */
+		current->personality = personality;
+		current->exec_domain = it;
+		set_fs_altroot();
+		put_exec_domain(current->exec_domain);
+	}
+}
 
-	old_personality = current->personality;
-	put_exec_domain(current->exec_domain);
-	current->personality = personality;
-	current->exec_domain = it;
-	ret = old_personality;
-out:
-	unlock_kernel();
+asmlinkage long sys_personality(unsigned long personality)
+{
+	int ret = current->personality;
+	if (personality != 0xffffffff) {
+		set_personality(personality);
+		if (current->personality != personality)
+			ret = -EINVAL;
+	}
 	return ret;
 }
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)