diff options
author | Rich Felker <dalias@aerifal.cx> | 2017-11-13 15:27:10 -0500 |
---|---|---|
committer | Rich Felker <dalias@aerifal.cx> | 2017-11-13 15:27:10 -0500 |
commit | a71b46cfd289aa0ff829fc9a436c59c398f8326d (patch) | |
tree | d830e2f59a7d4dd89aad7288224597b80af5677e | |
parent | d060edf6c569ba9df4b52d6bcd93edde812869c9 (diff) | |
download | musl-a71b46cfd289aa0ff829fc9a436c59c398f8326d.tar.gz musl-a71b46cfd289aa0ff829fc9a436c59c398f8326d.tar.bz2 musl-a71b46cfd289aa0ff829fc9a436c59c398f8326d.tar.xz musl-a71b46cfd289aa0ff829fc9a436c59c398f8326d.zip |
fix malloc state corruption when ldso rejects loading a second libc
commit c49d3c8adadfa24235fcf4779bb722b1aa6f480b added logic to detect
attempts to load libc.so via another name and instead redirect to the
existing libc, rather than loading two and producing dangerously
inconsistent state. however, the check for and unmapping of the
duplicate libc happened after reclaim_gaps was already called,
donating the slack space around the writable segment to malloc.
subsequent unmapping of the library then invalidated malloc's free
lists.
fix the issue by moving the call to reclaim_gaps out of map_library
into load_library, after the duplicate libc check but before the first
call to calloc, so that the gaps can still be used to satisfy the
allocation of struct dso. this change also eliminates the need for an
ugly hack (temporarily setting runtime=1) to avoid reclaim_gaps when
loading the main program via map_library, which happens when ldso is
invoked as a command.
only programs/libraries erroneously containing a DT_NEEDED reference
to libc.so via an absolute pathname or symlink were affected by this
issue.
-rw-r--r-- | ldso/dynlink.c | 7 |
1 files changed, 4 insertions, 3 deletions
diff --git a/ldso/dynlink.c b/ldso/dynlink.c index 35a90aef..4b4841f9 100644 --- a/ldso/dynlink.c +++ b/ldso/dynlink.c @@ -725,7 +725,6 @@ done_mapping: dso->base = base; dso->dynv = laddr(dso, dyn); if (dso->tls.size) dso->tls.image = laddr(dso, tls_image); - if (!runtime) reclaim_gaps(dso); free(allocated_buf); return map; noexec: @@ -1044,6 +1043,10 @@ static struct dso *load_library(const char *name, struct dso *needed_by) unmap_library(&temp_dso); return load_library("libc.so", needed_by); } + /* Past this point, if we haven't reached runtime yet, ldso has + * committed either to use the mapped library or to abort execution. + * Unmapping is not possible, so we can safely reclaim gaps. */ + if (!runtime) reclaim_gaps(&temp_dso); /* Allocate storage for the new DSO. When there is TLS, this * storage must include a reservation for all pre-existing @@ -1545,13 +1548,11 @@ _Noreturn void __dls3(size_t *sp) dprintf(2, "%s: cannot load %s: %s\n", ldname, argv[0], strerror(errno)); _exit(1); } - runtime = 1; Ehdr *ehdr = (void *)map_library(fd, &app); if (!ehdr) { dprintf(2, "%s: %s: Not a valid dynamic program\n", ldname, argv[0]); _exit(1); } - runtime = 0; close(fd); ldso.name = ldname; app.name = argv[0]; |