Blame sysdeps/generic/dl-cache.h

Packit 6c4009
/* Support for reading /etc/ld.so.cache files written by Linux ldconfig.
Packit 6c4009
   Copyright (C) 1999-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 Bot adb887
#ifndef _DL_CACHE_H
Packit Bot adb887
#define _DL_CACHE_H
Packit Bot adb887
Packit Bot adb887
#include <endian.h>
Packit Bot adb887
#include <stdbool.h>
Packit Bot 27c3f3
#include <stddef.h>
Packit 6c4009
#include <stdint.h>
Packit Bot 27c3f3
#include <string.h>
Packit 6c4009
Packit 6c4009
#ifndef _DL_CACHE_DEFAULT_ID
Packit 6c4009
# define _DL_CACHE_DEFAULT_ID	3
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifndef _dl_cache_check_flags
Packit 6c4009
# define _dl_cache_check_flags(flags)			\
Packit 6c4009
  ((flags) == 1 || (flags) == _DL_CACHE_DEFAULT_ID)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifndef LD_SO_CACHE
Packit 6c4009
# define LD_SO_CACHE SYSCONFDIR "/ld.so.cache"
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifndef add_system_dir
Packit 6c4009
# define add_system_dir(dir) add_dir (dir)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#define CACHEMAGIC "ld.so-1.7.0"
Packit 6c4009
Packit 6c4009
/* libc5 and glibc 2.0/2.1 use the same format.  For glibc 2.2 another
Packit 6c4009
   format has been added in a compatible way:
Packit 6c4009
   The beginning of the string table is used for the new table:
Packit 6c4009
	old_magic
Packit 6c4009
	nlibs
Packit 6c4009
	libs[0]
Packit 6c4009
	...
Packit 6c4009
	libs[nlibs-1]
Packit 6c4009
	pad, new magic needs to be aligned
Packit 6c4009
	     - this is string[0] for the old format
Packit 6c4009
	new magic - this is string[0] for the new format
Packit 6c4009
	newnlibs
Packit 6c4009
	...
Packit 6c4009
	newlibs[0]
Packit 6c4009
	...
Packit 6c4009
	newlibs[newnlibs-1]
Packit 6c4009
	string 1
Packit 6c4009
	string 2
Packit 6c4009
	...
Packit 6c4009
*/
Packit 6c4009
struct file_entry
Packit 6c4009
{
Packit Bot 5df1b6
  int32_t flags;		/* This is 1 for an ELF library.  */
Packit Bot 5df1b6
  uint32_t key, value;		/* String table indices.  */
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
struct cache_file
Packit 6c4009
{
Packit 6c4009
  char magic[sizeof CACHEMAGIC - 1];
Packit 6c4009
  unsigned int nlibs;
Packit 6c4009
  struct file_entry libs[0];
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
#define CACHEMAGIC_NEW "glibc-ld.so.cache"
Packit 6c4009
#define CACHE_VERSION "1.1"
Packit 6c4009
#define CACHEMAGIC_VERSION_NEW CACHEMAGIC_NEW CACHE_VERSION
Packit 6c4009
Packit 6c4009
Packit 6c4009
struct file_entry_new
Packit 6c4009
{
Packit Bot 5df1b6
  union
Packit Bot 5df1b6
  {
Packit Bot 5df1b6
    /* Fields shared with struct file_entry.  */
Packit Bot 5df1b6
    struct file_entry entry;
Packit Bot 5df1b6
    /* Also expose these fields directly.  */
Packit Bot 5df1b6
    struct
Packit Bot 5df1b6
    {
Packit Bot 5df1b6
      int32_t flags;		/* This is 1 for an ELF library.  */
Packit Bot 5df1b6
      uint32_t key, value;	/* String table indices.  */
Packit Bot 5df1b6
    };
Packit Bot 5df1b6
  };
Packit 6c4009
  uint32_t osversion;		/* Required OS version.	 */
Packit 6c4009
  uint64_t hwcap;		/* Hwcap entry.	 */
Packit 6c4009
};
Packit 6c4009
Packit Bot 9798e1
/* This bit in the hwcap field of struct file_entry_new indicates that
Packit Bot 9798e1
   the lower 32 bits contain an index into the
Packit Bot 9798e1
   cache_extension_tag_glibc_hwcaps section.  Older glibc versions do
Packit Bot 9798e1
   not know about this HWCAP bit, so they will ignore these
Packit Bot 9798e1
   entries.  */
Packit Bot 9798e1
#define DL_CACHE_HWCAP_EXTENSION (1ULL << 62)
Packit Bot 9798e1
Packit Bot 9798e1
/* Return true if the ENTRY->hwcap value indicates that
Packit Bot 9798e1
   DL_CACHE_HWCAP_EXTENSION is used.  */
Packit Bot 9798e1
static inline bool
Packit Bot 9798e1
dl_cache_hwcap_extension (struct file_entry_new *entry)
Packit Bot 9798e1
{
Packit Bot 9798e1
  /* If DL_CACHE_HWCAP_EXTENSION is set, but other bits as well, this
Packit Bot 9798e1
     is a different kind of extension.  */
Packit Bot 9798e1
  return (entry->hwcap >> 32) == (DL_CACHE_HWCAP_EXTENSION >> 32);
Packit Bot 9798e1
}
Packit Bot 9798e1
Packit Bot adb887
/* See flags member of struct cache_file_new below.  */
Packit Bot adb887
enum
Packit Bot adb887
  {
Packit Bot adb887
    /* No endianness information available.  An old ldconfig version
Packit Bot adb887
       without endianness support wrote the file.  */
Packit Bot adb887
    cache_file_new_flags_endian_unset = 0,
Packit Bot adb887
Packit Bot adb887
    /* Cache is invalid and should be ignored.  */
Packit Bot adb887
    cache_file_new_flags_endian_invalid = 1,
Packit Bot adb887
Packit Bot adb887
    /* Cache format is little endian.  */
Packit Bot adb887
    cache_file_new_flags_endian_little = 2,
Packit Bot adb887
Packit Bot adb887
    /* Cache format is big endian.  */
Packit Bot adb887
    cache_file_new_flags_endian_big = 3,
Packit Bot adb887
Packit Bot adb887
    /* Bit mask to extract the cache_file_new_flags_endian_*
Packit Bot adb887
       values.  */
Packit Bot adb887
    cache_file_new_flags_endian_mask = 3,
Packit Bot adb887
Packit Bot adb887
    /* Expected value of the endian bits in the flags member for the
Packit Bot adb887
       current architecture.  */
Packit Bot adb887
    cache_file_new_flags_endian_current
Packit Bot adb887
      = (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
Packit Bot adb887
	 ? cache_file_new_flags_endian_little
Packit Bot adb887
	 : cache_file_new_flags_endian_big),
Packit Bot adb887
  };
Packit Bot adb887
Packit 6c4009
struct cache_file_new
Packit 6c4009
{
Packit 6c4009
  char magic[sizeof CACHEMAGIC_NEW - 1];
Packit 6c4009
  char version[sizeof CACHE_VERSION - 1];
Packit 6c4009
  uint32_t nlibs;		/* Number of entries.  */
Packit 6c4009
  uint32_t len_strings;		/* Size of string table. */
Packit Bot adb887
Packit Bot adb887
  /* flags & cache_file_new_flags_endian_mask is one of the values
Packit Bot adb887
     cache_file_new_flags_endian_unset, cache_file_new_flags_endian_invalid,
Packit Bot adb887
     cache_file_new_flags_endian_little, cache_file_new_flags_endian_big.
Packit Bot adb887
Packit Bot adb887
     The remaining bits are unused and should be generated as zero and
Packit Bot adb887
     ignored by readers.  */
Packit Bot adb887
  uint8_t flags;
Packit Bot adb887
Packit Bot adb887
  uint8_t padding_unsed[3];	/* Not used, for future extensions.  */
Packit Bot adb887
Packit Bot 27c3f3
  /* File offset of the extension directory.  See struct
Packit Bot 27c3f3
     cache_extension below.  Must be a multiple of four.  */
Packit Bot 27c3f3
  uint32_t extension_offset;
Packit Bot 27c3f3
Packit Bot 27c3f3
  uint32_t unused[3];		/* Leave space for future extensions
Packit 6c4009
				   and align to 8 byte boundary.  */
Packit 6c4009
  struct file_entry_new libs[0]; /* Entries describing libraries.  */
Packit 6c4009
  /* After this the string table of size len_strings is found.	*/
Packit 6c4009
};
Packit Bot adb887
_Static_assert (sizeof (struct cache_file_new) == 48,
Packit Bot adb887
		"size of struct cache_file_new");
Packit Bot adb887
Packit Bot adb887
/* Returns false if *CACHE has the wrong endianness for this
Packit Bot adb887
   architecture, and true if the endianness matches (or is
Packit Bot adb887
   unknown).  */
Packit Bot adb887
static inline bool
Packit Bot adb887
cache_file_new_matches_endian (const struct cache_file_new *cache)
Packit Bot adb887
{
Packit Bot adb887
  /* A zero value for cache->flags means that no endianness
Packit Bot adb887
     information is available.  */
Packit Bot adb887
  return cache->flags == 0
Packit Bot adb887
    || ((cache->flags & cache_file_new_flags_endian_big)
Packit Bot adb887
	== cache_file_new_flags_endian_current);
Packit Bot adb887
}
Packit Bot adb887
Packit Service 138d0c
Packit Bot 27c3f3
/* Randomly chosen magic value, which allows for additional
Packit Bot 27c3f3
   consistency verification.  */
Packit Bot 27c3f3
enum { cache_extension_magic = (uint32_t) -358342284 };
Packit Bot 27c3f3
Packit Bot 27c3f3
/* Tag values for different kinds of extension sections.  Similar to
Packit Bot 27c3f3
   SHT_* constants.  */
Packit Bot 27c3f3
enum cache_extension_tag
Packit Bot 27c3f3
  {
Packit Bot 27c3f3
   /* Array of bytes containing the glibc version that generated this
Packit Bot 27c3f3
      cache file.  */
Packit Bot 27c3f3
   cache_extension_tag_generator,
Packit Bot 27c3f3
Packit Bot 9798e1
   /* glibc-hwcaps subdirectory information.  An array of uint32_t
Packit Bot 9798e1
      values, which are indices into the string table.  The strings
Packit Bot 9798e1
      are sorted lexicographically (according to strcmp).  The extra
Packit Bot 9798e1
      level of indirection (instead of using string table indices
Packit Bot 9798e1
      directly) allows the dynamic loader to compute the preference
Packit Bot 9798e1
      order of the hwcaps names more efficiently.
Packit Bot 9798e1
Packit Bot 9798e1
      For this section, 4-byte alignment is required, and the section
Packit Bot 9798e1
      size must be a multiple of 4.  */
Packit Bot 9798e1
   cache_extension_tag_glibc_hwcaps,
Packit Bot 9798e1
Packit Bot 27c3f3
   /* Total number of known cache extension tags.  */
Packit Bot 27c3f3
   cache_extension_count
Packit Bot 27c3f3
  };
Packit Bot 27c3f3
Packit Bot 27c3f3
/* Element in the array following struct cache_extension.  Similar to
Packit Bot 27c3f3
   an ELF section header.  */
Packit Bot 27c3f3
struct cache_extension_section
Packit Bot 27c3f3
{
Packit Bot 27c3f3
  /* Type of the extension section.  A enum cache_extension_tag value.  */
Packit Bot 27c3f3
  uint32_t tag;
Packit Bot 27c3f3
Packit Bot 27c3f3
  /* Extension-specific flags.  Currently generated as zero.  */
Packit Bot 27c3f3
  uint32_t flags;
Packit Bot 27c3f3
Packit Bot 27c3f3
  /* Offset from the start of the file for the data in this extension
Packit Bot 27c3f3
     section.  Specific extensions can have alignment constraints.  */
Packit Bot 27c3f3
  uint32_t offset;
Packit Bot 27c3f3
Packit Bot 27c3f3
  /* Length in bytes of the extension data.  Specific extensions may
Packit Bot 27c3f3
     have size requirements.  */
Packit Bot 27c3f3
  uint32_t size;
Packit Bot 27c3f3
};
Packit Bot 27c3f3
Packit Bot 27c3f3
/* The extension directory in the cache.  An array of struct
Packit Bot 27c3f3
   cache_extension_section entries.  */
Packit Bot 27c3f3
struct cache_extension
Packit Bot 27c3f3
{
Packit Bot 27c3f3
  uint32_t magic;		/* Always cache_extension_magic.  */
Packit Bot 27c3f3
  uint32_t count;		/* Number of following entries.  */
Packit Bot 27c3f3
Packit Bot 27c3f3
  /* count section descriptors of type struct cache_extension_section
Packit Bot 27c3f3
     follow.  */
Packit Bot 27c3f3
  struct cache_extension_section sections[];
Packit Bot 27c3f3
};
Packit Bot 27c3f3
Packit Bot 27c3f3
/* A relocated version of struct cache_extension_section.  */
Packit Bot 27c3f3
struct cache_extension_loaded
Packit Bot 27c3f3
{
Packit Bot 27c3f3
  /* Address and size of this extension section.  base is NULL if the
Packit Bot 27c3f3
     section is missing from the file.  */
Packit Bot 27c3f3
  const void *base;
Packit Bot 27c3f3
  size_t size;
Packit Bot 27c3f3
Packit Bot 27c3f3
  /* Flags from struct cache_extension_section.  */
Packit Bot 27c3f3
  uint32_t flags;
Packit Bot 27c3f3
};
Packit Bot 27c3f3
Packit Bot 27c3f3
/* All supported extension sections, relocated.  Filled in by
Packit Bot 27c3f3
   cache_extension_load below.  */
Packit Bot 27c3f3
struct cache_extension_all_loaded
Packit Bot 27c3f3
{
Packit Bot 27c3f3
  struct cache_extension_loaded sections[cache_extension_count];
Packit Bot 27c3f3
};
Packit Bot 27c3f3
Packit Bot 9798e1
/* Performs basic data validation based on section tag, and removes
Packit Bot 9798e1
   the sections which are invalid.  */
Packit Bot 9798e1
static void
Packit Bot 9798e1
cache_extension_verify (struct cache_extension_all_loaded *loaded)
Packit Bot 9798e1
{
Packit Bot 9798e1
  {
Packit Bot 9798e1
    /* Section must not be empty, it must be aligned at 4 bytes, and
Packit Bot 9798e1
       the size must be a multiple of 4.  */
Packit Bot 9798e1
    struct cache_extension_loaded *hwcaps
Packit Bot 9798e1
      = &loaded->sections[cache_extension_tag_glibc_hwcaps];
Packit Bot 9798e1
    if (hwcaps->size == 0
Packit Bot 9798e1
	|| ((uintptr_t) hwcaps->base % 4) != 0
Packit Bot 9798e1
	|| (hwcaps->size % 4) != 0)
Packit Bot 9798e1
      {
Packit Bot 9798e1
	hwcaps->base = NULL;
Packit Bot 9798e1
	hwcaps->size = 0;
Packit Bot 9798e1
	hwcaps->flags = 0;
Packit Bot 9798e1
      }
Packit Bot 9798e1
  }
Packit Bot 9798e1
}
Packit Bot 9798e1
Packit Bot 27c3f3
static bool __attribute__ ((unused))
Packit Bot 27c3f3
cache_extension_load (const struct cache_file_new *cache,
Packit Bot 27c3f3
		      const void *file_base, size_t file_size,
Packit Bot 27c3f3
		      struct cache_extension_all_loaded *loaded)
Packit Bot 27c3f3
{
Packit Bot 27c3f3
  memset (loaded, 0, sizeof (*loaded));
Packit Bot 27c3f3
  if (cache->extension_offset == 0)
Packit Bot 27c3f3
    /* No extensions present.  This is not a format error.  */
Packit Bot 27c3f3
    return true;
Packit Bot 27c3f3
  if ((cache->extension_offset % 4) != 0)
Packit Bot 27c3f3
    /* Extension offset is misaligned.  */
Packit Bot 27c3f3
    return false;
Packit Bot 27c3f3
  size_t size_tmp;
Packit Bot 27c3f3
  if (__builtin_add_overflow (cache->extension_offset,
Packit Bot 27c3f3
			      sizeof (struct cache_extension), &size_tmp)
Packit Bot 27c3f3
      || size_tmp > file_size)
Packit Bot 27c3f3
    /* Extension extends beyond the end of the file.  */
Packit Bot 27c3f3
    return false;
Packit Bot 27c3f3
  const struct cache_extension *ext = file_base + cache->extension_offset;
Packit Bot 27c3f3
  if (ext->magic != cache_extension_magic)
Packit Bot 27c3f3
    return false;
Packit Bot 27c3f3
  if (__builtin_mul_overflow (ext->count,
Packit Bot 27c3f3
			      sizeof (struct cache_extension_section),
Packit Bot 27c3f3
			      &size_tmp)
Packit Bot 27c3f3
      || __builtin_add_overflow (cache->extension_offset
Packit Bot 27c3f3
				 + sizeof (struct cache_extension), size_tmp,
Packit Bot 27c3f3
				 &size_tmp)
Packit Bot 27c3f3
      || size_tmp > file_size)
Packit Bot 27c3f3
    /* Extension array extends beyond the end of the file.  */
Packit Bot 27c3f3
    return false;
Packit Bot 27c3f3
  for (uint32_t i = 0; i < ext->count; ++i)
Packit Bot 27c3f3
    {
Packit Bot 27c3f3
      if (__builtin_add_overflow (ext->sections[i].offset,
Packit Bot 27c3f3
				  ext->sections[i].size, &size_tmp)
Packit Bot 27c3f3
	  || size_tmp > file_size)
Packit Bot 27c3f3
	/* Extension data extends beyond the end of the file.  */
Packit Bot 27c3f3
	return false;
Packit Bot 27c3f3
Packit Bot 27c3f3
      uint32_t tag = ext->sections[i].tag;
Packit Bot 27c3f3
      if (tag >= cache_extension_count)
Packit Bot 27c3f3
	/* Tag is out of range and unrecognized.  */
Packit Bot 27c3f3
	continue;
Packit Bot 27c3f3
      loaded->sections[tag].base = file_base + ext->sections[i].offset;
Packit Bot 27c3f3
      loaded->sections[tag].size = ext->sections[i].size;
Packit Bot 27c3f3
      loaded->sections[tag].flags = ext->sections[i].flags;
Packit Bot 27c3f3
    }
Packit Bot 9798e1
  cache_extension_verify (loaded);
Packit Bot 27c3f3
  return true;
Packit Bot 27c3f3
}
Packit Bot 27c3f3
Packit 6c4009
/* Used to align cache_file_new.  */
Packit 6c4009
#define ALIGN_CACHE(addr)				\
Packit 6c4009
(((addr) + __alignof__ (struct cache_file_new) -1)	\
Packit 6c4009
 & (~(__alignof__ (struct cache_file_new) - 1)))
Packit 6c4009
Packit 6c4009
extern int _dl_cache_libcmp (const char *p1, const char *p2) attribute_hidden;
Packit Bot adb887
Packit Bot adb887
#endif /* _DL_CACHE_H */