bin/119129: __stack_chk_guard setup is bogus in src/lib/libc/sys/stack_protector.c

Antoine Brodin antoine.brodin at laposte.net
Sat Dec 29 05:10:02 PST 2007


>Number:         119129
>Category:       bin
>Synopsis:       __stack_chk_guard setup is bogus in src/lib/libc/sys/stack_protector.c
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sat Dec 29 13:10:01 UTC 2007
>Closed-Date:
>Last-Modified:
>Originator:     Antoine Brodin
>Release:        FreeBSD 8.0-CURRENT i386
>Organization:
none
>Environment:
System: FreeBSD barton.dreadbsd.org. 8.0-CURRENT FreeBSD 8.0-CURRENT #0: Mon Dec 3 17:11:47 CET 2007 root at barton.dreadbsd.org.:/usr/obj/usr/src/sys/BARTON i386
>Description:
When compiling with -fstack-protector-all and executing a binary,
__stack_chk_guard is always initialized to 0xff0a0000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000.
(at least on i386).

>How-To-Repeat:
%%%
cat > b.c << EOF

#include <stdio.h>

extern long __stack_chk_guard[8];

int
main(void)
{
	int i;

	for (i = 0; i < 8; i++)
		printf("%lx\n", __stack_chk_guard[i]);
	return 0;
}

EOF
gcc -fstack-protector-all b.c
./a.out
%%%

It gives:
./a.out 
ff0a0000
0
0
0
0
0
0
0


Where is the problem ?
The length returned by sysctl(mib, 2, __stack_chk_guard, &len, NULL, 0)
is not sizeof(__stack_chk_guard) so the default canary is used:

%%%
cat > a.c << EOF

#include <sys/types.h>
#include <sys/sysctl.h>
#include <stdio.h>

int
main(void)
{
	long stack_chk_guard[8] = {0, 0, 0, 0, 0, 0, 0, 0};
	int mib[2];
	size_t len;
	int i, ret;

	mib[0] = CTL_KERN;
	mib[1] = KERN_ARND;
	len = sizeof(stack_chk_guard);
	ret = sysctl(mib, 2, stack_chk_guard, &len, NULL, 0);
	if (ret == -1)
		printf("-1\n");
	if (len != sizeof(stack_chk_guard))
		printf("%d != %d\n", len, sizeof(stack_chk_guard));
	if (ret == -1 || len != sizeof(stack_chk_guard))
	{
		((unsigned char *)(void *)stack_chk_guard)[0] = 0;
		((unsigned char *)(void *)stack_chk_guard)[1] = 0;
		((unsigned char *)(void *)stack_chk_guard)[2] = '\n';
		((unsigned char *)(void *)stack_chk_guard)[3] = 255;
	}
	for (i = 0; i < 8; i++)
		printf("%lx\n", stack_chk_guard[i]);
	return 0;
}

EOF
gcc a.c
./a.out
%%%

It gives:
./a.out
4 != 32
ff0a0000
0
0
0
0
0
0
0

>Fix:
There is a bug in either src/lib/libc/sys/stack_protector.c:__guard_setup(),
or in src/sys/kern/kern_mib.c:sysctl_kern_arnd().
sysctl_kern_arnd() generates a random long, while __guard_setup assumes it
generates a random buffer.
On OpenBSD, src/lib/libc/sys/stack_protector.c is the same but
src/sys/kern/kern_sysctl.c initializes a buffer for KERN_ARND
( http://fxr.watson.org/fxr/source//kern/kern_sysctl.c?v=OPENBSD#L394 )

>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list