From 3b149cc7cd1573436468c1103b2f42f3fd0888a4 Mon Sep 17 00:00:00 2001
From: Andrew Morton <akpm@digeo.com>
Date: Sun, 2 Feb 2003 06:06:58 -0800
Subject: [PATCH] [PATCH] remove lock_kernel() from exec of setuid apps

Patch from Manfred Spraul <manfred@colorfullife.com>

exec of setuid apps and ptrace must be synchronized, to ensure that a normal
user cannot ptrace a setuid app across exec.  ptrace_attach acquires the
task_lock around the uid checks, compute_creds acquires the BLK.  The patch
converts compute_creds to the task_lock.  Additionally, it removes the
do_unlock variable: the task_lock is not heaviliy used, there is no need to
avoid the spinlock by adding branches.

The patch is a cleanup patch, not a fix for a security problem: AFAICS the
sys_ptrace in every arch acquires the BKL before calling ptrace_attach.
---
 fs/exec.c             | 8 ++------
 security/capability.c | 8 ++------
 2 files changed, 4 insertions(+), 12 deletions(-)

diff --git a/fs/exec.c b/fs/exec.c
index 92716bc7c10b..69a19459e47d 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -873,12 +873,10 @@ int prepare_binprm(struct linux_binprm *bprm)
 
 void compute_creds(struct linux_binprm *bprm) 
 {
-	int do_unlock = 0;
-
+	task_lock(current);
 	if (bprm->e_uid != current->uid || bprm->e_gid != current->gid) {
                 current->mm->dumpable = 0;
 		
-		lock_kernel();
 		if (must_not_trace_exec(current)
 		    || atomic_read(&current->fs->count) > 1
 		    || atomic_read(&current->files->count) > 1
@@ -888,14 +886,12 @@ void compute_creds(struct linux_binprm *bprm)
 				bprm->e_gid = current->gid;
 			}
 		}
-		do_unlock = 1;
 	}
 
         current->suid = current->euid = current->fsuid = bprm->e_uid;
         current->sgid = current->egid = current->fsgid = bprm->e_gid;
 
-	if(do_unlock)
-		unlock_kernel();
+	task_unlock(current);
 
 	security_bprm_compute_creds(bprm);
 }
diff --git a/security/capability.c b/security/capability.c
index 8e26f1f52b1a..cf6d2440a21d 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -120,17 +120,16 @@ void cap_bprm_compute_creds (struct linux_binprm *bprm)
 {
 	/* Derived from fs/exec.c:compute_creds. */
 	kernel_cap_t new_permitted, working;
-	int do_unlock = 0;
 
 	new_permitted = cap_intersect (bprm->cap_permitted, cap_bset);
 	working = cap_intersect (bprm->cap_inheritable,
 				 current->cap_inheritable);
 	new_permitted = cap_combine (new_permitted, working);
 
+	task_lock(current);
 	if (!cap_issubset (new_permitted, current->cap_permitted)) {
 		current->mm->dumpable = 0;
 
-		lock_kernel ();
 		if (must_not_trace_exec (current)
 		    || atomic_read (&current->fs->count) > 1
 		    || atomic_read (&current->files->count) > 1
@@ -141,7 +140,6 @@ void cap_bprm_compute_creds (struct linux_binprm *bprm)
 							       cap_permitted);
 			}
 		}
-		do_unlock = 1;
 	}
 
 	/* For init, we want to retain the capabilities set
@@ -154,9 +152,7 @@ void cap_bprm_compute_creds (struct linux_binprm *bprm)
 	}
 
 	/* AUD: Audit candidate if current->cap_effective is set */
-
-	if (do_unlock)
-		unlock_kernel ();
+	task_unlock(current);
 
 	current->keep_capabilities = 0;
 }
-- 
2.30.9