From patchwork Sun Mar 8 20:46:37 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aurelien Jarno X-Patchwork-Id: 5523 Received: (qmail 61608 invoked by alias); 8 Mar 2015 20:46:44 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 61594 invoked by uid 89); 8 Mar 2015 20:46:43 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=BAYES_00, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: hall.aurel32.net Date: Sun, 8 Mar 2015 21:46:37 +0100 From: Aurelien Jarno To: libc-alpha@sourceware.org Subject: [PATCH][BUG 18093] Fix ldconfig segmentation fault with corrupted cache Message-ID: <20150308204637.GA21863@aurel32.net> Mail-Followup-To: libc-alpha@sourceware.org MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.23 (2014-03-12) ldconfig is using an aux-cache to speed up the ld.so.cache update. It is read by mmaping the file to a structure which contains data offsets used as pointers. As they are not checked, it is not hard to get ldconfig to segfault with a corrupted file. This happens for instance if the file is truncated, which is common following a filesystem check following a system crash. This can be reproduced for example by truncating the file to roughly half of it's size. There is already in some code in elf/cache.c (load_aux_cache) to check for a corrupted aux cache, but it happens to be broken and not enough. The test (aux_cache->nlibs >= aux_cache_size) compares the number of libs entry with the cache size. It's a non sense, as it basically assumes that each library entry is a 1 byte... Instead the patch below computes the theoretical cache size using the headers and compares it to the real size. Another corruption can happen if the pointers to the string table is corrupted though in that case it means that the file has been more than just truncated. The patch below ignores entries pointing outside of the string table, they will be added with the current ldconfig run. (This patch is based on an initial patch from Lennart Sorensen). 2015-03-08 Aurelien Jarno [BZ #18093] * elf/cache.c (load_aux_cache): Regenerate the cache if it has the wrong size. Ignore entries pointing outside of the mmaped memory. diff --git a/elf/cache.c b/elf/cache.c index 1732268..9131e08 100644 --- a/elf/cache.c +++ b/elf/cache.c @@ -698,7 +698,9 @@ load_aux_cache (const char *aux_cache_name) if (aux_cache == MAP_FAILED || aux_cache_size < sizeof (struct aux_cache_file) || memcmp (aux_cache->magic, AUX_CACHEMAGIC, sizeof AUX_CACHEMAGIC - 1) - || aux_cache->nlibs >= aux_cache_size) + || aux_cache_size != (sizeof(struct aux_cache_file) + + aux_cache->nlibs * sizeof(struct aux_cache_file_entry) + + aux_cache->len_strings)) { close (fd); init_aux_cache (); @@ -711,12 +713,13 @@ load_aux_cache (const char *aux_cache_name) const char *aux_cache_data = (const char *) &aux_cache->libs[aux_cache->nlibs]; for (unsigned int i = 0; i < aux_cache->nlibs; ++i) - insert_to_aux_cache (&aux_cache->libs[i].id, - aux_cache->libs[i].flags, - aux_cache->libs[i].osversion, - aux_cache->libs[i].soname == 0 - ? NULL : aux_cache_data + aux_cache->libs[i].soname, - 0); + if (aux_cache->libs[i].soname < aux_cache->len_strings) + insert_to_aux_cache (&aux_cache->libs[i].id, + aux_cache->libs[i].flags, + aux_cache->libs[i].osversion, + aux_cache->libs[i].soname == 0 + ? NULL : aux_cache_data + aux_cache->libs[i].soname, + 0); munmap (aux_cache, aux_cache_size); close (fd);