(root)/
glibc-2.38/
sysdeps/
x86/
dl-prop.h
       1  /* Support for GNU properties.  x86 version.
       2     Copyright (C) 2018-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #ifndef _DL_PROP_H
      20  #define _DL_PROP_H
      21  
      22  #include <libintl.h>
      23  
      24  extern void _dl_cet_check (struct link_map *, const char *)
      25      attribute_hidden;
      26  extern void _dl_cet_open_check (struct link_map *)
      27      attribute_hidden;
      28  
      29  static void
      30  dl_isa_level_check (struct link_map *m, const char *program)
      31  {
      32    const struct cpu_features *cpu_features = __get_cpu_features ();
      33    unsigned int i;
      34    struct link_map *l;
      35  
      36    i = m->l_searchlist.r_nlist;
      37    while (i-- > 0)
      38      {
      39        /* Check each shared object to see if ISA level is compatible.  */
      40        l = m->l_initfini[i];
      41  
      42        /* Skip ISA level check if functions have been executed.  */
      43        if (l->l_init_called)
      44  	continue;
      45  
      46  #ifdef SHARED
      47        /* Skip ISA level check for ld.so since ld.so won't run if its ISA
      48  	 level is higher than CPU.  */
      49        if (l == &GL(dl_rtld_map) || l->l_real == &GL(dl_rtld_map))
      50  	continue;
      51  #endif
      52  
      53        if ((l->l_x86_isa_1_needed & cpu_features->isa_1)
      54  	  != l->l_x86_isa_1_needed)
      55  	{
      56  	  if (program)
      57  	    _dl_fatal_printf ("%s: CPU ISA level is lower than required\n",
      58  			      *l->l_name != '\0' ? l->l_name : program);
      59  	  else
      60  	    _dl_signal_error (0, l->l_name, "dlopen",
      61  			      N_("CPU ISA level is lower than required"));
      62  	}
      63      }
      64  }
      65  
      66  static inline void __attribute__ ((always_inline))
      67  _rtld_main_check (struct link_map *m, const char *program)
      68  {
      69    dl_isa_level_check (m, program);
      70  #if CET_ENABLED
      71    _dl_cet_check (m, program);
      72  #endif
      73  }
      74  
      75  static inline void __attribute__ ((always_inline))
      76  _dl_open_check (struct link_map *m)
      77  {
      78    dl_isa_level_check (m, NULL);
      79  #if CET_ENABLED
      80    _dl_cet_open_check (m);
      81  #endif
      82  }
      83  
      84  static inline void __attribute__ ((unused))
      85  _dl_process_property_note (struct link_map *l, const ElfW(Nhdr) *note,
      86  			   const ElfW(Addr) size, const ElfW(Addr) align)
      87  {
      88    /* Skip if we have seen a NT_GNU_PROPERTY_TYPE_0 note before.  */
      89    if (l->l_property != lc_property_unknown)
      90      return;
      91  
      92    /* The NT_GNU_PROPERTY_TYPE_0 note must be aligned to 4 bytes in
      93       32-bit objects and to 8 bytes in 64-bit objects.  Skip notes
      94       with incorrect alignment.  */
      95    if (align != (__ELF_NATIVE_CLASS / 8))
      96      return;
      97  
      98    const ElfW(Addr) start = (ElfW(Addr)) note;
      99  
     100    unsigned int needed_1 = 0;
     101    unsigned int feature_1_and = 0;
     102    unsigned int isa_1_needed = 0;
     103    unsigned int last_type = 0;
     104  
     105    while ((ElfW(Addr)) (note + 1) - start < size)
     106      {
     107        /* Find the NT_GNU_PROPERTY_TYPE_0 note.  */
     108        if (note->n_namesz == 4
     109  	  && note->n_type == NT_GNU_PROPERTY_TYPE_0
     110  	  && memcmp (note + 1, "GNU", 4) == 0)
     111  	{
     112  	  /* Stop if we see more than one GNU property note which may
     113  	     be generated by the older linker.  */
     114  	  if (l->l_property != lc_property_unknown)
     115  	    return;
     116  
     117  	  /* Check CET status and ISA levels now.  */
     118  	  l->l_property = lc_property_none;
     119  
     120  	  /* Check for invalid property.  */
     121  	  if (note->n_descsz < 8
     122  	      || (note->n_descsz % sizeof (ElfW(Addr))) != 0)
     123  	    return;
     124  
     125  	  /* Start and end of property array.  */
     126  	  unsigned char *ptr = (unsigned char *) (note + 1) + 4;
     127  	  unsigned char *ptr_end = ptr + note->n_descsz;
     128  
     129  	  do
     130  	    {
     131  	      unsigned int type = *(unsigned int *) ptr;
     132  	      unsigned int datasz = *(unsigned int *) (ptr + 4);
     133  
     134  	      /* Property type must be in ascending order.  */
     135  	      if (type < last_type)
     136  		return;
     137  
     138  	      ptr += 8;
     139  	      if ((ptr + datasz) > ptr_end)
     140  		return;
     141  
     142  	      last_type = type;
     143  
     144  	      if (type == GNU_PROPERTY_X86_FEATURE_1_AND
     145  		  || type == GNU_PROPERTY_X86_ISA_1_NEEDED
     146  		  || type == GNU_PROPERTY_1_NEEDED)
     147  		{
     148  		  /* The sizes of types which we are searching for are
     149  		     4 bytes.  There is no point to continue if this
     150  		     note is ill-formed.  */
     151  		  if (datasz != 4)
     152  		    return;
     153  
     154  		  /* NB: Stop the scan only after seeing all types which
     155  		     we are searching for.  */
     156  		  _Static_assert (((GNU_PROPERTY_X86_ISA_1_NEEDED
     157  				    > GNU_PROPERTY_X86_FEATURE_1_AND)
     158  				   && (GNU_PROPERTY_X86_FEATURE_1_AND
     159  				       > GNU_PROPERTY_1_NEEDED)),
     160  				  "GNU_PROPERTY_X86_ISA_1_NEEDED > "
     161  				  "GNU_PROPERTY_X86_FEATURE_1_AND && "
     162  				  "GNU_PROPERTY_X86_FEATURE_1_AND > "
     163  				  "GNU_PROPERTY_1_NEEDED");
     164  		  if (type == GNU_PROPERTY_X86_FEATURE_1_AND)
     165  		    feature_1_and = *(unsigned int *) ptr;
     166  		  else if (type == GNU_PROPERTY_1_NEEDED)
     167  		    needed_1 = *(unsigned int *) ptr;
     168  		  else
     169  		    {
     170  		      isa_1_needed = *(unsigned int *) ptr;
     171  
     172  		      /* Keep searching for the next GNU property note
     173  			 generated by the older linker.  */
     174  		      break;
     175  		    }
     176  		}
     177  	      else if (type > GNU_PROPERTY_X86_ISA_1_NEEDED)
     178  		{
     179  		  /* Stop the scan since property type is in ascending
     180  		     order.  */
     181  		  break;
     182  		}
     183  
     184  	      /* Check the next property item.  */
     185  	      ptr += ALIGN_UP (datasz, sizeof (ElfW(Addr)));
     186  	    }
     187  	  while ((ptr_end - ptr) >= 8);
     188  	}
     189  
     190        /* NB: Note sections like .note.ABI-tag and .note.gnu.build-id are
     191  	 aligned to 4 bytes in 64-bit ELF objects.  */
     192        note = ((const void *) note
     193  	      + ELF_NOTE_NEXT_OFFSET (note->n_namesz, note->n_descsz,
     194  				      align));
     195      }
     196  
     197    /* We get here only if there is one or no GNU property note.  */
     198    if (needed_1 != 0 || isa_1_needed != 0 || feature_1_and != 0)
     199      {
     200        l->l_property = lc_property_valid;
     201        l->l_1_needed = needed_1;
     202        l->l_x86_isa_1_needed = isa_1_needed;
     203        l->l_x86_feature_1_and = feature_1_and;
     204      }
     205    else
     206      l->l_property = lc_property_none;
     207  }
     208  
     209  static inline void __attribute__ ((unused))
     210  _dl_process_pt_note (struct link_map *l, int fd, const ElfW(Phdr) *ph)
     211  {
     212    const ElfW(Nhdr) *note = (const void *) (ph->p_vaddr + l->l_addr);
     213    _dl_process_property_note (l, note, ph->p_memsz, ph->p_align);
     214  }
     215  
     216  static inline int __attribute__ ((always_inline))
     217  _dl_process_gnu_property (struct link_map *l, int fd, uint32_t type,
     218  			  uint32_t datasz, void *data)
     219  {
     220    return 0;
     221  }
     222  
     223  #endif /* _DL_PROP_H */