Subject: why is setcontext(0) caught in kernel?
To: None <tech-kern@netbsd.org>
From: Matthias Drochner <M.Drochner@fz-juelich.de>
List: tech-kern
Date: 08/01/2006 23:29:26
This is a multipart MIME message.

--==_Exmh_2891217098850
Content-Type: text/plain; charset=us-ascii


Hi -

looking at PR port-i386/34112 I've looked at setcontext()
a bit more and found that it wouldn't take much to make
it more robust against corrupted input.
That's nothing impacting kernel security afaict, just
unexpected behaviour and poor handling of memory corruption
happening in userland.

There was a design decision appearently to allow a zero
pointer argument to setcontext(2), and interpret this
as _exit(0). There are two problems with this:
-corruption in userland can easily go unnoticed, the
 process will just exit with success status
-processes using makecontext properly will not do the usual
 cleanup, exit handlers etc.

I don't think this is necessary. The uc_link end can
be caught in _resumecontext as well, and then there was
no reason anymore to allow the zero pointer to setcontext(),
that would be just an EFAULT.
Also, setcontext(2) has the habit to return(JUSTRETURN)
occasionally, without providing a useful error code. If
it returns, something is seriously corrupted, and the
process should exit with something nonzero.

I've started to do the userland parts for i386 and alpha.
Patches appended. If all ports did that, we could remove
the special handling of setcontect(0) in-kernel.

what do you think?

best regards
Matthias



--==_Exmh_2891217098850
Content-Type: text/plain ; name="context.txt"; charset=us-ascii
Content-Description: context.txt
Content-Disposition: attachment; filename="context.txt"

Index: arch/i386/gen/resumecontext.S
===================================================================
RCS file: /cvsroot/src/lib/libc/arch/i386/gen/resumecontext.S,v
retrieving revision 1.4
diff -u -r1.4 resumecontext.S
--- arch/i386/gen/resumecontext.S	26 Jan 2003 18:14:03 -0000	1.4
+++ arch/i386/gen/resumecontext.S	1 Aug 2006 21:21:24 -0000
@@ -37,6 +37,7 @@
  */
 
 #include <machine/asm.h>
+#include "SYS.h"
 
 #if defined(LIBC_SCCS) && !defined(lint)
 	RCSID("$NetBSD: resumecontext.S,v 1.4 2003/01/26 18:14:03 kleink Exp $")
@@ -63,6 +64,9 @@
 	PIC_EPILOGUE
 	movl	4(%esp),%ecx		/* uc_link */
 	PIC_PROLOGUE
+	cmpl	$0,%ecx			/* link end? */
+	je	9f	/* watch out for local label use in PIC_* */
+
 	pushl	%ecx
 #ifdef PIC
 	call	PIC_PLT(_C_LABEL(setcontext))
@@ -70,3 +74,16 @@
 	call	_C_LABEL(setcontext)
 #endif
 	/* NOTREACHED */
+
+	/* something is wrong, pull the brake */
+	pushl	$-1
+	pushl	$0
+	SYSTRAP(exit)
+
+9:
+	pushl	$0 /* exit code */
+#ifdef PIC
+	call	PIC_PLT(_C_LABEL(exit))
+#else
+	call	_C_LABEL(exit)
+#endif
Index: arch/i386/sys/__sigtramp2.S
===================================================================
RCS file: /cvsroot/src/lib/libc/arch/i386/sys/__sigtramp2.S,v
retrieving revision 1.1
diff -u -r1.1 __sigtramp2.S
--- arch/i386/sys/__sigtramp2.S	6 Sep 2003 22:10:40 -0000	1.1
+++ arch/i386/sys/__sigtramp2.S	1 Aug 2006 21:21:24 -0000
@@ -51,9 +51,9 @@
  *	sp->	signal number				[0]
  */
 NENTRY(__sigtramp_siginfo_2)
-	movl	8(%esp),%eax	/* get pointer to ucontext */
+	leal	12+128(%esp),%eax /* get address of ucontext */
 	movl	%eax,4(%esp)	/* put it in the argument slot */
 				/* fake return address already there */
 	SYSTRAP(setcontext)	/* do setcontext */
-	movl	%eax,4(%esp)	/* error code */
+	movl	$-1,4(%esp)	/* if we return here, something is wrong */
 	SYSTRAP(exit)		/* exit */
Index: arch/alpha/gen/resumecontext.c
===================================================================
RCS file: /cvsroot/src/lib/libc/arch/alpha/gen/resumecontext.c,v
retrieving revision 1.2
diff -u -r1.2 resumecontext.c
--- arch/alpha/gen/resumecontext.c	18 Jan 2003 11:04:39 -0000	1.2
+++ arch/alpha/gen/resumecontext.c	1 Aug 2006 21:21:24 -0000
@@ -43,6 +43,8 @@
 
 #include "namespace.h"
 #include <ucontext.h>
+#include <unistd.h>
+#include <stdlib.h>
 #include "extern.h"
 
 void
@@ -51,6 +53,11 @@
 	ucontext_t uct;
 
 	(void)getcontext(&uct);
-	(void)setcontext(uct.uc_link);
+	if (uct.uc_link) {
+		(void)setcontext(uct.uc_link);
+		/* NOTREACHED */
+		_exit(0xff);
+	}
+	exit(0);
 	/* NOTREACHED */
 }
Index: arch/alpha/sys/__sigtramp2.S
===================================================================
RCS file: /cvsroot/src/lib/libc/arch/alpha/sys/__sigtramp2.S,v
retrieving revision 1.1
diff -u -r1.1 __sigtramp2.S
--- arch/alpha/sys/__sigtramp2.S	7 Oct 2003 17:08:07 -0000	1.1
+++ arch/alpha/sys/__sigtramp2.S	1 Aug 2006 21:21:24 -0000
@@ -41,6 +41,6 @@
 NESTED_NOPROFILE(__sigtramp_siginfo_2,0,0,ra,0,0)
 	lda	a0,(128)(sp)		/* get pointer to ucontext */
 	CALLSYS_NOERROR(setcontext)	/* and call setcontext() with it */
-	mov	v0, a0			/* if that failed, get error code */
-	CALLSYS_NOERROR(exit)		/* and call exit() with it */
+	ldiq	a0,-1			/* if that failed, set an exit code */
+	CALL(exit)			/* and call exit() */
 END(__sigtramp_siginfo_2)

--==_Exmh_2891217098850--