| Anonymous | Login | Signup for a new account | 11-10-2008 13:49 PST |
| Main | My View | View Issues | Change Log | Docs |
| Viewing Issue Simple Details [ Jump to Notes ] | [ View Advanced ] [ Issue History ] [ Print ] | ||||||||
| ID | Category | Severity | Reproducibility | Date Submitted | Last Update | ||||
| 0005784 | [uClibc] Shared Library Support | major | always | 10-28-08 10:29 | 10-31-08 02:02 | ||||
| Reporter | estesp | View Status | public | ||||||
| Assigned To | uClibc | ||||||||
| Priority | normal | Resolution | fixed | ||||||
| Status | closed | Product Version | 0.9.30 | ||||||
| Summary | 0005784: ref counting can wrap in libdl.so | ||||||||
| Description |
Recently while investigating a problem with pam authentication+uClibc, my investigation led me to the point where I realized that the dlopen() and dlclose() management of ref. counting is not balanced, which leads to the heaviest "DL_NEEDED" libraries basically getting incremented to the point of overflowing "unsigned short usage_count". This leads to a nasty situation where libc.so is munmapped (because usage_count == 0), and the next call to a C runtime function traps, of course. The exact point of trap is in ldso/libdl/libdl.c around line 533: 529 _dl_munmap((void*)tpnt->loadaddr, end); 530 /* Free elements in RTLD_LOCAL scope list */ 531 for (runp = tpnt->rtld_local; runp; runp = tmp) { 532 tmp = runp->next; 533 free(runp); 534 } When the wrap happens, you will find this code executed where tpnt is pointing at libc.so--therefore the dl_munmap @ 529 will actually unmap the code segment of libc.so. When the free() at line 533 is executed, it will segfault, given the offset of the function free() (which was in libc.so's code segment) is now unmapped/inaccessible memory to this process. |
||||||||
| Additional Information |
I will add a simple testcase that can be used to reproduce this problem. Given a few factors the number of iterations to recreate can vary, but an easy way to 'watch' the libc.so ref count wrap is to add a breakpoint at libdl.c:247 and then use the following commands function of gdb to output the refcount each time: (at gdb prompt) > commands <brnum> > silent > printf "%d : %s\n",(*tpnt1)->usage_count, lpntstr > cont > end Now you can continue and watch the usage count of each library loaded climb. A temporary fix, of course, is to make sure that the usage count does not wrap--this can be done easily in the function which increments usage count: ldso/ldso/dl-elf.c around line 381. Right after the usage_count is incremented, a check can be inserted for 0.. an incremented usage_count could never be zero, so when it is you know you have wrapped--simple set back to some large value near unsigned int max (e.g. 0xfff0) and the problem is worked around. I believe the right permanent fix is to understand why ref. counting is not balanced between load and unload of dependent libs, however, that code is more involved and probably needs someone well versed in the dlopen/dlclose design/architecture. |
||||||||
| Attached Files |
|
||||||||
|
|
|||||||||
| Copyright © 2000 - 2006 Mantis Group |