From owner-freebsd-bugs@FreeBSD.ORG Thu Apr 16 12:20:02 2009 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 8D5891065674 for ; Thu, 16 Apr 2009 12:20:02 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 5D8068FC20 for ; Thu, 16 Apr 2009 12:20:02 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.14.3/8.14.3) with ESMTP id n3GCK2br022628 for ; Thu, 16 Apr 2009 12:20:02 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.3/8.14.3/Submit) id n3GCK2Ki022627; Thu, 16 Apr 2009 12:20:02 GMT (envelope-from gnats) Resent-Date: Thu, 16 Apr 2009 12:20:02 GMT Resent-Message-Id: <200904161220.n3GCK2Ki022627@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Tobias Brunner Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 6FACC1065686 for ; Thu, 16 Apr 2009 12:11:56 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21]) by mx1.freebsd.org (Postfix) with ESMTP id 5ACB18FC22 for ; Thu, 16 Apr 2009 12:11:56 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from www.freebsd.org (localhost [127.0.0.1]) by www.freebsd.org (8.14.3/8.14.3) with ESMTP id n3GCBuZ0098187 for ; Thu, 16 Apr 2009 12:11:56 GMT (envelope-from nobody@www.freebsd.org) Received: (from nobody@localhost) by www.freebsd.org (8.14.3/8.14.3/Submit) id n3GCBuGe098186; Thu, 16 Apr 2009 12:11:56 GMT (envelope-from nobody) Message-Id: <200904161211.n3GCBuGe098186@www.freebsd.org> Date: Thu, 16 Apr 2009 12:11:56 GMT From: Tobias Brunner To: freebsd-gnats-submit@FreeBSD.org X-Send-Pr-Version: www-3.1 Cc: Subject: kern/133776: [libc] snprintf(3) and vsnprintf(3) do not properly initialize _fl_mutex X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 16 Apr 2009 12:20:04 -0000 >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 #include #include #include 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: