public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] CRED: Fix check_unsafe_exec()
@ 2009-03-10 18:07 David Howells
  2009-03-10 21:31 ` Hugh Dickins
  0 siblings, 1 reply; 10+ messages in thread
From: David Howells @ 2009-03-10 18:07 UTC (permalink / raw)
  To: hugh, jmalicki, chrisw, akpm
  Cc: linux-kernel, dhowells, linux-security-module

check_unsafe_exec() relies on the usage counts of fs_struct and files_struct to
indicate the subscription count of cloned processes to these structures.  This
is not a viable method, however, as /proc can increment these counts when
merely accessing the data.

The effect of this is to occasionally prevent setuid executables from altering
their security details correctly.

To deal with this, subscription counters are added in addition to the usage
counters to fs_struct and files_struct.

This should hopefully fix:

	http://lkml.org/lkml/2009/2/25/491
	Date: Wed, 25 Feb 2009 18:11:54 -0500 (EST)
	From: Joe Malicki <jmalicki@metacarta.com>
	Subject: BUG: setuid sometimes doesn't.

	Very rarely, we experience a setuid program not properly getting
	the euid of its owner.  This happens with (at least) both Linux 2.6.24.7
	and Linux 2.6.28.4, on multiple machines of at least two configurations
	(Dell 860 and Dell 2950 - cpuinfo attached).
	...

Reported-by: Joe Malicki <jmalicki@metacarta.com>
Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/exec.c                 |    4 ++--
 fs/file.c                 |    1 +
 include/linux/fdtable.h   |    4 +++-
 include/linux/fs_struct.h |    7 ++++++-
 kernel/exit.c             |    2 ++
 kernel/fork.c             |    3 +++
 6 files changed, 17 insertions(+), 4 deletions(-)


diff --git a/fs/exec.c b/fs/exec.c
index 929b580..67d7a45 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1069,8 +1069,8 @@ void check_unsafe_exec(struct linux_binprm *bprm, struct files_struct *files)
 		n_sighand++;
 	}
 
-	if (atomic_read(&p->fs->count) > n_fs ||
-	    atomic_read(&p->files->count) > n_files ||
+	if (atomic_read(&p->fs->subscribers) > n_fs ||
+	    atomic_read(&p->files->subscribers) > n_files ||
 	    atomic_read(&p->sighand->count) > n_sighand)
 		bprm->unsafe |= LSM_UNSAFE_SHARE;
 
diff --git a/fs/file.c b/fs/file.c
index f313314..6a33a7a 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -303,6 +303,7 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
 		goto out;
 
 	atomic_set(&newf->count, 1);
+	atomic_set(&newf->subscribers, 1);
 
 	spin_lock_init(&newf->file_lock);
 	newf->next_fd = 0;
diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h
index 09d6c5b..12e54bc 100644
--- a/include/linux/fdtable.h
+++ b/include/linux/fdtable.h
@@ -42,7 +42,9 @@ struct files_struct {
   /*
    * read mostly part
    */
-	atomic_t count;
+	atomic_t count;		/* number of processes accessing this set */
+	atomic_t subscribers;	/* number of cloned processes subscribed to
+				 * this set */
 	struct fdtable *fdt;
 	struct fdtable fdtab;
   /*
diff --git a/include/linux/fs_struct.h b/include/linux/fs_struct.h
index a97c053..47679c1 100644
--- a/include/linux/fs_struct.h
+++ b/include/linux/fs_struct.h
@@ -3,8 +3,13 @@
 
 #include <linux/path.h>
 
+/*
+ * General filesystem access parameter block.
+ */
 struct fs_struct {
-	atomic_t count;
+	atomic_t count;		/* number of processes accessing this block */
+	atomic_t subscribers;	/* number of cloned processes subscribed to
+				 * this block */
 	rwlock_t lock;
 	int umask;
 	struct path root, pwd;
diff --git a/kernel/exit.c b/kernel/exit.c
index efd30cc..57b63bb 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -561,6 +561,7 @@ void exit_files(struct task_struct *tsk)
 		task_lock(tsk);
 		tsk->files = NULL;
 		task_unlock(tsk);
+		atomic_dec(&files->subscribers);
 		put_files_struct(files);
 	}
 }
@@ -583,6 +584,7 @@ void exit_fs(struct task_struct *tsk)
 		task_lock(tsk);
 		tsk->fs = NULL;
 		task_unlock(tsk);
+		atomic_dec(&fs->subscribers);
 		put_fs_struct(fs);
 	}
 }
diff --git a/kernel/fork.c b/kernel/fork.c
index 4854c2c..9d1a2a7 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -682,6 +682,7 @@ static struct fs_struct *__copy_fs_struct(struct fs_struct *old)
 	/* We don't need to lock fs - think why ;-) */
 	if (fs) {
 		atomic_set(&fs->count, 1);
+		atomic_set(&fs->subscribers, 1);
 		rwlock_init(&fs->lock);
 		fs->umask = old->umask;
 		read_lock(&old->lock);
@@ -705,6 +706,7 @@ static int copy_fs(unsigned long clone_flags, struct task_struct *tsk)
 {
 	if (clone_flags & CLONE_FS) {
 		atomic_inc(&current->fs->count);
+		atomic_inc(&current->fs->subscribers);
 		return 0;
 	}
 	tsk->fs = __copy_fs_struct(current->fs);
@@ -727,6 +729,7 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk)
 
 	if (clone_flags & CLONE_FILES) {
 		atomic_inc(&oldf->count);
+		atomic_inc(&oldf->subscribers);
 		goto out;
 	}
 


^ permalink raw reply related	[flat|nested] 10+ messages in thread
[parent not found: <3830454.11106421237315019351.JavaMail.root@ouachita>]
[parent not found: <1906769.11304931237505721331.JavaMail.root@ouachita>]

end of thread, other threads:[~2009-03-19 23:36 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-03-10 18:07 [PATCH] CRED: Fix check_unsafe_exec() David Howells
2009-03-10 21:31 ` Hugh Dickins
2009-03-10 23:01   ` David Howells
2009-03-10 23:40     ` Hugh Dickins
2009-03-12 13:23       ` David Howells
2009-03-16 22:15         ` Hugh Dickins
     [not found] <3830454.11106421237315019351.JavaMail.root@ouachita>
2009-03-17 18:39 ` Joe Malicki
2009-03-17 23:07   ` Joe Malicki
2009-03-19 18:44     ` Hugh Dickins
     [not found] <1906769.11304931237505721331.JavaMail.root@ouachita>
2009-03-19 23:36 ` Joe Malicki

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox