x86: Modularize sysdeps/x86/dl-cet.c
[glibc.git] / sysdeps / x86 / dl-cet.c
blob67c51ee8c2dd09f6d5ea06d10a3afb77d26c8b20
1 /* x86 CET initializers function.
2 Copyright (C) 2018-2023 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 struct dl_cet_info
37 const char *program;
39 /* Check how IBT and SHSTK should be enabled. */
40 enum dl_x86_cet_control enable_ibt_type;
41 enum dl_x86_cet_control enable_shstk_type;
43 /* If IBT and SHSTK were previously enabled. */
44 unsigned int feature_1_enabled;
46 /* If IBT and SHSTK should be enabled. */
47 unsigned int enable_feature_1;
49 /* If there are any legacy shared object. */
50 unsigned int feature_1_legacy;
52 /* Which shared object is the first legacy shared object. */
53 unsigned int feature_1_legacy_ibt;
54 unsigned int feature_1_legacy_shstk;
57 /* Check if the object M and its dependencies are legacy object. */
59 static void
60 dl_check_legacy_object (struct link_map *m,
61 struct dl_cet_info *info)
63 unsigned int i;
64 struct link_map *l = NULL;
66 i = m->l_searchlist.r_nlist;
67 while (i-- > 0)
69 /* Check each shared object to see if IBT and SHSTK are enabled. */
70 l = m->l_initfini[i];
72 if (l->l_init_called)
73 continue;
75 #ifdef SHARED
76 /* Skip check for ld.so since it has the features enabled. The
77 features will be disabled later if they are not enabled in
78 executable. */
79 if (l == &GL(dl_rtld_map)
80 || l->l_real == &GL(dl_rtld_map)
81 || (info->program != NULL && l == m))
82 continue;
83 #endif
85 /* IBT and SHSTK set only if enabled in executable and all DSOs.
86 NB: cet_always_on is handled outside of the loop. */
87 info->enable_feature_1 &= ((l->l_x86_feature_1_and
88 & (GNU_PROPERTY_X86_FEATURE_1_IBT
89 | GNU_PROPERTY_X86_FEATURE_1_SHSTK))
90 | ~(GNU_PROPERTY_X86_FEATURE_1_IBT
91 | GNU_PROPERTY_X86_FEATURE_1_SHSTK));
92 if ((info->feature_1_legacy
93 & GNU_PROPERTY_X86_FEATURE_1_IBT) == 0
94 && ((info->enable_feature_1
95 & GNU_PROPERTY_X86_FEATURE_1_IBT)
96 != (info->feature_1_enabled
97 & GNU_PROPERTY_X86_FEATURE_1_IBT)))
99 info->feature_1_legacy_ibt = i;
100 info->feature_1_legacy |= GNU_PROPERTY_X86_FEATURE_1_IBT;
103 if ((info->feature_1_legacy
104 & GNU_PROPERTY_X86_FEATURE_1_SHSTK) == 0
105 && ((info->enable_feature_1
106 & GNU_PROPERTY_X86_FEATURE_1_SHSTK)
107 != (info->feature_1_enabled
108 & GNU_PROPERTY_X86_FEATURE_1_SHSTK)))
110 info->feature_1_legacy_shstk = i;
111 info->feature_1_legacy |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
115 /* Handle cet_always_on. */
116 if ((info->feature_1_enabled
117 & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0
118 && info->enable_ibt_type == cet_always_on)
120 info->feature_1_legacy &= ~GNU_PROPERTY_X86_FEATURE_1_IBT;
121 info->enable_feature_1 |= GNU_PROPERTY_X86_FEATURE_1_IBT;
124 if ((info->feature_1_enabled
125 & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0
126 && info->enable_shstk_type == cet_always_on)
128 info->feature_1_legacy &= ~GNU_PROPERTY_X86_FEATURE_1_SHSTK;
129 info->enable_feature_1 |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
133 #ifdef SHARED
134 /* Enable IBT and SHSTK only if they are enabled in executable. Set
135 feature bits properly at the start of the program. */
137 static void
138 dl_cet_check_startup (struct link_map *m, struct dl_cet_info *info)
140 /* NB: IBT and SHSTK may be disabled by environment variable:
142 GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK.
144 if (CPU_FEATURE_USABLE (IBT))
146 if (info->enable_ibt_type == cet_always_on)
147 info->enable_feature_1 |= GNU_PROPERTY_X86_FEATURE_1_IBT;
148 else
149 info->enable_feature_1 &= ((m->l_x86_feature_1_and
150 & GNU_PROPERTY_X86_FEATURE_1_IBT)
151 | ~GNU_PROPERTY_X86_FEATURE_1_IBT);
153 else
154 info->enable_feature_1 &= ~GNU_PROPERTY_X86_FEATURE_1_IBT;
156 if (CPU_FEATURE_USABLE (SHSTK))
158 if (info->enable_shstk_type == cet_always_on)
159 info->enable_feature_1 |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
160 else
161 info->enable_feature_1 &= ((m->l_x86_feature_1_and
162 & GNU_PROPERTY_X86_FEATURE_1_SHSTK)
163 | ~GNU_PROPERTY_X86_FEATURE_1_SHSTK);
165 else
166 info->enable_feature_1 &= ~GNU_PROPERTY_X86_FEATURE_1_SHSTK;
168 if (info->enable_feature_1 != 0)
169 dl_check_legacy_object (m, info);
171 unsigned int disable_feature_1
172 = info->enable_feature_1 ^ info->feature_1_enabled;
173 if (disable_feature_1 != 0)
175 /* Disable features in the kernel because of legacy objects or
176 cet_always_off. */
177 if (dl_cet_disable_cet (disable_feature_1) != 0)
178 _dl_fatal_printf ("%s: can't disable x86 Features\n",
179 info->program);
181 /* Clear the disabled bits. Sync dl_x86_feature_1 and
182 info->feature_1_enabled with info->enable_feature_1. */
183 info->feature_1_enabled = info->enable_feature_1;
184 GL(dl_x86_feature_1) = info->enable_feature_1;
187 if (HAS_CPU_FEATURE (IBT) || HAS_CPU_FEATURE (SHSTK))
189 /* Lock CET features only if IBT or SHSTK are enabled and are not
190 enabled permissively. */
191 unsigned int feature_1_lock = 0;
193 if (((info->feature_1_enabled & GNU_PROPERTY_X86_FEATURE_1_IBT)
194 != 0)
195 && info->enable_ibt_type != cet_permissive)
196 feature_1_lock |= GNU_PROPERTY_X86_FEATURE_1_IBT;
198 if (((info->feature_1_enabled & GNU_PROPERTY_X86_FEATURE_1_SHSTK)
199 != 0)
200 && info->enable_shstk_type != cet_permissive)
201 feature_1_lock |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
203 if (feature_1_lock != 0
204 && dl_cet_lock_cet () != 0)
205 _dl_fatal_printf ("%s: can't lock CET\n", info->program);
208 THREAD_SETMEM (THREAD_SELF, header.feature_1, GL(dl_x86_feature_1));
210 #endif
212 /* Check feature bits when dlopening the shared object M. */
214 static void
215 dl_cet_check_dlopen (struct link_map *m, struct dl_cet_info *info)
217 /* Check if there are any legacy objects loaded. */
218 if (info->enable_feature_1 != 0)
220 dl_check_legacy_object (m, info);
222 /* Skip if there are no legacy shared objects loaded. */
223 if (info->feature_1_legacy == 0)
224 return;
227 unsigned int disable_feature_1 = 0;
228 unsigned int legacy_obj = 0;
229 const char *msg = NULL;
231 if ((info->feature_1_enabled
232 & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0
233 && (info->feature_1_legacy
234 & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0)
236 if (info->enable_ibt_type != cet_permissive)
238 legacy_obj = info->feature_1_legacy_ibt;
239 msg = N_("rebuild shared object with IBT support enabled");
241 else
242 disable_feature_1 |= GNU_PROPERTY_X86_FEATURE_1_IBT;
245 /* Check the next feature only if there is no error. */
246 if (msg == NULL
247 && (info->feature_1_enabled
248 & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0
249 && (info->feature_1_legacy
250 & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0)
252 if (info->enable_shstk_type != cet_permissive)
254 legacy_obj = info->feature_1_legacy_shstk;
255 msg = N_("rebuild shared object with SHSTK support enabled");
257 else
258 disable_feature_1 |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
261 /* If there is an error, long jump back to the caller. */
262 if (msg != NULL)
263 _dl_signal_error (0, m->l_initfini[legacy_obj]->l_name, "dlopen",
264 msg);
266 if (disable_feature_1 != 0)
268 int res = dl_cet_disable_cet (disable_feature_1);
269 if (res)
271 if ((disable_feature_1
272 & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0)
273 msg = N_("can't disable IBT");
274 else
275 msg = N_("can't disable SHSTK");
276 /* Long jump back to the caller on error. */
277 _dl_signal_error (-res, m->l_initfini[legacy_obj]->l_name,
278 "dlopen", msg);
281 /* Clear the disabled bits in dl_x86_feature_1. */
282 GL(dl_x86_feature_1) &= ~disable_feature_1;
284 THREAD_SETMEM (THREAD_SELF, header.feature_1,
285 GL(dl_x86_feature_1));
289 static void
290 dl_cet_check (struct link_map *m, const char *program)
292 struct dl_cet_info info;
294 /* Check how IBT and SHSTK should be enabled. */
295 info.enable_ibt_type = GL(dl_x86_feature_control).ibt;
296 info.enable_shstk_type = GL(dl_x86_feature_control).shstk;
298 info.feature_1_enabled = GL(dl_x86_feature_1);
300 /* No legacy object check if IBT and SHSTK are always on. */
301 if (info.enable_ibt_type == cet_always_on
302 && info.enable_shstk_type == cet_always_on)
304 #ifdef SHARED
305 /* Set it only during startup. */
306 if (program != NULL)
307 THREAD_SETMEM (THREAD_SELF, header.feature_1,
308 info.feature_1_enabled);
309 #endif
310 return;
313 /* Check if IBT and SHSTK were enabled by kernel. */
314 if (info.feature_1_enabled == 0)
315 return;
317 info.program = program;
319 /* Check which features should be enabled. */
320 info.enable_feature_1 = 0;
321 if (info.enable_ibt_type != cet_always_off)
322 info.enable_feature_1 |= (info.feature_1_enabled
323 & GNU_PROPERTY_X86_FEATURE_1_IBT);
324 if (info.enable_shstk_type != cet_always_off)
325 info.enable_feature_1 |= (info.feature_1_enabled
326 & GNU_PROPERTY_X86_FEATURE_1_SHSTK);
328 /* Start with no legacy objects. */
329 info.feature_1_legacy = 0;
330 info.feature_1_legacy_ibt = 0;
331 info.feature_1_legacy_shstk = 0;
333 #ifdef SHARED
334 if (program)
335 dl_cet_check_startup (m, &info);
336 else
337 #endif
338 dl_cet_check_dlopen (m, &info);
341 void
342 _dl_cet_open_check (struct link_map *l)
344 dl_cet_check (l, NULL);
347 #ifdef SHARED
349 # ifndef LINKAGE
350 # define LINKAGE
351 # endif
353 LINKAGE
354 void
355 _dl_cet_check (struct link_map *main_map, const char *program)
357 dl_cet_check (main_map, program);
359 #endif /* SHARED */