Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 16 Apr 2009 12:11:56 GMT
From:      Tobias Brunner <tobias.brunner@strongswan.org>
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   kern/133776: [libc] snprintf(3) and vsnprintf(3) do not properly initialize _fl_mutex
Message-ID:  <200904161211.n3GCBuGe098186@www.freebsd.org>
Resent-Message-ID: <200904161220.n3GCK2Ki022627@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         133776
>Category:       kern
>Synopsis:       [libc] snprintf(3) and vsnprintf(3) do not properly initialize _fl_mutex
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Apr 16 12:20:02 UTC 2009
>Closed-Date:
>Last-Modified:
>Originator:     Tobias Brunner
>Release:        8.0-CURRENT
>Organization:
strongSwan Project
>Environment:
FreeBSD bsd.strongswan.org 8.0-CURRENT FreeBSD 8.0-CURRENT #3: Fri Apr 10 00:20:00 CEST 2009     root@bsd.strongswan.org:/usr/obj/usr/src/sys/IPSEC  i386
>Description:
snprintf(3) and vsnprintf(3) do not properly initialze _fl_mutex of the FILE object that is then passed to __vfprintf.  This is usually fine but if custom printf specifiers are registered using the GNU compatible register_printf_function this could result in a segmentation fault or a lockup, depending on the contents of the stack during the execution of snprintf or vsnprintf.

The problem is, that the FILE object created in snprintf or vsnprintf is passed as-is to the registered callback function.  There, one usually uses fprintf or fwrite to write content to the stream.  Since FreeBSD libc does not support unlocked io functions (other than putc_unlocked) this eventually results in a call to _flockfile (stdio/_flock_stub.c) which then tries to acquire the mutex.  As the mutex is not initialized to NULL this either works (because _fl_mutex coincidentally equals NULL), result in a segmentation fault, a lockup (if the memory area _fl_mutex points to is interpreted as a locked mutex) or the lock is acquired (while changing random memory wherever _fl_mutex points to).

>How-To-Repeat:
Since this bug highly depends on the contents of the stack during the execution of snprintf or vsnprintf it is not always triggered.  But running the following program always resulted in a segmentation fault on my machine.

Compile with -lpthread:

--------

#include <stdlib.h>
#include <stdio.h>
#include <printf.h>
#include <pthread.h>

static int custom_print(FILE *stream, const struct printf_info *info,
                        const void *const *args)
{
    return fprintf(stream, "%d", *(int*)args[0]);
}

static int custom_arginfo(const struct printf_info *info, size_t n, int *argtypes)
{
	if (n >= 1)
	{
		argtypes[0] = PA_INT;
	}
	return 1;
}

static void thread_func(void *this) {
	char buf[256];
	sleep(random() & 0x03);
	snprintf(buf, sizeof(buf), "%N %d", 23, 42);
	printf("[thread]: %s\n", buf);
}

int main (int argc, char const* argv[])
{
	char buf[256];
	pthread_t t1, t2, t3;
	register_printf_function('N', custom_print, custom_arginfo);
	snprintf(buf, sizeof(buf), "%N %d", 42, 23);
	printf("[main]  : %s\n", buf);
	pthread_create(&t1, NULL, (void*)thread_func, NULL);
	pthread_create(&t2, NULL, (void*)thread_func, NULL);
	pthread_create(&t3, NULL, (void*)thread_func, NULL);
	pthread_join(t1, NULL);
	pthread_join(t2, NULL);
	pthread_join(t3, NULL);
	return 0;
}
>Fix:
Applying the following patch solves the problem.

Patch attached with submission follows:

Index: lib/libc/stdio/snprintf.c
===================================================================
--- lib/libc/stdio/snprintf.c	(revision 191141)
+++ lib/libc/stdio/snprintf.c	(working copy)
@@ -61,6 +61,7 @@
 	f._bf._base = f._p = (unsigned char *)str;
 	f._bf._size = f._w = n;
 	f._orientation = 0;
+	f._fl_mutex = NULL;
 	memset(&f._mbstate, 0, sizeof(mbstate_t));
 	ret = __vfprintf(&f, fmt, ap);
 	if (on > 0)
Index: lib/libc/stdio/vsnprintf.c
===================================================================
--- lib/libc/stdio/vsnprintf.c	(revision 191141)
+++ lib/libc/stdio/vsnprintf.c	(working copy)
@@ -66,6 +66,7 @@
 	f._bf._base = f._p = (unsigned char *)str;
 	f._bf._size = f._w = n;
 	f._orientation = 0;
+	f._fl_mutex = NULL;
 	memset(&f._mbstate, 0, sizeof(mbstate_t));
 	ret = __vfprintf(&f, fmt, ap);
 	if (on > 0)


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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200904161211.n3GCBuGe098186>