Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 838

kernel-2.6.18-238.el5.src.rpm

From: Vitaly Mayatskikh <vmayatsk@redhat.com>
Date: Sat, 8 Sep 2007 23:57:48 +0200
Subject: [fs] Fix unserialized task->files changing
Message-id: m3sl5o7rc3.fsf@dhcp-lab-156.englab.brq.redhat.com
O-Subject: [RHEL 5.2 patch] BZ253866 Fix unserialized task->files changing
Bugzilla: 253866

bz253866
https://bugzilla.redhat.com/show_bug.cgi?id=253866

Description:
===========
This is a race condition between tasks that are creating/removing tasks.
While one task is traversing through '/proc/<pid>/fd/'
directory and trying to access the symbolic links, simultaneously tasks on
other cpus are trying to close the open files or are exec'ing into a new task.

Upstream status of the patch:
=============================
Patch is in upstream
http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=3b9b8ab65d8eed784b9164d03807cb2bda7b5cd6;hp=fc09561d6392771a392dea55c287de7e849b6b63

Test status:
============
Patch has been stress-tested by reporter on internal build of RHEL4.6.
Patch has been backported, built and tested on RHEL-5/x86 box.

Acked-by: Pete Zaitcev <zaitcev@redhat.com>
---
 fs/binfmt_elf.c      |    6 ++----
 fs/binfmt_misc.c     |    6 ++----
 fs/exec.c            |    3 +--
 include/linux/file.h |    1 +
 kernel/exit.c        |   13 +++++++++++++
 5 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 3c2bcba..d70697e 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1110,10 +1110,8 @@ out_free_interp:
 out_free_file:
 	sys_close(elf_exec_fileno);
 out_free_fh:
-	if (files) {
-		put_files_struct(current->files);
-		current->files = files;
-	}
+	if (files)
+		reset_files_struct(current, files);
 out_free_ph:
 	kfree(elf_phdata);
 	goto out;
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index 66ba137..1713c48 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -215,10 +215,8 @@ _error:
 	bprm->interp_flags = 0;
 	bprm->interp_data = 0;
 _unshare:
-	if (files) {
-		put_files_struct(current->files);
-		current->files = files;
-	}
+	if (files)
+		reset_files_struct(current, files);
 	goto _ret;
 }
 
diff --git a/fs/exec.c b/fs/exec.c
index cfbd035..a06b4fe 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -904,8 +904,7 @@ int flush_old_exec(struct linux_binprm * bprm)
 	return 0;
 
 mmap_failed:
-	put_files_struct(current->files);
-	current->files = files;
+	reset_files_struct(current, files);
 out:
 	return retval;
 }
diff --git a/include/linux/file.h b/include/linux/file.h
index 19a856f..433bc1c 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -112,6 +112,7 @@ struct task_struct;
 
 struct files_struct *get_files_struct(struct task_struct *);
 void FASTCALL(put_files_struct(struct files_struct *fs));
+void reset_files_struct(struct task_struct *, struct files_struct *);
 
 extern int dupfd(struct file *file, unsigned int start);
 
diff --git a/kernel/exit.c b/kernel/exit.c
index d1750a6..d779f4f 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -496,6 +496,19 @@ void fastcall put_files_struct(struct files_struct *files)
 
 EXPORT_SYMBOL(put_files_struct);
 
+void reset_files_struct(struct task_struct *tsk, struct files_struct *files)
+{
+	struct files_struct *old;
+
+	old = tsk->files;
+	task_lock(tsk);
+	tsk->files = files;
+	task_unlock(tsk);
+	put_files_struct(old);
+}
+
+EXPORT_SYMBOL(reset_files_struct);
+
 static inline void __exit_files(struct task_struct *tsk)
 {
 	struct files_struct * files = tsk->files;
-- 
1.5.3.5.645.gbb47