1 /* x86-64 CET initializers function.
2 Copyright (C) 2018-2024 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/>. */
23 #include <sys/single_threaded.h>
25 /* GNU_PROPERTY_X86_FEATURE_1_IBT and GNU_PROPERTY_X86_FEATURE_1_SHSTK
26 are defined in <elf.h>, which are only available for C sources.
27 X86_FEATURE_1_IBT and X86_FEATURE_1_SHSTK are defined in <sysdep.h>
28 which are available for both C and asm sources. They must match. */
29 #if GNU_PROPERTY_X86_FEATURE_1_IBT != X86_FEATURE_1_IBT
30 # error GNU_PROPERTY_X86_FEATURE_1_IBT != X86_FEATURE_1_IBT
32 #if GNU_PROPERTY_X86_FEATURE_1_SHSTK != X86_FEATURE_1_SHSTK
33 # error GNU_PROPERTY_X86_FEATURE_1_SHSTK != X86_FEATURE_1_SHSTK
40 /* Check how IBT and SHSTK should be enabled. */
41 enum dl_x86_cet_control enable_ibt_type
;
42 enum dl_x86_cet_control enable_shstk_type
;
44 /* If IBT and SHSTK were previously enabled. */
45 unsigned int feature_1_enabled
;
47 /* If IBT and SHSTK should be enabled. */
48 unsigned int enable_feature_1
;
50 /* If there are any legacy shared object. */
51 unsigned int feature_1_legacy
;
53 /* Which shared object is the first legacy shared object. */
54 unsigned int feature_1_legacy_ibt
;
55 unsigned int feature_1_legacy_shstk
;
58 /* Check if the object M and its dependencies are legacy object. */
61 dl_check_legacy_object (struct link_map
*m
,
62 struct dl_cet_info
*info
)
65 struct link_map
*l
= NULL
;
67 i
= m
->l_searchlist
.r_nlist
;
70 /* Check each shared object to see if IBT and SHSTK are enabled. */
77 /* Skip check for ld.so since it has the features enabled. The
78 features will be disabled later if they are not enabled in
80 if (l
== &GL(dl_rtld_map
)
81 || l
->l_real
== &GL(dl_rtld_map
)
82 || (info
->program
!= NULL
&& l
== m
))
86 /* IBT and SHSTK set only if enabled in executable and all DSOs.
87 NB: cet_always_on is handled outside of the loop. */
88 info
->enable_feature_1
&= ((l
->l_x86_feature_1_and
89 & (GNU_PROPERTY_X86_FEATURE_1_IBT
90 | GNU_PROPERTY_X86_FEATURE_1_SHSTK
))
91 | ~(GNU_PROPERTY_X86_FEATURE_1_IBT
92 | GNU_PROPERTY_X86_FEATURE_1_SHSTK
));
93 if ((info
->feature_1_legacy
94 & GNU_PROPERTY_X86_FEATURE_1_IBT
) == 0
95 && ((info
->enable_feature_1
96 & GNU_PROPERTY_X86_FEATURE_1_IBT
)
97 != (info
->feature_1_enabled
98 & GNU_PROPERTY_X86_FEATURE_1_IBT
)))
100 info
->feature_1_legacy_ibt
= i
;
101 info
->feature_1_legacy
|= GNU_PROPERTY_X86_FEATURE_1_IBT
;
104 if ((info
->feature_1_legacy
105 & GNU_PROPERTY_X86_FEATURE_1_SHSTK
) == 0
106 && ((info
->enable_feature_1
107 & GNU_PROPERTY_X86_FEATURE_1_SHSTK
)
108 != (info
->feature_1_enabled
109 & GNU_PROPERTY_X86_FEATURE_1_SHSTK
)))
111 info
->feature_1_legacy_shstk
= i
;
112 info
->feature_1_legacy
|= GNU_PROPERTY_X86_FEATURE_1_SHSTK
;
116 /* Handle cet_always_on. */
117 if ((info
->feature_1_enabled
118 & GNU_PROPERTY_X86_FEATURE_1_IBT
) != 0
119 && info
->enable_ibt_type
== cet_always_on
)
121 info
->feature_1_legacy
&= ~GNU_PROPERTY_X86_FEATURE_1_IBT
;
122 info
->enable_feature_1
|= GNU_PROPERTY_X86_FEATURE_1_IBT
;
125 if ((info
->feature_1_enabled
126 & GNU_PROPERTY_X86_FEATURE_1_SHSTK
) != 0
127 && info
->enable_shstk_type
== cet_always_on
)
129 info
->feature_1_legacy
&= ~GNU_PROPERTY_X86_FEATURE_1_SHSTK
;
130 info
->enable_feature_1
|= GNU_PROPERTY_X86_FEATURE_1_SHSTK
;
135 /* Enable IBT and SHSTK only if they are enabled in executable. Set
136 feature bits properly at the start of the program. */
139 dl_cet_check_startup (struct link_map
*m
, struct dl_cet_info
*info
)
141 /* NB: IBT and SHSTK may be disabled by environment variable:
143 GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK.
145 if (CPU_FEATURE_USABLE (IBT
))
147 if (info
->enable_ibt_type
== cet_always_on
)
148 info
->enable_feature_1
|= GNU_PROPERTY_X86_FEATURE_1_IBT
;
150 info
->enable_feature_1
&= ((m
->l_x86_feature_1_and
151 & GNU_PROPERTY_X86_FEATURE_1_IBT
)
152 | ~GNU_PROPERTY_X86_FEATURE_1_IBT
);
155 info
->enable_feature_1
&= ~GNU_PROPERTY_X86_FEATURE_1_IBT
;
157 if (CPU_FEATURE_USABLE (SHSTK
))
159 if (info
->enable_shstk_type
== cet_always_on
)
160 info
->enable_feature_1
|= GNU_PROPERTY_X86_FEATURE_1_SHSTK
;
162 info
->enable_feature_1
&= ((m
->l_x86_feature_1_and
163 & GNU_PROPERTY_X86_FEATURE_1_SHSTK
)
164 | ~GNU_PROPERTY_X86_FEATURE_1_SHSTK
);
167 info
->enable_feature_1
&= ~GNU_PROPERTY_X86_FEATURE_1_SHSTK
;
169 if (info
->enable_feature_1
!= 0)
170 dl_check_legacy_object (m
, info
);
172 unsigned int disable_feature_1
173 = info
->enable_feature_1
^ info
->feature_1_enabled
;
174 if (disable_feature_1
!= 0)
176 /* Clear the disabled bits. Sync dl_x86_feature_1 and
177 info->feature_1_enabled with info->enable_feature_1. */
178 info
->feature_1_enabled
= info
->enable_feature_1
;
179 GL(dl_x86_feature_1
) = info
->enable_feature_1
;
184 /* Check feature bits when dlopening the shared object M. */
187 dl_cet_check_dlopen (struct link_map
*m
, struct dl_cet_info
*info
)
189 /* Check if there are any legacy objects loaded. */
190 if (info
->enable_feature_1
!= 0)
192 dl_check_legacy_object (m
, info
);
194 /* Skip if there are no legacy shared objects loaded. */
195 if (info
->feature_1_legacy
== 0)
199 unsigned int disable_feature_1
= 0;
200 unsigned int legacy_obj
= 0;
201 const char *msg
= NULL
;
203 if ((info
->feature_1_enabled
204 & GNU_PROPERTY_X86_FEATURE_1_IBT
) != 0
205 && (info
->feature_1_legacy
206 & GNU_PROPERTY_X86_FEATURE_1_IBT
) != 0)
208 /* Don't disable IBT if not single threaded since IBT may be still
209 enabled in other threads. */
210 if (info
->enable_ibt_type
!= cet_permissive
213 legacy_obj
= info
->feature_1_legacy_ibt
;
214 msg
= N_("rebuild shared object with IBT support enabled");
217 disable_feature_1
|= GNU_PROPERTY_X86_FEATURE_1_IBT
;
220 /* Check the next feature only if there is no error. */
222 && (info
->feature_1_enabled
223 & GNU_PROPERTY_X86_FEATURE_1_SHSTK
) != 0
224 && (info
->feature_1_legacy
225 & GNU_PROPERTY_X86_FEATURE_1_SHSTK
) != 0)
227 /* Don't disable SHSTK if not single threaded since SHSTK may be
228 still enabled in other threads. */
229 if (info
->enable_shstk_type
!= cet_permissive
232 legacy_obj
= info
->feature_1_legacy_shstk
;
233 msg
= N_("rebuild shared object with SHSTK support enabled");
236 disable_feature_1
|= GNU_PROPERTY_X86_FEATURE_1_SHSTK
;
239 /* If there is an error, long jump back to the caller. */
241 _dl_signal_error (0, m
->l_initfini
[legacy_obj
]->l_name
, "dlopen",
244 if (disable_feature_1
!= 0)
246 int res
= dl_cet_disable_cet (disable_feature_1
);
249 if ((disable_feature_1
250 & GNU_PROPERTY_X86_FEATURE_1_IBT
) != 0)
251 msg
= N_("can't disable IBT");
253 msg
= N_("can't disable SHSTK");
254 /* Long jump back to the caller on error. */
255 _dl_signal_error (-res
, m
->l_initfini
[legacy_obj
]->l_name
,
259 /* Clear the disabled bits in dl_x86_feature_1. */
260 GL(dl_x86_feature_1
) &= ~disable_feature_1
;
262 THREAD_SETMEM (THREAD_SELF
, header
.feature_1
,
263 GL(dl_x86_feature_1
));
268 dl_cet_check (struct link_map
*m
, const char *program
)
270 struct dl_cet_info info
;
272 /* CET is enabled only if RTLD_START_ENABLE_X86_FEATURES is defined. */
273 #if defined SHARED && defined RTLD_START_ENABLE_X86_FEATURES
274 /* Set dl_x86_feature_1 to features enabled in the executable. */
276 GL(dl_x86_feature_1
) = (m
->l_x86_feature_1_and
278 | X86_FEATURE_1_SHSTK
));
281 /* Check how IBT and SHSTK should be enabled. */
282 info
.enable_ibt_type
= GL(dl_x86_feature_control
).ibt
;
283 info
.enable_shstk_type
= GL(dl_x86_feature_control
).shstk
;
285 info
.feature_1_enabled
= GL(dl_x86_feature_1
);
287 /* No legacy object check if IBT and SHSTK are always on. */
288 if (info
.enable_ibt_type
== cet_always_on
289 && info
.enable_shstk_type
== cet_always_on
)
292 /* Check if IBT and SHSTK were enabled. */
293 if (info
.feature_1_enabled
== 0)
296 info
.program
= program
;
298 /* Check which features should be enabled. */
299 info
.enable_feature_1
= 0;
300 if (info
.enable_ibt_type
!= cet_always_off
)
301 info
.enable_feature_1
|= (info
.feature_1_enabled
302 & GNU_PROPERTY_X86_FEATURE_1_IBT
);
303 if (info
.enable_shstk_type
!= cet_always_off
)
304 info
.enable_feature_1
|= (info
.feature_1_enabled
305 & GNU_PROPERTY_X86_FEATURE_1_SHSTK
);
307 /* Start with no legacy objects. */
308 info
.feature_1_legacy
= 0;
309 info
.feature_1_legacy_ibt
= 0;
310 info
.feature_1_legacy_shstk
= 0;
314 dl_cet_check_startup (m
, &info
);
317 dl_cet_check_dlopen (m
, &info
);
321 _dl_cet_open_check (struct link_map
*l
)
323 dl_cet_check (l
, NULL
);
326 /* Set GL(dl_x86_feature_1) to the enabled features and clear the
327 active bits of the disabled features. */
329 attribute_hidden
void
330 _dl_cet_setup_features (unsigned int cet_feature
)
332 /* NB: cet_feature == GL(dl_x86_feature_1) which is set to features
333 enabled from executable, not necessarily supported by kernel. */
334 if (cet_feature
!= 0)
336 cet_feature
= dl_cet_get_cet_status ();
337 if (cet_feature
!= 0)
339 THREAD_SETMEM (THREAD_SELF
, header
.feature_1
, cet_feature
);
341 /* Lock CET if IBT or SHSTK is enabled in executable. Don't
342 lock CET if IBT or SHSTK is enabled permissively. */
343 if (GL(dl_x86_feature_control
).ibt
!= cet_permissive
344 && (GL(dl_x86_feature_control
).shstk
!= cet_permissive
))
345 dl_cet_lock_cet (cet_feature
);
347 /* Sync GL(dl_x86_feature_1) with kernel. */
348 GL(dl_x86_feature_1
) = cet_feature
;
360 _dl_cet_check (struct link_map
*main_map
, const char *program
)
362 dl_cet_check (main_map
, program
);