Subject: Re: exploit with memcpy()
To: None <tech-userlevel@netbsd.org, tech-security@netbsd.org>
From: TAMURA Kent <kent@netbsd.org>
List: tech-security
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>