All of lore.kernel.org
 help / color / mirror / Atom feed
From: ebiederm+eric@ccr.net (Eric W. Biederman)
To: Linus Torvalds <torvalds@transmeta.com>
Cc: linux-kernel@vger.rutgers.edu, linux-mm@kvack.org
Subject: vfork & co bugfix
Date: 10 Jan 1999 00:48:06 -0600	[thread overview]
Message-ID: <m14spz8vyx.fsf@flinx.ccr.net> (raw)


Looking at vfork in 2.2.0-pre6 I was struck by how badly 
looking at current, (to release a process) hacks up mmput.

It took a little while but eventually a case where
this really goes wrong.

In:
kernel/fork.c:copy_mm
fs/exec.c/exec_mmap

If the we can't allocate page tables, we currently erroneously
wake up a vfork waiter, and clear our segments, and set the ldt
to that of init.

To correct this I've added a companion function mm_release
that we call to remove any dangling references to the old
mm_struct of the current process.

This also ensures that segment and ldt clearing happen for every x86
process.  Not just when the previous memory area was totally freed.

Eric

diff -uNrX linux-ignore-files linux-2.2.0-pre6/arch/i386/kernel/process.c linux-2.2.0-pre6.eb1/arch/i386/kernel/process.c
--- linux-2.2.0-pre6/arch/i386/kernel/process.c	Sat Jan  9 13:33:02 1999
+++ linux-2.2.0-pre6.eb1/arch/i386/kernel/process.c	Sun Jan 10 01:26:17 1999
@@ -475,22 +475,25 @@
 
 void release_segments(struct mm_struct *mm)
 {
-	/* forget local segments */
-	__asm__ __volatile__("movl %w0,%%fs ; movl %w0,%%gs"
-		: /* no outputs */
-		: "r" (0));
 	if (mm->segments) {
 		void * ldt = mm->segments;
-
-		/*
-		 * Get the LDT entry from init_task.
-		 */
-		current->tss.ldt = _LDT(0);
-		load_ldt(0);
-
 		mm->segments = NULL;
 		vfree(ldt);
 	}
+}
+
+void forget_segments(struct task_struct *tsk)
+{
+	/* forget local segments */
+	__asm__ __volatile__("movl %w0,%%fs ; movl %w0,%%gs"
+		: /* no outputs */
+		: "r" (0));
+
+	/*
+	 * Get the LDT entry from init_task.
+	 */
+	tsk->tss.ldt = _LDT(0);
+	load_ldt(0);
 }
 
 /*
diff -uNrX linux-ignore-files linux-2.2.0-pre6/fs/exec.c linux-2.2.0-pre6.eb1/fs/exec.c
--- linux-2.2.0-pre6/fs/exec.c	Fri Dec 25 17:43:18 1998
+++ linux-2.2.0-pre6.eb1/fs/exec.c	Sun Jan 10 01:41:20 1999
@@ -383,6 +383,7 @@
 		exit_mmap(current->mm);
 		clear_page_tables(current);
 		flush_tlb_mm(current->mm);
+		mm_release(current);
 		return 0;
 	}
 
@@ -413,6 +414,7 @@
 	activate_context(current);
 	up(&mm->mmap_sem);
 	mmput(old_mm);
+	mm_release(current);
 	return 0;
 
 	/*
diff -uNrX linux-ignore-files linux-2.2.0-pre6/include/asm-alpha/processor.h linux-2.2.0-pre6.eb1/include/asm-alpha/processor.h
--- linux-2.2.0-pre6/include/asm-alpha/processor.h	Fri Dec 25 17:41:47 1998
+++ linux-2.2.0-pre6.eb1/include/asm-alpha/processor.h	Sun Jan 10 00:38:50 1999
@@ -113,6 +113,7 @@
 
 #define copy_segments(nr, tsk, mm)	do { } while (0)
 #define release_segments(mm)		do { } while (0)
+#define forget_segments(tsk)		do { } while (0)
 
 /* NOTE: The task struct and the stack go together!  */
 #define alloc_task_struct() \
diff -uNrX linux-ignore-files linux-2.2.0-pre6/include/asm-arm/processor.h linux-2.2.0-pre6.eb1/include/asm-arm/processor.h
--- linux-2.2.0-pre6/include/asm-arm/processor.h	Sun Oct 11 14:16:42 1998
+++ linux-2.2.0-pre6.eb1/include/asm-arm/processor.h	Sun Jan 10 01:15:50 1999
@@ -53,11 +53,9 @@
 extern void release_thread(struct task_struct *);
 
 /* Copy and release all segment info associated with a VM */
-extern void copy_segments(int nr, struct task_struct *p, struct mm_struct * mm);
-extern void release_segments(struct mm_struct * mm);
-
 #define copy_segments(nr, tsk, mm)	do { } while (0)
 #define release_segments(mm)		do { } while (0)
+#define forget_segments(tsk)		do { } while (0)
 
 #define init_task	(init_task_union.task)
 #define init_stack	(init_task_union.stack)
diff -uNrX linux-ignore-files linux-2.2.0-pre6/include/asm-i386/processor.h linux-2.2.0-pre6.eb1/include/asm-i386/processor.h
--- linux-2.2.0-pre6/include/asm-i386/processor.h	Wed Jan  6 23:51:10 1999
+++ linux-2.2.0-pre6.eb1/include/asm-i386/processor.h	Sun Jan 10 01:16:30 1999
@@ -281,6 +281,7 @@
 /* Copy and release all segment info associated with a VM */
 extern void copy_segments(int nr, struct task_struct *p, struct mm_struct * mm);
 extern void release_segments(struct mm_struct * mm);
+extern void forget_segments(struct task_struct * tsk);
 
 /*
  * FPU lazy state save handling..
diff -uNrX linux-ignore-files linux-2.2.0-pre6/include/asm-m68k/processor.h linux-2.2.0-pre6.eb1/include/asm-m68k/processor.h
--- linux-2.2.0-pre6/include/asm-m68k/processor.h	Sun Oct 11 14:09:34 1998
+++ linux-2.2.0-pre6.eb1/include/asm-m68k/processor.h	Sun Jan 10 00:41:10 1999
@@ -74,6 +74,7 @@
 
 #define copy_segments(nr, tsk, mm)	do { } while (0)
 #define release_segments(mm)		do { } while (0)
+#define forget_segments(tsk)		do { } while (0)
 
 /*
  * Free current thread data structures etc..
diff -uNrX linux-ignore-files linux-2.2.0-pre6/include/asm-mips/processor.h linux-2.2.0-pre6.eb1/include/asm-mips/processor.h
--- linux-2.2.0-pre6/include/asm-mips/processor.h	Fri Dec 25 17:41:48 1998
+++ linux-2.2.0-pre6.eb1/include/asm-mips/processor.h	Sun Jan 10 00:42:10 1999
@@ -178,6 +178,7 @@
 /* Copy and release all segment info associated with a VM */
 #define copy_segments(nr, p, mm) do { } while(0)
 #define release_segments(mm) do { } while(0)
+#define forget_segments(tsk)		do { } while (0)
 
 /*
  * Return saved PC of a blocked thread.
diff -uNrX linux-ignore-files linux-2.2.0-pre6/include/asm-ppc/processor.h linux-2.2.0-pre6.eb1/include/asm-ppc/processor.h
--- linux-2.2.0-pre6/include/asm-ppc/processor.h	Sun Oct 11 14:18:12 1998
+++ linux-2.2.0-pre6.eb1/include/asm-ppc/processor.h	Sun Jan 10 00:42:32 1999
@@ -299,6 +299,7 @@
 
 #define copy_segments(nr, tsk, mm)	do { } while (0)
 #define release_segments(mm)		do { } while (0)
+#define forget_segments(tsk)		do { } while (0)
 
 /*
  * NOTE! The task struct and the stack go together
diff -uNrX linux-ignore-files linux-2.2.0-pre6/include/asm-sparc/processor.h linux-2.2.0-pre6.eb1/include/asm-sparc/processor.h
--- linux-2.2.0-pre6/include/asm-sparc/processor.h	Sun Oct 11 14:13:51 1998
+++ linux-2.2.0-pre6.eb1/include/asm-sparc/processor.h	Sun Jan 10 00:43:45 1999
@@ -148,6 +148,7 @@
 
 #define copy_segments(nr, tsk, mm)	do { } while (0)
 #define release_segments(mm)		do { } while (0)
+#define forget_segments(tsk)		do { } while (0)
 
 #ifdef __KERNEL__
 
diff -uNrX linux-ignore-files linux-2.2.0-pre6/include/asm-sparc64/processor.h linux-2.2.0-pre6.eb1/include/asm-sparc64/processor.h
--- linux-2.2.0-pre6/include/asm-sparc64/processor.h	Fri Dec 25 17:42:26 1998
+++ linux-2.2.0-pre6.eb1/include/asm-sparc64/processor.h	Sun Jan 10 00:44:37 1999
@@ -208,6 +208,7 @@
 
 #define copy_segments(nr, tsk, mm)	do { } while (0)
 #define release_segments(mm)		do { } while (0)
+#define forget_segments(tsk)		do { } while (0)
 
 #ifdef __KERNEL__
 /* Allocation and freeing of task_struct and kernel stack. */
diff -uNrX linux-ignore-files linux-2.2.0-pre6/include/linux/sched.h linux-2.2.0-pre6.eb1/include/linux/sched.h
--- linux-2.2.0-pre6/include/linux/sched.h	Sat Jan  9 13:33:21 1999
+++ linux-2.2.0-pre6.eb1/include/linux/sched.h	Sun Jan 10 01:16:53 1999
@@ -609,6 +609,8 @@
 	atomic_inc(&mm->count);
 }
 extern void mmput(struct mm_struct *);
+/* Remove the current tasks stale references to the old mm_struct */
+extern void mm_release(struct task_struct *);
 
 extern int  copy_thread(int, unsigned long, unsigned long, struct task_struct *, struct pt_regs *);
 extern void flush_thread(void);
diff -uNrX linux-ignore-files linux-2.2.0-pre6/kernel/exit.c linux-2.2.0-pre6.eb1/kernel/exit.c
--- linux-2.2.0-pre6/kernel/exit.c	Sat Jan  9 13:33:22 1999
+++ linux-2.2.0-pre6.eb1/kernel/exit.c	Sun Jan 10 00:19:03 1999
@@ -259,6 +259,7 @@
 		tsk->swappable = 0;
 		SET_PAGE_DIR(tsk, swapper_pg_dir);
 		mmput(mm);
+		mm_release(tsk);
 	}
 }
 
diff -uNrX linux-ignore-files linux-2.2.0-pre6/kernel/fork.c linux-2.2.0-pre6.eb1/kernel/fork.c
--- linux-2.2.0-pre6/kernel/fork.c	Sat Jan  9 13:33:22 1999
+++ linux-2.2.0-pre6.eb1/kernel/fork.c	Sun Jan 10 01:20:06 1999
@@ -278,14 +278,19 @@
 	return mm;
 }
 
+void mm_release(struct task_struct *tsk)
+{
+	forget_segments(tsk);
+	/* Notify parent sleeping on vfork().
+	 */
+	wake_up(&tsk->p_opptr->vfork_sleep);
+}
+
 /*
  * Decrement the use count and release all resources for an mm.
  */
 void mmput(struct mm_struct *mm)
 {
-	/* notify parent sleeping on vfork() */
-	wake_up(&current->p_opptr->vfork_sleep);
-
 	if (atomic_dec_and_test(&mm->count)) {
 		release_segments(mm);
 		exit_mmap(mm);

--
This is a majordomo managed list.  To unsubscribe, send a message with
the body 'unsubscribe linux-mm me@address' to: majordomo@kvack.org

             reply	other threads:[~1999-01-10  6:54 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
1999-01-10  6:48 Eric W. Biederman [this message]
1999-01-10 18:04 ` vfork & co bugfix Linus Torvalds
1999-01-10 21:34   ` Eric W. Biederman
1999-01-11  4:32   ` Eric W. Biederman
1999-01-11  6:35     ` Linus Torvalds
1999-01-11  6:59       ` Eric W. Biederman
1999-01-11  7:31         ` Linus Torvalds

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=m14spz8vyx.fsf@flinx.ccr.net \
    --to=ebiederm+eric@ccr.net \
    --cc=linux-kernel@vger.rutgers.edu \
    --cc=linux-mm@kvack.org \
    --cc=torvalds@transmeta.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.