From patchwork Mon Jun 22 15:14:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 39754 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 93E70394BE20; Mon, 22 Jun 2020 15:15:10 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 93E70394BE20 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1592838910; bh=2B1E+cFFElMYR2YZjVlBubBjCDD8FuUn+phFb/Lxipc=; h=To:Subject:In-Reply-To:References:Date:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=mjtmXpGV1VX6hC6eimyjT6cCP7mZpJkLFuDCt1qvItkYWTnHfUv5t4/iCii8XwfQF t/vVzO6Kfsmm/R1s1pTKfbrrpoWvL2iR3WHDZ09PFkbQwzQjz+OztWcNuHqEv2F1KD wBUiiGWLZAqn+Er3ixf6Y4AjgMA1tweoaYgC7s9E= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from us-smtp-1.mimecast.com (us-smtp-delivery-1.mimecast.com [205.139.110.120]) by sourceware.org (Postfix) with ESMTP id E31FF3952011 for ; Mon, 22 Jun 2020 15:15:07 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org E31FF3952011 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-508-FQtl7zDmOhOlExovec6Olg-1; Mon, 22 Jun 2020 11:15:04 -0400 X-MC-Unique: FQtl7zDmOhOlExovec6Olg-1 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 11B4DEC1B4 for ; Mon, 22 Jun 2020 15:15:02 +0000 (UTC) Received: from oldenburg2.str.redhat.com (ovpn-112-185.ams2.redhat.com [10.36.112.185]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 5B19F5C1BD for ; Mon, 22 Jun 2020 15:15:01 +0000 (UTC) To: libc-alpha@sourceware.org Subject: [PATCH 23/30] elf: Add endianness markup to ld.so.cache In-Reply-To: References: Message-Id: <35954fabd6bd6c82de54298f322c23eee6b6a54c.1592836143.git.fweimer@redhat.com> Date: Mon, 22 Jun 2020 17:14:59 +0200 User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.3 (gnu/linux) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-13.0 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Florian Weimer via Libc-alpha From: Florian Weimer Reply-To: Florian Weimer Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" Use a reserved byte in the new format cache header to indicate whether the file is in little endian or big endian format. Eventually, this information could be used to provide a unified cache for qemu-user and similiar scenarios. --- elf/cache.c | 11 ++++++++++ elf/dl-cache.c | 20 +++++++++++++++++- sysdeps/generic/dl-cache.h | 43 +++++++++++++++++++++++++++++++++++++- 3 files changed, 72 insertions(+), 2 deletions(-) diff --git a/elf/cache.c b/elf/cache.c index d92b4e59c1..c10981641f 100644 --- a/elf/cache.c +++ b/elf/cache.c @@ -152,6 +152,14 @@ print_entry (const char *lib, int flag, unsigned int osversion, printf (") => %s\n", key); } +/* Print an error and exit if the new-file cache is internally + inconsistent. */ +static void +check_new_cache (struct cache_file_new *cache) +{ + if (! cache_file_new_matches_endian (cache)) + error (EXIT_FAILURE, 0, _("Cache file has wrong endianness.\n")); +} /* Print the whole cache file, if a file contains the new cache format hidden in the old one, print the contents of the new format. */ @@ -193,6 +201,7 @@ print_cache (const char *cache_name) || memcmp (cache_new->version, CACHE_VERSION, sizeof CACHE_VERSION - 1)) error (EXIT_FAILURE, 0, _("File is not a cache file.\n")); + check_new_cache (cache_new); format = 1; /* This is where the strings start. */ cache_data = (const char *) cache_new; @@ -222,6 +231,7 @@ print_cache (const char *cache_name) && memcmp (cache_new->version, CACHE_VERSION, sizeof CACHE_VERSION - 1) == 0) { + check_new_cache (cache_new); cache_data = (const char *) cache_new; format = 1; } @@ -361,6 +371,7 @@ save_cache (const char *cache_name) file_entries_new->nlibs = cache_entry_count; file_entries_new->len_strings = total_strlen; + file_entries_new->flags = cache_file_new_flags_endian; } /* Pad for alignment of cache_file_new. */ diff --git a/elf/dl-cache.c b/elf/dl-cache.c index 93d185e788..3aa8ed6c13 100644 --- a/elf/dl-cache.c +++ b/elf/dl-cache.c @@ -210,6 +210,11 @@ _dl_load_cache_lookup (const char *name) && ((cachesize - sizeof *cache_new) / sizeof (struct file_entry_new) >= ((struct cache_file_new *) file)->nlibs)) { + if (! cache_file_new_matches_endian (file)) + { + __munmap (file, cachesize); + file = (void *) -1; + } cache_new = file; cache = file; } @@ -231,7 +236,20 @@ _dl_load_cache_lookup (const char *name) if (cachesize < (offset + sizeof (struct cache_file_new)) || memcmp (cache_new->magic, CACHEMAGIC_VERSION_NEW, sizeof CACHEMAGIC_VERSION_NEW - 1) != 0) - cache_new = (void *) -1; + cache_new = (void *) -1; + else + { + if (! cache_file_new_matches_endian (cache_new)) + { + /* The old-format part of the cache is bogus as well + if the endianness does not match. (But it is + unclear how the new header can be located if the + endianess does not match.) */ + cache = (void *) -1; + cache_new = (void *) -1; + __munmap (file, cachesize); + } + } } else { diff --git a/sysdeps/generic/dl-cache.h b/sysdeps/generic/dl-cache.h index 6b310e9e15..1b04211f6b 100644 --- a/sysdeps/generic/dl-cache.h +++ b/sysdeps/generic/dl-cache.h @@ -16,6 +16,11 @@ License along with the GNU C Library; if not, see . */ +#ifndef _DL_CACHE_H +#define _DL_CACHE_H + +#include +#include #include #ifndef _DL_CACHE_DEFAULT_ID @@ -83,21 +88,57 @@ struct file_entry_new uint64_t hwcap; /* Hwcap entry. */ }; +/* See flags member of struct cache_file_new below. */ +enum + { + cache_file_new_flags_endian = (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + ? 2 : 3) + }; + struct cache_file_new { char magic[sizeof CACHEMAGIC_NEW - 1]; char version[sizeof CACHE_VERSION - 1]; uint32_t nlibs; /* Number of entries. */ uint32_t len_strings; /* Size of string table. */ - uint32_t unused[5]; /* Leave space for future extensions + + /* flags & 3 is used to indicate the endianness of the cache. + 0: no endianness information available + (An old ldconfig version without endianness support wrote the file.) + 1: cache is invalid + 2: little endian + 3: big endian + + The remaining bits are unused and should be generated as zero and + ignored by readers. */ + uint8_t flags; + + uint8_t padding_unsed[3]; /* Not used, for future extensions. */ + + uint32_t unused[4]; /* Leave space for future extensions and align to 8 byte boundary. */ struct file_entry_new libs[0]; /* Entries describing libraries. */ /* After this the string table of size len_strings is found. */ }; +/* Returns false if *CACHE has the wrong endianness for this + architecture, and true if the endianness matches (or is + unknown). */ +static inline bool +cache_file_new_matches_endian (const struct cache_file_new *cache) +{ + /* A zero value for cache->flags means that no endianness + information is available. */ + return cache->flags == 0 + || (cache->flags & 3) == cache_file_new_flags_endian; +} + + /* Used to align cache_file_new. */ #define ALIGN_CACHE(addr) \ (((addr) + __alignof__ (struct cache_file_new) -1) \ & (~(__alignof__ (struct cache_file_new) - 1))) extern int _dl_cache_libcmp (const char *p1, const char *p2) attribute_hidden; + +#endif /* _DL_CACHE_H */