(root)/
glibc-2.38/
sysdeps/
x86/
dl-cet.c
       1  /* x86 CET initializers function.
       2     Copyright (C) 2018-2023 Free Software Foundation, Inc.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <unistd.h>
      19  #include <errno.h>
      20  #include <libintl.h>
      21  #include <ldsodefs.h>
      22  #include <dl-cet.h>
      23  
      24  /* GNU_PROPERTY_X86_FEATURE_1_IBT and GNU_PROPERTY_X86_FEATURE_1_SHSTK
      25     are defined in <elf.h>, which are only available for C sources.
      26     X86_FEATURE_1_IBT and X86_FEATURE_1_SHSTK are defined in <sysdep.h>
      27     which are available for both C and asm sources.  They must match.   */
      28  #if GNU_PROPERTY_X86_FEATURE_1_IBT != X86_FEATURE_1_IBT
      29  # error GNU_PROPERTY_X86_FEATURE_1_IBT != X86_FEATURE_1_IBT
      30  #endif
      31  #if GNU_PROPERTY_X86_FEATURE_1_SHSTK != X86_FEATURE_1_SHSTK
      32  # error GNU_PROPERTY_X86_FEATURE_1_SHSTK != X86_FEATURE_1_SHSTK
      33  #endif
      34  
      35  /* Check if object M is compatible with CET.  */
      36  
      37  static void
      38  dl_cet_check (struct link_map *m, const char *program)
      39  {
      40    /* Check how IBT should be enabled.  */
      41    enum dl_x86_cet_control enable_ibt_type
      42      = GL(dl_x86_feature_control).ibt;
      43    /* Check how SHSTK should be enabled.  */
      44    enum dl_x86_cet_control enable_shstk_type
      45      = GL(dl_x86_feature_control).shstk;
      46  
      47    /* No legacy object check if both IBT and SHSTK are always on.  */
      48    if (enable_ibt_type == cet_always_on
      49        && enable_shstk_type == cet_always_on)
      50      {
      51        THREAD_SETMEM (THREAD_SELF, header.feature_1, GL(dl_x86_feature_1));
      52        return;
      53      }
      54  
      55    /* Check if IBT is enabled by kernel.  */
      56    bool ibt_enabled
      57      = (GL(dl_x86_feature_1) & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0;
      58    /* Check if SHSTK is enabled by kernel.  */
      59    bool shstk_enabled
      60      = (GL(dl_x86_feature_1) & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0;
      61  
      62    if (ibt_enabled || shstk_enabled)
      63      {
      64        struct link_map *l = NULL;
      65        unsigned int ibt_legacy = 0, shstk_legacy = 0;
      66        bool found_ibt_legacy = false, found_shstk_legacy = false;
      67  
      68        /* Check if IBT and SHSTK are enabled in object.  */
      69        bool enable_ibt = (ibt_enabled
      70  			 && enable_ibt_type != cet_always_off);
      71        bool enable_shstk = (shstk_enabled
      72  			   && enable_shstk_type != cet_always_off);
      73        if (program)
      74  	{
      75  	  /* Enable IBT and SHSTK only if they are enabled in executable.
      76  	     NB: IBT and SHSTK may be disabled by environment variable:
      77  
      78  	     GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK
      79  	   */
      80  	  enable_ibt &= (CPU_FEATURE_USABLE (IBT)
      81  			 && (enable_ibt_type == cet_always_on
      82  			     || (m->l_x86_feature_1_and
      83  				 & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0));
      84  	  enable_shstk &= (CPU_FEATURE_USABLE (SHSTK)
      85  			   && (enable_shstk_type == cet_always_on
      86  			       || (m->l_x86_feature_1_and
      87  				   & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0));
      88  	}
      89  
      90        /* ld.so is CET-enabled by kernel.  But shared objects may not
      91  	 support IBT nor SHSTK.  */
      92        if (enable_ibt || enable_shstk)
      93  	{
      94  	  unsigned int i;
      95  
      96  	  i = m->l_searchlist.r_nlist;
      97  	  while (i-- > 0)
      98  	    {
      99  	      /* Check each shared object to see if IBT and SHSTK are
     100  		 enabled.  */
     101  	      l = m->l_initfini[i];
     102  
     103  	      if (l->l_init_called)
     104  		continue;
     105  
     106  #ifdef SHARED
     107  	      /* Skip CET check for ld.so since ld.so is CET-enabled.
     108  		 CET will be disabled later if CET isn't enabled in
     109  		 executable.  */
     110  	      if (l == &GL(dl_rtld_map)
     111  		  ||  l->l_real == &GL(dl_rtld_map)
     112  		  || (program && l == m))
     113  		continue;
     114  #endif
     115  
     116  	      /* IBT is enabled only if it is enabled in executable as
     117  		 well as all shared objects.  */
     118  	      enable_ibt &= (enable_ibt_type == cet_always_on
     119  			     || (l->l_x86_feature_1_and
     120  				 & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0);
     121  	      if (!found_ibt_legacy && enable_ibt != ibt_enabled)
     122  		{
     123  		  found_ibt_legacy = true;
     124  		  ibt_legacy = i;
     125  		}
     126  
     127  	      /* SHSTK is enabled only if it is enabled in executable as
     128  		 well as all shared objects.  */
     129  	      enable_shstk &= (enable_shstk_type == cet_always_on
     130  			       || (l->l_x86_feature_1_and
     131  				   & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0);
     132  	      if (enable_shstk != shstk_enabled)
     133  		{
     134  		  found_shstk_legacy = true;
     135  		  shstk_legacy = i;
     136  		}
     137  	    }
     138  	}
     139  
     140        bool cet_feature_changed = false;
     141  
     142        if (enable_ibt != ibt_enabled || enable_shstk != shstk_enabled)
     143  	{
     144  	  if (!program)
     145  	    {
     146  	      if (enable_ibt_type != cet_permissive)
     147  		{
     148  		  /* When IBT is enabled, we cannot dlopen a shared
     149  		     object without IBT.  */
     150  		  if (found_ibt_legacy)
     151  		    _dl_signal_error (0,
     152  				      m->l_initfini[ibt_legacy]->l_name,
     153  				      "dlopen",
     154  				      N_("rebuild shared object with IBT support enabled"));
     155  		}
     156  
     157  	      if (enable_shstk_type != cet_permissive)
     158  		{
     159  		  /* When SHSTK is enabled, we cannot dlopen a shared
     160  		     object without SHSTK.  */
     161  		  if (found_shstk_legacy)
     162  		    _dl_signal_error (0,
     163  				      m->l_initfini[shstk_legacy]->l_name,
     164  				      "dlopen",
     165  				      N_("rebuild shared object with SHSTK support enabled"));
     166  		}
     167  
     168  	      if (enable_ibt_type != cet_permissive
     169  		  && enable_shstk_type != cet_permissive)
     170  		return;
     171  	    }
     172  
     173  	  /* Disable IBT and/or SHSTK if they are enabled by kernel, but
     174  	     disabled in executable or shared objects.  */
     175  	  unsigned int cet_feature = 0;
     176  
     177  	  if (!enable_ibt)
     178  	    cet_feature |= GNU_PROPERTY_X86_FEATURE_1_IBT;
     179  	  if (!enable_shstk)
     180  	    cet_feature |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
     181  
     182  	  int res = dl_cet_disable_cet (cet_feature);
     183  	  if (res != 0)
     184  	    {
     185  	      if (program)
     186  		_dl_fatal_printf ("%s: can't disable CET\n", program);
     187  	      else
     188  		{
     189  		  if (found_ibt_legacy)
     190  		    l = m->l_initfini[ibt_legacy];
     191  		  else
     192  		    l = m->l_initfini[shstk_legacy];
     193  		  _dl_signal_error (-res, l->l_name, "dlopen",
     194  				    N_("can't disable CET"));
     195  		}
     196  	    }
     197  
     198  	  /* Clear the disabled bits in dl_x86_feature_1.  */
     199  	  GL(dl_x86_feature_1) &= ~cet_feature;
     200  
     201  	  cet_feature_changed = true;
     202  	}
     203  
     204  #ifdef SHARED
     205        if (program && (ibt_enabled || shstk_enabled))
     206  	{
     207  	  if ((!ibt_enabled
     208  	       || enable_ibt_type != cet_permissive)
     209  	      && (!shstk_enabled
     210  		  || enable_shstk_type != cet_permissive))
     211  	    {
     212  	      /* Lock CET if IBT or SHSTK is enabled in executable unless
     213  	         IBT or SHSTK is enabled permissively.  */
     214  	      int res = dl_cet_lock_cet ();
     215  	      if (res != 0)
     216  		_dl_fatal_printf ("%s: can't lock CET\n", program);
     217  	    }
     218  
     219  	  /* Set feature_1 if IBT or SHSTK is enabled in executable.  */
     220  	  cet_feature_changed = true;
     221  	}
     222  #endif
     223  
     224        if (cet_feature_changed)
     225  	{
     226  	  unsigned int feature_1 = 0;
     227  	  if (enable_ibt)
     228  	    feature_1 |= GNU_PROPERTY_X86_FEATURE_1_IBT;
     229  	  if (enable_shstk)
     230  	    feature_1 |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
     231  	  struct pthread *self = THREAD_SELF;
     232  	  THREAD_SETMEM (self, header.feature_1, feature_1);
     233  	}
     234      }
     235  }
     236  
     237  void
     238  _dl_cet_open_check (struct link_map *l)
     239  {
     240    dl_cet_check (l, NULL);
     241  }
     242  
     243  #ifdef SHARED
     244  
     245  # ifndef LINKAGE
     246  #  define LINKAGE
     247  # endif
     248  
     249  LINKAGE
     250  void
     251  _dl_cet_check (struct link_map *main_map, const char *program)
     252  {
     253    dl_cet_check (main_map, program);
     254  }
     255  #endif /* SHARED */