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/>. */
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
31 #if GNU_PROPERTY_X86_FEATURE_1_SHSTK != X86_FEATURE_1_SHSTK
32 # error GNU_PROPERTY_X86_FEATURE_1_SHSTK != X86_FEATURE_1_SHSTK
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. */
60 dl_check_legacy_object (struct link_map
*m
,
61 struct dl_cet_info
*info
)
64 struct link_map
*l
= NULL
;
66 i
= m
->l_searchlist
.r_nlist
;
69 /* Check each shared object to see if IBT and SHSTK are enabled. */
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
79 if (l
== &GL(dl_rtld_map
)
80 || l
->l_real
== &GL(dl_rtld_map
)
81 || (info
->program
!= NULL
&& l
== m
))
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
;
134 /* Enable IBT and SHSTK only if they are enabled in executable. Set
135 feature bits properly at the start of the program. */
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
;
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
);
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
;
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
);
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
177 if (dl_cet_disable_cet (disable_feature_1
) != 0)
178 _dl_fatal_printf ("%s: can't disable x86 Features\n",
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
)
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
)
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
));
212 /* Check feature bits when dlopening the shared object M. */
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)
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");
242 disable_feature_1
|= GNU_PROPERTY_X86_FEATURE_1_IBT
;
245 /* Check the next feature only if there is no error. */
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");
258 disable_feature_1
|= GNU_PROPERTY_X86_FEATURE_1_SHSTK
;
261 /* If there is an error, long jump back to the caller. */
263 _dl_signal_error (0, m
->l_initfini
[legacy_obj
]->l_name
, "dlopen",
266 if (disable_feature_1
!= 0)
268 int res
= dl_cet_disable_cet (disable_feature_1
);
271 if ((disable_feature_1
272 & GNU_PROPERTY_X86_FEATURE_1_IBT
) != 0)
273 msg
= N_("can't disable IBT");
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
,
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
));
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
)
305 /* Set it only during startup. */
307 THREAD_SETMEM (THREAD_SELF
, header
.feature_1
,
308 info
.feature_1_enabled
);
313 /* Check if IBT and SHSTK were enabled by kernel. */
314 if (info
.feature_1_enabled
== 0)
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;
335 dl_cet_check_startup (m
, &info
);
338 dl_cet_check_dlopen (m
, &info
);
342 _dl_cet_open_check (struct link_map
*l
)
344 dl_cet_check (l
, NULL
);
355 _dl_cet_check (struct link_map
*main_map
, const char *program
)
357 dl_cet_check (main_map
, program
);