x86: Set header.feature_1 in TCB for always-on CET [BZ #27177]
[glibc.git] / sysdeps / x86 / dl-cet.c
bloba63b9c7164e73c2b76a883343eb073c22349c95d
1 /* x86 CET initializers function.
2 Copyright (C) 2018-2021 Free Software Foundation, Inc.
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.
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.
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/>. */
18 #include <unistd.h>
19 #include <errno.h>
20 #include <libintl.h>
21 #include <ldsodefs.h>
22 #include <dl-cet.h>
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
35 /* Check if object M is compatible with CET. */
37 static void
38 dl_cet_check (struct link_map *m, const char *program)
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;
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)
51 THREAD_SETMEM (THREAD_SELF, header.feature_1, GL(dl_x86_feature_1));
52 return;
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;
62 if (ibt_enabled || shstk_enabled)
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;
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)
75 /* Enable IBT and SHSTK only if they are enabled in executable.
76 NB: IBT and SHSTK may be disabled by environment variable:
78 GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK
80 enable_ibt &= (HAS_CPU_FEATURE (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 &= (HAS_CPU_FEATURE (SHSTK)
85 && (enable_shstk_type == cet_always_on
86 || (m->l_x86_feature_1_and
87 & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0));
90 /* ld.so is CET-enabled by kernel. But shared objects may not
91 support IBT nor SHSTK. */
92 if (enable_ibt || enable_shstk)
94 unsigned int i;
96 i = m->l_searchlist.r_nlist;
97 while (i-- > 0)
99 /* Check each shared object to see if IBT and SHSTK are
100 enabled. */
101 l = m->l_initfini[i];
103 if (l->l_init_called)
104 continue;
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
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)
123 found_ibt_legacy = true;
124 ibt_legacy = i;
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)
134 found_shstk_legacy = true;
135 shstk_legacy = i;
140 bool cet_feature_changed = false;
142 if (enable_ibt != ibt_enabled || enable_shstk != shstk_enabled)
144 if (!program)
146 if (enable_ibt_type != cet_permissive)
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"));
157 if (enable_shstk_type != cet_permissive)
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"));
168 if (enable_ibt_type != cet_permissive
169 && enable_shstk_type != cet_permissive)
170 return;
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;
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;
182 int res = dl_cet_disable_cet (cet_feature);
183 if (res != 0)
185 if (program)
186 _dl_fatal_printf ("%s: can't disable CET\n", program);
187 else
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"));
198 /* Clear the disabled bits in dl_x86_feature_1. */
199 GL(dl_x86_feature_1) &= ~cet_feature;
201 cet_feature_changed = true;
204 #ifdef SHARED
205 if (program && (ibt_enabled || shstk_enabled))
207 if ((!ibt_enabled
208 || enable_ibt_type != cet_permissive)
209 && (!shstk_enabled
210 || enable_shstk_type != cet_permissive))
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);
219 /* Set feature_1 if IBT or SHSTK is enabled in executable. */
220 cet_feature_changed = true;
222 #endif
224 if (cet_feature_changed)
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);
237 void
238 _dl_cet_open_check (struct link_map *l)
240 dl_cet_check (l, NULL);
243 #ifdef SHARED
245 # ifndef LINKAGE
246 # define LINKAGE
247 # endif
249 LINKAGE
250 void
251 _dl_cet_check (struct link_map *main_map, const char *program)
253 dl_cet_check (main_map, program);
255 #endif /* SHARED */