Subject: Re: exploit with memcpy()
To: None <tech-userlevel@netbsd.org, tech-security@netbsd.org>
From: TAMURA Kent <kent@netbsd.org>
List: tech-userlevel
Date: 07/04/2002 00:59:28
> Right and no.  The exploit succeeds if and only if memcpy() is
> compatible with memmove().  Gcc's builtin memcpy() is not.

Let me explain detail.

The expoit is not normal buffer overflow.  It is a kind of
buffer *underflow*.  In this case, BSD memcpy() starts with
dst+length as the destination and copies backward.  It breaks
parameters of memcpy() and the return address to the caller.  If
BSD memcpy() did not perfom as memmove(), the exploit would
fail, and gcc's builtin memcpy() and glibc memcpy() never copies
backward.  This is the reason why Apache exploits target for
*BSD.  If Apache used memmove() instead of memcpy(), many OSs
would be exploitable.

We can avoid normal buffer overflow exploits with
stack-protected compilers such as IBM's gcc-ssp [1].  I compiled
the kernel and all user-land programs with gcc-ssp and install
them to some machines.  Unfortunately gcc-ssp does not cover
buffer *underflow*.

[1] http://www.trl.ibm.com/projects/security/ssp/


Revised patch:
Index: arch/i386/string/bcopy.S
===================================================================
RCS file: /cvsroot/basesrc/lib/libc/arch/i386/string/bcopy.S,v
retrieving revision 1.6
diff -u -r1.6 bcopy.S
--- arch/i386/string/bcopy.S	1996/11/12 00:50:06	1.6
+++ arch/i386/string/bcopy.S	2002/07/03 15:30:16
@@ -84,6 +84,33 @@
 1:
 	addl	%ecx,%edi	/* copy backwards. */
 	addl	%ecx,%esi
+#ifdef _DIAGNOSTIC
+#define _DIAGASSERT	call	_C_LABEL(__diagassert13)
+	pushl	%ecx
+	cmpl	12(%esp),%edi	/* check pointer wraparound */
+	jae	2f
+	pushl	$diagmes1
+	pushl	$func
+	pushl	$__LINE__
+	pushl	$file
+	_DIAGASSERT
+	addl	$16,%esp
+	popl	%ecx
+	jmp	4f
+2:	
+	cmpl	16(%esp),%esi
+	jae	3f
+	pushl	$diagmes2
+	pushl	$func
+	pushl	$__LINE__
+	pushl	$file
+	_DIAGASSERT
+	addl	$16,%esp
+	popl	%ecx
+	jmp	4f
+3:
+	popl	%ecx
+#endif
 	std
 	andl	$3,%ecx		/* any fractional bytes? */
 	decl	%edi
@@ -96,6 +123,7 @@
 	subl	$3,%edi
 	rep
 	movsl
+4:
 #if defined(MEMCOPY) || defined(MEMMOVE)
 	movl	12(%esp),%eax
 #endif
@@ -103,3 +131,20 @@
 	popl	%esi
 	cld
 	ret
+
+#ifdef _DIAGNOSTIC
+file:
+	.asciz	__FILE__
+func:
+#if defined(MEMCOPY)
+	.asciz	"memcpy"
+#elseif defined(MEMMOVE)
+	.asciz	"memmove"
+#else
+	.asciz	"bcopy"
+#endif
+diagmes1:
+	.asciz	"src + length > src"
+diagmes2:
+	.asciz	"dst + length > dst"
+#endif
Index: string/bcopy.c
===================================================================
RCS file: /cvsroot/basesrc/lib/libc/string/bcopy.c,v
retrieving revision 1.13
diff -u -r1.13 bcopy.c
--- string/bcopy.c	2001/02/08 18:33:50	1.13
+++ string/bcopy.c	2002/07/03 15:30:20
@@ -132,6 +132,8 @@
 		 */
 		src += length;
 		dst += length;
+		_DIAGASSERT((unsigned long)dst >= (unsigned long)dst0);
+		_DIAGASSERT((unsigned long)src >= (unsigned long)src0);
 		u = (unsigned long)src;
 		if ((u | (unsigned long)dst) & wmask) {
 			if ((u ^ (unsigned long)dst) & wmask || length <= wsize)

-- 
TAMURA Kent <kent2002@hauN.org> <kent@netbsd.org>