Blame elf/dl-cache.c

Packit 6c4009
/* Support for reading /etc/ld.so.cache files written by Linux ldconfig.
Packit 6c4009
   Copyright (C) 1996-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <ldsodefs.h>
Packit 6c4009
#include <sys/mman.h>
Packit 6c4009
#include <dl-cache.h>
Packit 6c4009
#include <dl-procinfo.h>
Packit 6c4009
#include <stdint.h>
Packit 6c4009
#include <_itoa.h>
Packit 6c4009
#include <dl-hwcaps.h>
Packit 6c4009
Packit 6c4009
#ifndef _DL_PLATFORMS_COUNT
Packit 6c4009
# define _DL_PLATFORMS_COUNT 0
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* This is the starting address and the size of the mmap()ed file.  */
Packit 6c4009
static struct cache_file *cache;
Packit 6c4009
static struct cache_file_new *cache_new;
Packit 6c4009
static size_t cachesize;
Packit 6c4009
Packit Bot e2c958
#ifdef SHARED
Packit Bot e2c958
/* This is used to cache the priorities of glibc-hwcaps
Packit Bot e2c958
   subdirectories.  The elements of _dl_cache_priorities correspond to
Packit Bot e2c958
   the strings in the cache_extension_tag_glibc_hwcaps section.  */
Packit Bot e2c958
static uint32_t *glibc_hwcaps_priorities;
Packit Bot e2c958
static uint32_t glibc_hwcaps_priorities_length;
Packit Bot e2c958
static uint32_t glibc_hwcaps_priorities_allocated;
Packit Bot e2c958
Packit Bot e2c958
/* True if the full malloc was used to allocated the array.  */
Packit Bot e2c958
static bool glibc_hwcaps_priorities_malloced;
Packit Bot e2c958
Packit Bot e2c958
/* Deallocate the glibc_hwcaps_priorities array.  */
Packit Bot e2c958
static void
Packit Bot e2c958
glibc_hwcaps_priorities_free (void)
Packit Bot e2c958
{
Packit Bot e2c958
  /* When the minimal malloc is in use, free does not do anything,
Packit Bot e2c958
     so it does not make sense to call it.  */
Packit Bot e2c958
  if (glibc_hwcaps_priorities_malloced)
Packit Bot e2c958
    free (glibc_hwcaps_priorities);
Packit Bot e2c958
  glibc_hwcaps_priorities = NULL;
Packit Bot e2c958
  glibc_hwcaps_priorities_allocated = 0;
Packit Bot e2c958
}
Packit Bot e2c958
Packit Bot e2c958
/* Ordered comparison of a hwcaps string from the cache on the left
Packit Bot e2c958
   (identified by its string table index) and a _dl_hwcaps_priorities
Packit Bot e2c958
   element on the right.  */
Packit Bot e2c958
static int
Packit Bot e2c958
glibc_hwcaps_compare (uint32_t left_index, struct dl_hwcaps_priority *right)
Packit Bot e2c958
{
Packit Bot e2c958
  const char *left_name = (const char *) cache + left_index;
Packit Bot e2c958
  uint32_t left_name_length = strlen (left_name);
Packit Bot e2c958
  uint32_t to_compare;
Packit Bot e2c958
  if (left_name_length < right->name_length)
Packit Bot e2c958
    to_compare = left_name_length;
Packit Bot e2c958
  else
Packit Bot e2c958
    to_compare = right->name_length;
Packit Bot e2c958
  int cmp = memcmp (left_name, right->name, to_compare);
Packit Bot e2c958
  if (cmp != 0)
Packit Bot e2c958
    return cmp;
Packit Bot e2c958
  if (left_name_length < right->name_length)
Packit Bot e2c958
    return -1;
Packit Bot e2c958
  else if (left_name_length > right->name_length)
Packit Bot e2c958
    return 1;
Packit Bot e2c958
  else
Packit Bot e2c958
    return 0;
Packit Bot e2c958
}
Packit Bot e2c958
Packit Bot e2c958
/* Initialize the glibc_hwcaps_priorities array and its length,
Packit Bot e2c958
   glibc_hwcaps_priorities_length.  */
Packit Bot e2c958
static void
Packit Bot e2c958
glibc_hwcaps_priorities_init (void)
Packit Bot e2c958
{
Packit Bot e2c958
  struct cache_extension_all_loaded ext;
Packit Bot e2c958
  if (!cache_extension_load (cache_new, cache, cachesize, &ext))
Packit Bot e2c958
    return;
Packit Bot e2c958
Packit Bot e2c958
  uint32_t length = (ext.sections[cache_extension_tag_glibc_hwcaps].size
Packit Bot e2c958
		     / sizeof (uint32_t));
Packit Bot e2c958
  if (length > glibc_hwcaps_priorities_allocated)
Packit Bot e2c958
    {
Packit Bot e2c958
      glibc_hwcaps_priorities_free ();
Packit Bot e2c958
Packit Bot e2c958
      uint32_t *new_allocation = malloc (length * sizeof (uint32_t));
Packit Bot e2c958
      if (new_allocation == NULL)
Packit Bot e2c958
	/* This effectively disables hwcaps on memory allocation
Packit Bot e2c958
	   errors.  */
Packit Bot e2c958
	return;
Packit Bot e2c958
Packit Bot e2c958
      glibc_hwcaps_priorities = new_allocation;
Packit Bot e2c958
      glibc_hwcaps_priorities_allocated = length;
Packit Bot e2c958
      glibc_hwcaps_priorities_malloced = __rtld_malloc_is_complete ();
Packit Bot e2c958
    }
Packit Bot e2c958
Packit Bot e2c958
  /* Compute the priorities for the subdirectories by merging the
Packit Bot e2c958
     array in the cache with the dl_hwcaps_priorities array.  */
Packit Bot e2c958
  const uint32_t *left = ext.sections[cache_extension_tag_glibc_hwcaps].base;
Packit Bot e2c958
  const uint32_t *left_end = left + length;
Packit Bot e2c958
  struct dl_hwcaps_priority *right = _dl_hwcaps_priorities;
Packit Bot e2c958
  struct dl_hwcaps_priority *right_end = right + _dl_hwcaps_priorities_length;
Packit Bot e2c958
  uint32_t *result = glibc_hwcaps_priorities;
Packit Bot e2c958
Packit Bot e2c958
  while (left < left_end && right < right_end)
Packit Bot e2c958
    {
Packit Bot e2c958
      if (*left < cachesize)
Packit Bot e2c958
	{
Packit Bot e2c958
	  int cmp = glibc_hwcaps_compare (*left, right);
Packit Bot e2c958
	  if (cmp == 0)
Packit Bot e2c958
	    {
Packit Bot e2c958
	      *result = right->priority;
Packit Bot e2c958
	      ++result;
Packit Bot e2c958
	      ++left;
Packit Bot e2c958
	      ++right;
Packit Bot e2c958
	    }
Packit Bot e2c958
	  else if (cmp < 0)
Packit Bot e2c958
	    {
Packit Bot e2c958
	      *result = 0;
Packit Bot e2c958
	      ++result;
Packit Bot e2c958
	      ++left;
Packit Bot e2c958
	    }
Packit Bot e2c958
	  else
Packit Bot e2c958
	    ++right;
Packit Bot e2c958
	}
Packit Bot e2c958
      else
Packit Bot e2c958
	{
Packit Bot e2c958
	  *result = 0;
Packit Bot e2c958
	  ++result;
Packit Bot e2c958
	}
Packit Bot e2c958
    }
Packit Bot e2c958
  while (left < left_end)
Packit Bot e2c958
    {
Packit Bot e2c958
      *result = 0;
Packit Bot e2c958
      ++result;
Packit Bot e2c958
      ++left;
Packit Bot e2c958
    }
Packit Bot e2c958
Packit Bot e2c958
  glibc_hwcaps_priorities_length = length;
Packit Bot e2c958
}
Packit Bot e2c958
Packit Bot e2c958
/* Return the priority of the cache_extension_tag_glibc_hwcaps section
Packit Bot e2c958
   entry at INDEX.  Zero means do not use.  Otherwise, lower values
Packit Bot e2c958
   indicate greater preference.  */
Packit Bot e2c958
static uint32_t
Packit Bot e2c958
glibc_hwcaps_priority (uint32_t index)
Packit Bot e2c958
{
Packit Bot e2c958
  /* This does not need to repeated initialization attempts because
Packit Bot e2c958
     this function is only called if there is glibc-hwcaps data in the
Packit Bot e2c958
     cache, so the first call initializes the glibc_hwcaps_priorities
Packit Bot e2c958
     array.  */
Packit Bot e2c958
  if (glibc_hwcaps_priorities_length == 0)
Packit Bot e2c958
    glibc_hwcaps_priorities_init ();
Packit Bot e2c958
Packit Bot e2c958
  if (index < glibc_hwcaps_priorities_length)
Packit Bot e2c958
    return glibc_hwcaps_priorities[index];
Packit Bot e2c958
  else
Packit Bot e2c958
    return 0;
Packit Bot e2c958
}
Packit Bot e2c958
#endif /* SHARED */
Packit Bot e2c958
Packit Bot 5df1b6
/* True if PTR is a valid string table index.  */
Packit Bot 5df1b6
static inline bool
Packit Bot 5df1b6
_dl_cache_verify_ptr (uint32_t ptr, size_t string_table_size)
Packit Bot 5df1b6
{
Packit Bot 5df1b6
  return ptr < string_table_size;
Packit Bot 5df1b6
}
Packit Bot 5df1b6
Packit Bot 5df1b6
/* Compute the address of the element INDEX of the array at LIBS.
Packit Bot 5df1b6
   Conceptually, this is &LIBS[INDEX], but use ENTRY_SIZE for the size
Packit Bot 5df1b6
   of *LIBS.  */
Packit Bot 5df1b6
static inline const struct file_entry *
Packit Bot 5df1b6
_dl_cache_file_entry (const struct file_entry *libs, size_t entry_size,
Packit Bot 5df1b6
		      size_t index)
Packit Bot 5df1b6
{
Packit Bot 5df1b6
  return (const void *) libs + index * entry_size;
Packit Bot 5df1b6
}
Packit Bot 5df1b6
Packit Bot 5df1b6
/* We use binary search since the table is sorted in the cache file.
Packit Bot 5df1b6
   The first matching entry in the table is returned.  It is important
Packit Bot 5df1b6
   to use the same algorithm as used while generating the cache file.
Packit Bot 5df1b6
   STRING_TABLE_SIZE indicates the maximum offset in STRING_TABLE at
Packit Bot 5df1b6
   which data is mapped; it is not exact.  */
Packit Bot 5df1b6
static const char *
Packit Bot 5df1b6
search_cache (const char *string_table, uint32_t string_table_size,
Packit Bot 5df1b6
	      struct file_entry *libs, uint32_t nlibs, uint32_t entry_size,
Packit Bot 5df1b6
	      const char *name)
Packit Bot 5df1b6
{
Packit Bot 5df1b6
  /* Used by the HWCAP check in the struct file_entry_new case.  */
Packit Bot 5df1b6
  uint64_t platform = _dl_string_platform (GLRO (dl_platform));
Packit Bot 5df1b6
  if (platform != (uint64_t) -1)
Packit Bot 5df1b6
    platform = 1ULL << platform;
Packit Bot 5df1b6
  uint64_t hwcap_mask = GET_HWCAP_MASK ();
Packit Bot 5df1b6
#define _DL_HWCAP_TLS_MASK (1LL << 63)
Packit Bot 5df1b6
  uint64_t hwcap_exclude = ~((GLRO (dl_hwcap) & hwcap_mask)
Packit Bot 5df1b6
			     | _DL_HWCAP_PLATFORM | _DL_HWCAP_TLS_MASK);
Packit Bot 5df1b6
Packit Bot 5df1b6
  int left = 0;
Packit Bot 5df1b6
  int right = nlibs - 1;
Packit Bot 5df1b6
  const char *best = NULL;
Packit Bot e2c958
#ifdef SHARED
Packit Bot e2c958
  uint32_t best_priority = 0;
Packit Bot e2c958
#endif
Packit Bot 5df1b6
Packit Bot 5df1b6
  while (left <= right)
Packit Bot 5df1b6
    {
Packit Bot 5df1b6
      int middle = (left + right) / 2;
Packit Bot 5df1b6
      uint32_t key = _dl_cache_file_entry (libs, entry_size, middle)->key;
Packit Bot 5df1b6
Packit Bot 5df1b6
      /* Make sure string table indices are not bogus before using
Packit Bot 5df1b6
	 them.  */
Packit Bot 5df1b6
      if (!_dl_cache_verify_ptr (key, string_table_size))
Packit Bot 5df1b6
	return NULL;
Packit Bot 5df1b6
Packit Bot 5df1b6
      /* Actually compare the entry with the key.  */
Packit Bot 5df1b6
      int cmpres = _dl_cache_libcmp (name, string_table + key);
Packit Bot 5df1b6
      if (__glibc_unlikely (cmpres == 0))
Packit Bot 5df1b6
	{
Packit Bot 5df1b6
	  /* Found it.  LEFT now marks the last entry for which we
Packit Bot 5df1b6
	     know the name is correct.  */
Packit Bot 5df1b6
	  left = middle;
Packit Bot 5df1b6
Packit Bot 5df1b6
	  /* There might be entries with this name before the one we
Packit Bot 5df1b6
	     found.  So we have to find the beginning.  */
Packit Bot 5df1b6
	  while (middle > 0)
Packit Bot 5df1b6
	    {
Packit Bot 5df1b6
	      key = _dl_cache_file_entry (libs, entry_size, middle - 1)->key;
Packit Bot 5df1b6
	      /* Make sure string table indices are not bogus before
Packit Bot 5df1b6
		 using them.  */
Packit Bot 5df1b6
	      if (!_dl_cache_verify_ptr (key, string_table_size)
Packit Bot 5df1b6
		  /* Actually compare the entry.  */
Packit Bot 5df1b6
		  || _dl_cache_libcmp (name, string_table + key) != 0)
Packit Bot 5df1b6
		break;
Packit Bot 5df1b6
	      --middle;
Packit Bot 5df1b6
	    }
Packit Bot 5df1b6
Packit Bot 5df1b6
	  do
Packit Bot 5df1b6
	    {
Packit Bot 5df1b6
	      int flags;
Packit Bot 5df1b6
	      const struct file_entry *lib
Packit Bot 5df1b6
		= _dl_cache_file_entry (libs, entry_size, middle);
Packit Bot 5df1b6
Packit Bot 5df1b6
	      /* Only perform the name test if necessary.  */
Packit Bot 5df1b6
	      if (middle > left
Packit Bot 5df1b6
		  /* We haven't seen this string so far.  Test whether the
Packit Bot 5df1b6
		     index is ok and whether the name matches.  Otherwise
Packit Bot 5df1b6
		     we are done.  */
Packit Bot 5df1b6
		  && (! _dl_cache_verify_ptr (lib->key, string_table_size)
Packit Bot 5df1b6
		      || (_dl_cache_libcmp (name, string_table + lib->key)
Packit Bot 5df1b6
			  != 0)))
Packit Bot 5df1b6
		break;
Packit Bot 5df1b6
Packit Bot 5df1b6
	      flags = lib->flags;
Packit Bot 5df1b6
	      if (_dl_cache_check_flags (flags)
Packit Bot 5df1b6
		  && _dl_cache_verify_ptr (lib->value, string_table_size))
Packit Bot 5df1b6
		{
Packit Bot 5df1b6
		  if (best == NULL || flags == GLRO (dl_correct_cache_id))
Packit Bot 5df1b6
		    {
Packit Bot e2c958
		      /* Named/extension hwcaps get slightly different
Packit Bot e2c958
			 treatment: We keep searching for a better
Packit Bot e2c958
			 match.  */
Packit Bot e2c958
		      bool named_hwcap = false;
Packit Bot e2c958
Packit Bot 5df1b6
		      if (entry_size >= sizeof (struct file_entry_new))
Packit Bot 5df1b6
			{
Packit Bot 5df1b6
			  /* The entry is large enough to include
Packit Bot 5df1b6
			     HWCAP data.  Check it.  */
Packit Bot 5df1b6
			  struct file_entry_new *libnew
Packit Bot 5df1b6
			    = (struct file_entry_new *) lib;
Packit Bot 5df1b6
Packit Bot e2c958
#ifdef SHARED
Packit Bot e2c958
			  named_hwcap = dl_cache_hwcap_extension (libnew);
Packit Bot e2c958
#endif
Packit Bot e2c958
Packit Bot e2c958
			  /* The entries with named/extension hwcaps
Packit Bot e2c958
			     have been exhausted.  Return the best
Packit Bot e2c958
			     match encountered so far if there is
Packit Bot e2c958
			     one.  */
Packit Bot e2c958
			  if (!named_hwcap && best != NULL)
Packit Bot e2c958
			    break;
Packit Bot e2c958
Packit Bot e2c958
			  if ((libnew->hwcap & hwcap_exclude) && !named_hwcap)
Packit Bot 5df1b6
			    continue;
Packit Bot 5df1b6
			  if (GLRO (dl_osversion)
Packit Bot 5df1b6
			      && libnew->osversion > GLRO (dl_osversion))
Packit Bot 5df1b6
			    continue;
Packit Bot 5df1b6
			  if (_DL_PLATFORMS_COUNT
Packit Bot 5df1b6
			      && (libnew->hwcap & _DL_HWCAP_PLATFORM) != 0
Packit Bot 5df1b6
			      && ((libnew->hwcap & _DL_HWCAP_PLATFORM)
Packit Bot 5df1b6
				  != platform))
Packit Bot 5df1b6
			    continue;
Packit Bot e2c958
Packit Bot e2c958
#ifdef SHARED
Packit Bot e2c958
			  /* For named hwcaps, determine the priority
Packit Bot e2c958
			     and see if beats what has been found so
Packit Bot e2c958
			     far.  */
Packit Bot e2c958
			  if (named_hwcap)
Packit Bot e2c958
			    {
Packit Bot e2c958
			      uint32_t entry_priority
Packit Bot e2c958
				= glibc_hwcaps_priority (libnew->hwcap);
Packit Bot e2c958
			      if (entry_priority == 0)
Packit Bot e2c958
				/* Not usable at all.  Skip.  */
Packit Bot e2c958
				continue;
Packit Bot e2c958
			      else if (best == NULL
Packit Bot e2c958
				       || entry_priority < best_priority)
Packit Bot e2c958
				/* This entry is of higher priority
Packit Bot e2c958
				   than the previous one, or it is the
Packit Bot e2c958
				   first entry.  */
Packit Bot e2c958
				best_priority = entry_priority;
Packit Bot e2c958
			      else
Packit Bot e2c958
				/* An entry has already been found,
Packit Bot e2c958
				   but it is a better match.  */
Packit Bot e2c958
				continue;
Packit Bot e2c958
			    }
Packit Bot e2c958
#endif /* SHARED */
Packit Bot 5df1b6
			}
Packit Bot 5df1b6
Packit Bot 5df1b6
		      best = string_table + lib->value;
Packit Bot 5df1b6
Packit Bot e2c958
		      if (flags == GLRO (dl_correct_cache_id)
Packit Bot e2c958
			  && !named_hwcap)
Packit Bot 5df1b6
			/* We've found an exact match for the shared
Packit Bot 5df1b6
			   object and no general `ELF' release.  Stop
Packit Bot e2c958
			   searching, but not if a named (extension)
Packit Bot e2c958
			   hwcap is used.  In this case, an entry with
Packit Bot e2c958
			   a higher priority may come up later.  */
Packit Bot 5df1b6
			break;
Packit Bot 5df1b6
		    }
Packit Bot 5df1b6
		}
Packit Bot 5df1b6
	    }
Packit Bot 5df1b6
	  while (++middle <= right);
Packit Bot 5df1b6
	  break;
Packit Bot 5df1b6
	}
Packit Service 22146a
Packit Bot 5df1b6
      if (cmpres < 0)
Packit Bot 5df1b6
	left = middle + 1;
Packit Bot 5df1b6
      else
Packit Bot 5df1b6
	right = middle - 1;
Packit Bot 5df1b6
    }
Packit Bot 5df1b6
Packit Bot 5df1b6
  return best;
Packit Bot 5df1b6
}
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
_dl_cache_libcmp (const char *p1, const char *p2)
Packit 6c4009
{
Packit 6c4009
  while (*p1 != '\0')
Packit 6c4009
    {
Packit 6c4009
      if (*p1 >= '0' && *p1 <= '9')
Packit 6c4009
        {
Packit 6c4009
          if (*p2 >= '0' && *p2 <= '9')
Packit 6c4009
            {
Packit 6c4009
	      /* Must compare this numerically.  */
Packit 6c4009
	      int val1;
Packit 6c4009
	      int val2;
Packit 6c4009
Packit 6c4009
	      val1 = *p1++ - '0';
Packit 6c4009
	      val2 = *p2++ - '0';
Packit 6c4009
	      while (*p1 >= '0' && *p1 <= '9')
Packit 6c4009
	        val1 = val1 * 10 + *p1++ - '0';
Packit 6c4009
	      while (*p2 >= '0' && *p2 <= '9')
Packit 6c4009
	        val2 = val2 * 10 + *p2++ - '0';
Packit 6c4009
	      if (val1 != val2)
Packit 6c4009
		return val1 - val2;
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
            return 1;
Packit 6c4009
        }
Packit 6c4009
      else if (*p2 >= '0' && *p2 <= '9')
Packit 6c4009
        return -1;
Packit 6c4009
      else if (*p1 != *p2)
Packit 6c4009
        return *p1 - *p2;
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  ++p1;
Packit 6c4009
	  ++p2;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  return *p1 - *p2;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Look up NAME in ld.so.cache and return the file name stored there, or null
Packit 6c4009
   if none is found.  The cache is loaded if it was not already.  If loading
Packit 6c4009
   the cache previously failed there will be no more attempts to load it.
Packit 6c4009
   The caller is responsible for freeing the returned string.  The ld.so.cache
Packit 6c4009
   may be unmapped at any time by a completing recursive dlopen and
Packit 6c4009
   this function must take care that it does not return references to
Packit 6c4009
   any data in the mapping.  */
Packit 6c4009
char *
Packit 6c4009
_dl_load_cache_lookup (const char *name)
Packit 6c4009
{
Packit 6c4009
  /* Print a message if the loading of libs is traced.  */
Packit 6c4009
  if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
Packit 6c4009
    _dl_debug_printf (" search cache=%s\n", LD_SO_CACHE);
Packit 6c4009
Packit 6c4009
  if (cache == NULL)
Packit 6c4009
    {
Packit 6c4009
      /* Read the contents of the file.  */
Packit 6c4009
      void *file = _dl_sysdep_read_whole_file (LD_SO_CACHE, &cachesize,
Packit 6c4009
					       PROT_READ);
Packit 6c4009
Packit 6c4009
      /* We can handle three different cache file formats here:
Packit Bot b64f4c
	 - only the new format
Packit 6c4009
	 - the old libc5/glibc2.0/2.1 format
Packit 6c4009
	 - the old format with the new format in it
Packit 6c4009
	 The following checks if the cache contains any of these formats.  */
Packit Bot b64f4c
      if (file != MAP_FAILED && cachesize > sizeof *cache_new
Packit Bot b64f4c
	  && memcmp (file, CACHEMAGIC_VERSION_NEW,
Packit Bot b64f4c
		     sizeof CACHEMAGIC_VERSION_NEW - 1) == 0
Packit Bot c332f4
	  /* Check for corruption, avoiding overflow.  */
Packit Bot b64f4c
	  && ((cachesize - sizeof *cache_new) / sizeof (struct file_entry_new)
Packit Bot b64f4c
	      >= ((struct cache_file_new *) file)->nlibs))
Packit Bot b64f4c
	{
Packit Bot adb887
	  if (! cache_file_new_matches_endian (file))
Packit Bot adb887
	    {
Packit Bot adb887
	      __munmap (file, cachesize);
Packit Bot adb887
	      file = (void *) -1;
Packit Bot adb887
	    }
Packit Bot b64f4c
	  cache_new = file;
Packit Bot b64f4c
	  cache = file;
Packit Bot b64f4c
	}
Packit Bot b64f4c
      else if (file != MAP_FAILED && cachesize > sizeof *cache
Packit Bot b64f4c
	       && memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1) == 0
Packit Bot b64f4c
	       /* Check for corruption, avoiding overflow.  */
Packit Bot b64f4c
	       && ((cachesize - sizeof *cache) / sizeof (struct file_entry)
Packit Bot b64f4c
		   >= ((struct cache_file *) file)->nlibs))
Packit 6c4009
	{
Packit 6c4009
	  size_t offset;
Packit 6c4009
	  /* Looks ok.  */
Packit 6c4009
	  cache = file;
Packit 6c4009
Packit 6c4009
	  /* Check for new version.  */
Packit 6c4009
	  offset = ALIGN_CACHE (sizeof (struct cache_file)
Packit 6c4009
				+ cache->nlibs * sizeof (struct file_entry));
Packit 6c4009
Packit 6c4009
	  cache_new = (struct cache_file_new *) ((void *) cache + offset);
Packit 6c4009
	  if (cachesize < (offset + sizeof (struct cache_file_new))
Packit 6c4009
	      || memcmp (cache_new->magic, CACHEMAGIC_VERSION_NEW,
Packit 6c4009
			 sizeof CACHEMAGIC_VERSION_NEW - 1) != 0)
Packit Bot adb887
	      cache_new = (void *) -1;
Packit Bot adb887
	  else
Packit Bot adb887
	    {
Packit Bot adb887
	      if (! cache_file_new_matches_endian (cache_new))
Packit Bot adb887
		{
Packit Bot adb887
		  /* The old-format part of the cache is bogus as well
Packit Bot adb887
		     if the endianness does not match.  (But it is
Packit Bot adb887
		     unclear how the new header can be located if the
Packit Bot adb887
		     endianess does not match.)  */
Packit Bot adb887
		  cache = (void *) -1;
Packit Bot adb887
		  cache_new = (void *) -1;
Packit Bot adb887
		  __munmap (file, cachesize);
Packit Bot adb887
		}
Packit Bot adb887
	    }
Packit Bot 0c2104
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  if (file != MAP_FAILED)
Packit 6c4009
	    __munmap (file, cachesize);
Packit 6c4009
	  cache = (void *) -1;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      assert (cache != NULL);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (cache == (void *) -1)
Packit 6c4009
    /* Previously looked for the cache file and didn't find it.  */
Packit 6c4009
    return NULL;
Packit 6c4009
Packit Bot 5df1b6
  const char *best;
Packit 6c4009
  if (cache_new != (void *) -1)
Packit 6c4009
    {
Packit Bot 5df1b6
      const char *string_table = (const char *) cache_new;
Packit Bot 5df1b6
      best = search_cache (string_table, cachesize,
Packit Bot 5df1b6
			   &cache_new->libs[0].entry, cache_new->nlibs,
Packit Bot 5df1b6
			   sizeof (cache_new->libs[0]), name);
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit Bot 5df1b6
      const char *string_table = (const char *) &cache->libs[cache->nlibs];
Packit Bot 5df1b6
      uint32_t string_table_size
Packit Bot 5df1b6
	= (const char *) cache + cachesize - string_table;
Packit Bot 5df1b6
      best = search_cache (string_table, string_table_size,
Packit Bot 5df1b6
			   &cache->libs[0], cache->nlibs,
Packit Bot 5df1b6
			   sizeof (cache->libs[0]), name);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Print our result if wanted.  */
Packit 6c4009
  if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0)
Packit 6c4009
      && best != NULL)
Packit 6c4009
    _dl_debug_printf ("  trying file=%s\n", best);
Packit 6c4009
Packit 6c4009
  if (best == NULL)
Packit 6c4009
    return NULL;
Packit 6c4009
Packit 6c4009
  /* The double copy is *required* since malloc may be interposed
Packit 6c4009
     and call dlopen itself whose completion would unmap the data
Packit 6c4009
     we are accessing. Therefore we must make the copy of the
Packit 6c4009
     mapping data without using malloc.  */
Packit 6c4009
  char *temp;
Packit 6c4009
  temp = alloca (strlen (best) + 1);
Packit 6c4009
  strcpy (temp, best);
Packit 6c4009
  return __strdup (temp);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#ifndef MAP_COPY
Packit 6c4009
/* If the system does not support MAP_COPY we cannot leave the file open
Packit 6c4009
   all the time since this would create problems when the file is replaced.
Packit 6c4009
   Therefore we provide this function to close the file and open it again
Packit 6c4009
   once needed.  */
Packit 6c4009
void
Packit 6c4009
_dl_unload_cache (void)
Packit 6c4009
{
Packit 6c4009
  if (cache != NULL && cache != (struct cache_file *) -1)
Packit 6c4009
    {
Packit 6c4009
      __munmap (cache, cachesize);
Packit 6c4009
      cache = NULL;
Packit 6c4009
    }
Packit Bot e2c958
#ifdef SHARED
Packit Bot e2c958
  /* This marks the glibc_hwcaps_priorities array as out-of-date.  */
Packit Bot e2c958
  glibc_hwcaps_priorities_length = 0;
Packit Bot e2c958
#endif
Packit 6c4009
}
Packit 6c4009
#endif