Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 3 Sep 2002 19:17:37 -0700 (PDT)
From:      Eric Albert <ejalbert@cs.stanford.edu>
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   bin/42397: dlclose for a module loaded with RTLD_GLOBAL can access freed memory and crash
Message-ID:  <200209040217.g842Hb67078576@www.freebsd.org>

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

>Number:         42397
>Category:       bin
>Synopsis:       dlclose for a module loaded with RTLD_GLOBAL can access freed memory and crash
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Sep 03 19:20:01 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator:     Eric Albert
>Release:        4.5
>Organization:
>Environment:
FreeBSD ithilien.qualarius.org 4.5-RELEASE FreeBSD 4.5-RELEASE #0: Mon Jan 28 14:31:56 GMT 2002   murray@builder.freebsdmall.com:/usr/src/sys/compile/GENERIC i386
>Description:
Consider two modules, A and B, where A links against B (B is in A's DAG). If both A and B are loaded via dlopen with the RTLD_GLOBAL flag, then B is unloaded via dlclose, when A is unloaded via dlclose B will not be removed from the list of global libraries. Any future symbol lookups in the application -- any standard function call inside or between a shared object -- can crash.

Specifically, in unload_object in src/libexec/rtld-elf/rtld.c, root is removed from list_global. Any object in root's DAG whose refcount drops to 0 is freed, but isn't removed from list_global. Any future reference to list_global will access freed memory if any one of those objects in root's DAG was loaded with RTLD_GLOBAL.
>How-To-Repeat:
Detecting the problem is dependent on the system's behavior when accessing freed memory, so it isn't easy to demonstrate the issue. It's easy to describe how to see it via code inspection, though:

Shared library A links against B.
In the application, A is loaded via dl_open(/path/to/A, RTLD_GLOBAL). This inserts A into the global list, with B in its DAG.
B is loaded via dl_open(/path/to/B, RTLD_GLOBAL). This modifies the refcount on B and inserts B into the global list (if the first step didn't do that; I'm not sure).
B is unloaded via dl_close. B's refcount drops to 1, and nothing is unloaded.
A is unloaded via dl_close. A's refcount drops to 0. A is removed from the global list. B's refcount drops to 0. In unload_object in src/libexec/rtld-elf/rtld.c, B's underlying data structure is freed, but B is not removed from the global list.
The application calls additional functions in other libraries, prompting a symbol lookup. Since B is still in the global list, access to B's element in that list can cause a crash.
>Fix:
[Not tested]

Take the objlist_remove(&list_global, root) line in unload_object and copy it inside the while loop in that function, to be called with obj instead of root if obj->refcount == 0.
>Release-Note:
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




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