From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 2458 invoked by alias); 13 Mar 2006 13:15:46 -0000 Received: (qmail 2442 invoked by uid 22791); 13 Mar 2006 13:15:46 -0000 X-Spam-Check-By: sourceware.org Received: from sunsite.ms.mff.cuni.cz (HELO sunsite.mff.cuni.cz) (195.113.15.26) by sourceware.org (qpsmtpd/0.31) with ESMTP; Mon, 13 Mar 2006 13:15:42 +0000 Received: from sunsite.mff.cuni.cz (sunsite.mff.cuni.cz [127.0.0.1]) by sunsite.mff.cuni.cz (8.13.1/8.13.1) with ESMTP id k2DDERpH023820; Mon, 13 Mar 2006 14:14:27 +0100 Received: (from jj@localhost) by sunsite.mff.cuni.cz (8.13.1/8.13.1/Submit) id k2DDERdH023816; Mon, 13 Mar 2006 14:14:27 +0100 Date: Mon, 13 Mar 2006 13:15:00 -0000 From: Jakub Jelinek To: Ulrich Drepper , Roland McGrath Cc: Glibc hackers Subject: [PATCH] Fix dlopen memory leaks (BZ#2451) Message-ID: <20060313131427.GW30252@sunsite.mff.cuni.cz> Reply-To: Jakub Jelinek Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.4.1i Mailing-List: contact libc-hacker-help@sourceware.org; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-hacker-owner@sourceware.org X-SW-Source: 2006-03/txt/msg00034.txt.bz2 Hi! If open_verify calls lose (and therefore _dl_signal_error), in one _dl_map_object place we leak realname. We can't free it unconditionally in open_verify though, because the other 2 callers call open_verify with allocaed string rather than malloced. 2006-03-13 Jakub Jelinek [BZ #2451] * elf/dl-load.c (open_verify): Add free_name argument, if true, free name before calling lose. (open_path): Adjust caller. (_dl_map_object): Adjust callers. Free name_copy before calling _dl_signal_error. * elf/Makefile: Add rules to build and run tst-leaks1. * elf/tst-leaks1.c: New test. --- libc/elf/dl-load.c.jj 2006-03-13 13:26:21.000000000 +0100 +++ libc/elf/dl-load.c 2006-03-13 13:53:40.000000000 +0100 @@ -1,5 +1,6 @@ /* Map in a shared object's segments from the file. - Copyright (C) 1995-2002, 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, + 2005, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -1554,7 +1555,7 @@ print_search_path (struct r_search_path_ user might want to know about this. */ static int open_verify (const char *name, struct filebuf *fbp, struct link_map *loader, - int whatcode, bool *found_other_class) + int whatcode, bool *found_other_class, bool free_name) { /* This is the expected ELF header. */ #define ELF32_CLASS ELFCLASS32 @@ -1635,6 +1636,12 @@ open_verify (const char *name, struct fi errstring = (errval == 0 ? N_("file too short") : N_("cannot read file data")); call_lose: + if (free_name) + { + char *realname = (char *) name; + name = strdupa (realname); + free (realname); + } lose (errval, fd, name, NULL, NULL, errstring); } @@ -1821,7 +1828,8 @@ open_path (const char *name, size_t name if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0)) _dl_debug_printf (" trying file=%s\n", buf); - fd = open_verify (buf, fbp, loader, whatcode, found_other_class); + fd = open_verify (buf, fbp, loader, whatcode, found_other_class, + false); if (this_dir->status[cnt] == unknown) { if (fd != -1) @@ -2098,7 +2106,7 @@ _dl_map_object (struct link_map *loader, { fd = open_verify (cached, &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded, - LA_SER_CONFIG, &found_other_class); + LA_SER_CONFIG, &found_other_class, false); if (__builtin_expect (fd != -1, 1)) { realname = local_strdup (cached); @@ -2136,7 +2144,7 @@ _dl_map_object (struct link_map *loader, { fd = open_verify (realname, &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded, 0, - &found_other_class); + &found_other_class, true); if (__builtin_expect (fd, 0) == -1) free (realname); } @@ -2166,8 +2174,11 @@ _dl_map_object (struct link_map *loader, if ((name_copy = local_strdup (name)) == NULL || (l = _dl_new_object (name_copy, name, type, loader, mode, nsid)) == NULL) - _dl_signal_error (ENOMEM, name, NULL, - N_("cannot create shared object descriptor")); + { + free (name_copy); + _dl_signal_error (ENOMEM, name, NULL, + N_("cannot create shared object descriptor")); + } /* Signal that this is a faked entry. */ l->l_faked = 1; /* Since the descriptor is initialized with zero we do not --- libc/elf/Makefile.jj 2006-03-03 14:31:37.000000000 +0100 +++ libc/elf/Makefile 2006-03-13 13:44:49.000000000 +0100 @@ -91,7 +91,7 @@ distribute := rtld-Rules \ order2mod1.c order2mod2.c order2mod3.c order2mod4.c \ tst-stackguard1.c tst-stackguard1-static.c \ tst-array5.c tst-array5-static.c tst-array5dep.c \ - tst-array5.exp + tst-array5.exp tst-leaks1.c CFLAGS-dl-runtime.c = -fexceptions -fasynchronous-unwind-tables CFLAGS-dl-lookup.c = -fexceptions -fasynchronous-unwind-tables @@ -139,7 +139,7 @@ vpath %.c ../locale/programs endif endif -tests = tst-tls1 tst-tls2 tst-tls9 +tests = tst-tls1 tst-tls2 tst-tls9 tst-leaks1 ifeq (yes,$(have-initfini-array)) tests += tst-array1 tst-array2 tst-array3 tst-array4 tst-array5 endif @@ -180,6 +180,7 @@ endif ifeq (yesyes,$(have-fpie)$(build-shared)) tests: $(objpfx)tst-pie1.out endif +tests: $(objpfx)tst-leaks1-mem modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ testobj1_1 failobj constload2 constload3 unloadmod \ dep1 dep2 dep3 dep4 $(modules-vis-$(have-protected)) \ @@ -895,3 +896,9 @@ order2mod2.so-no-z-defs = yes tst-stackguard1-ARGS = --command "$(built-program-cmd) --child" tst-stackguard1-static-ARGS = --command "$(objpfx)tst-stackguard1-static --child" + +$(objpfx)tst-leaks1: $(libdl) +$(objpfx)tst-leaks1-mem: $(objpfx)tst-leaks1.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-leaks1.mtrace > $@ + +tst-leaks1-ENV = MALLOC_TRACE=$(objpfx)tst-leaks1.mtrace --- libc/elf/tst-leaks1.c.jj 2006-03-13 13:34:43.000000000 +0100 +++ libc/elf/tst-leaks1.c 2006-03-13 13:50:32.000000000 +0100 @@ -0,0 +1,24 @@ +#include +#include +#include + +int +main (void) +{ + mtrace (); + + int ret = 0; + for (int i = 0; i < 10; i++) + { + void *h = dlopen (i < 5 ? "./tst-leaks1.c" + : "$ORIGIN/tst-leaks1.o", RTLD_LAZY); + if (h != NULL) + { + puts ("dlopen unexpectedly succeeded"); + ret = 1; + dlclose (h); + } + } + + return ret; +} Jakub