1 /* x86 CET initializers function.
2 Copyright (C) 2018-2019 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 <http://www.gnu.org/licenses/>. */
23 #include <cet-tunables.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
37 dl_cet_mark_legacy_region (struct link_map
*l
)
39 /* Mark PT_LOAD segments with PF_X in legacy code page bitmap. */
40 size_t i
, phnum
= l
->l_phnum
;
41 const ElfW(Phdr
) *phdr
= l
->l_phdr
;
43 typedef unsigned long long word_t
;
45 typedef unsigned long word_t
;
47 unsigned int bits_to_set
;
49 #define BITS_PER_WORD (sizeof (word_t) * 8)
50 #define BITMAP_FIRST_WORD_MASK(start) \
51 (~((word_t) 0) << ((start) & (BITS_PER_WORD - 1)))
52 #define BITMAP_LAST_WORD_MASK(nbits) \
53 (~((word_t) 0) >> (-(nbits) & (BITS_PER_WORD - 1)))
55 word_t
*bitmap
= (word_t
*) GL(dl_x86_legacy_bitmap
)[0];
56 word_t bitmap_size
= GL(dl_x86_legacy_bitmap
)[1];
58 size_t page_size
= GLRO(dl_pagesize
);
60 for (i
= 0; i
< phnum
; i
++)
61 if (phdr
[i
].p_type
== PT_LOAD
&& (phdr
[i
].p_flags
& PF_X
))
63 /* One bit in legacy bitmap represents a page. */
64 ElfW(Addr
) start
= (phdr
[i
].p_vaddr
+ l
->l_addr
) / page_size
;
65 ElfW(Addr
) len
= (phdr
[i
].p_memsz
+ page_size
- 1) / page_size
;
66 ElfW(Addr
) end
= start
+ len
;
68 if ((end
/ 8) > bitmap_size
)
71 p
= bitmap
+ (start
/ BITS_PER_WORD
);
72 bits_to_set
= BITS_PER_WORD
- (start
% BITS_PER_WORD
);
73 mask_to_set
= BITMAP_FIRST_WORD_MASK (start
);
75 while (len
>= bits_to_set
)
79 bits_to_set
= BITS_PER_WORD
;
80 mask_to_set
= ~((word_t
) 0);
85 mask_to_set
&= BITMAP_LAST_WORD_MASK (end
);
93 /* Check if object M is compatible with CET. */
96 dl_cet_check (struct link_map
*m
, const char *program
)
98 /* Check how IBT should be enabled. */
99 unsigned int enable_ibt_type
100 = GL(dl_x86_feature_1
)[1] & ((1 << CET_MAX
) - 1);
101 /* Check how SHSTK should be enabled. */
102 unsigned int enable_shstk_type
103 = ((GL(dl_x86_feature_1
)[1] >> CET_MAX
) & ((1 << CET_MAX
) - 1));
105 /* No legacy object check if both IBT and SHSTK are always on. */
106 if (enable_ibt_type
== CET_ALWAYS_ON
107 && enable_shstk_type
== CET_ALWAYS_ON
)
110 /* Check if IBT is enabled by kernel. */
112 = (GL(dl_x86_feature_1
)[0] & GNU_PROPERTY_X86_FEATURE_1_IBT
) != 0;
113 /* Check if SHSTK is enabled by kernel. */
115 = (GL(dl_x86_feature_1
)[0] & GNU_PROPERTY_X86_FEATURE_1_SHSTK
) != 0;
117 if (ibt_enabled
|| shstk_enabled
)
119 struct link_map
*l
= NULL
;
121 /* Check if IBT and SHSTK are enabled in object. */
122 bool enable_ibt
= (ibt_enabled
123 && enable_ibt_type
!= CET_ALWAYS_OFF
);
124 bool enable_shstk
= (shstk_enabled
125 && enable_shstk_type
!= CET_ALWAYS_OFF
);
128 /* Enable IBT and SHSTK only if they are enabled in executable.
129 NB: IBT and SHSTK may be disabled by environment variable:
131 GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK
133 enable_ibt
&= (HAS_CPU_FEATURE (IBT
)
134 && (enable_ibt_type
== CET_ALWAYS_ON
135 || (m
->l_cet
& lc_ibt
) != 0));
136 enable_shstk
&= (HAS_CPU_FEATURE (SHSTK
)
137 && (enable_shstk_type
== CET_ALWAYS_ON
138 || (m
->l_cet
& lc_shstk
) != 0));
141 /* ld.so is CET-enabled by kernel. But shared objects may not
142 support IBT nor SHSTK. */
143 if (enable_ibt
|| enable_shstk
)
147 unsigned int first_legacy
, last_legacy
;
148 bool need_legacy_bitmap
= false;
150 i
= m
->l_searchlist
.r_nlist
;
153 /* Check each shared object to see if IBT and SHSTK are
155 l
= m
->l_initfini
[i
];
157 if (l
->l_init_called
)
161 /* Skip CET check for ld.so since ld.so is CET-enabled.
162 CET will be disabled later if CET isn't enabled in
164 if (l
== &GL(dl_rtld_map
)
165 || l
->l_real
== &GL(dl_rtld_map
)
166 || (program
&& l
== m
))
171 && enable_ibt_type
!= CET_ALWAYS_ON
172 && !(l
->l_cet
& lc_ibt
))
174 /* Remember the first and last legacy objects. */
175 if (!need_legacy_bitmap
)
178 need_legacy_bitmap
= true;
181 /* SHSTK is enabled only if it is enabled in executable as
182 well as all shared objects. */
183 enable_shstk
&= (enable_shstk_type
== CET_ALWAYS_ON
184 || (l
->l_cet
& lc_shstk
) != 0);
187 if (need_legacy_bitmap
)
189 if (GL(dl_x86_legacy_bitmap
)[0])
191 /* Change legacy bitmap to writable. */
192 if (__mprotect ((void *) GL(dl_x86_legacy_bitmap
)[0],
193 GL(dl_x86_legacy_bitmap
)[1],
194 PROT_READ
| PROT_WRITE
) < 0)
198 _dl_fatal_printf ("%s: mprotect legacy bitmap failed\n",
201 _dl_signal_error (EINVAL
, l
->l_name
, "dlopen",
202 N_("mprotect legacy bitmap failed"));
207 /* Allocate legacy bitmap. */
208 int res
= dl_cet_allocate_legacy_bitmap
209 (GL(dl_x86_legacy_bitmap
));
213 _dl_fatal_printf ("%s: legacy bitmap isn't available\n",
216 _dl_signal_error (EINVAL
, l
->l_name
, "dlopen",
217 N_("legacy bitmap isn't available"));
221 /* Put legacy shared objects in legacy bitmap. */
222 for (i
= first_legacy
; i
<= last_legacy
; i
++)
224 l
= m
->l_initfini
[i
];
226 if (l
->l_init_called
|| (l
->l_cet
& lc_ibt
))
230 if (l
== &GL(dl_rtld_map
)
231 || l
->l_real
== &GL(dl_rtld_map
)
232 || (program
&& l
== m
))
236 /* If IBT is enabled in executable and IBT isn't enabled
237 in this shard object, mark PT_LOAD segments with PF_X
238 in legacy code page bitmap. */
239 res
= dl_cet_mark_legacy_region (l
);
243 _dl_fatal_printf ("%s: failed to mark legacy code region\n",
246 _dl_signal_error (-res
, l
->l_name
, "dlopen",
247 N_("failed to mark legacy code region"));
251 /* Change legacy bitmap to read-only. */
252 if (__mprotect ((void *) GL(dl_x86_legacy_bitmap
)[0],
253 GL(dl_x86_legacy_bitmap
)[1], PROT_READ
) < 0)
254 goto mprotect_failure
;
258 bool cet_feature_changed
= false;
260 if (enable_ibt
!= ibt_enabled
|| enable_shstk
!= shstk_enabled
)
263 && enable_shstk_type
!= CET_PERMISSIVE
)
265 /* When SHSTK is enabled, we can't dlopening a shared
266 object without SHSTK. */
267 if (enable_shstk
!= shstk_enabled
)
268 _dl_signal_error (EINVAL
, l
->l_name
, "dlopen",
269 N_("shadow stack isn't enabled"));
273 /* Disable IBT and/or SHSTK if they are enabled by kernel, but
274 disabled in executable or shared objects. */
275 unsigned int cet_feature
= 0;
277 /* Disable IBT only during program startup. */
278 if (program
&& !enable_ibt
)
279 cet_feature
|= GNU_PROPERTY_X86_FEATURE_1_IBT
;
281 cet_feature
|= GNU_PROPERTY_X86_FEATURE_1_SHSTK
;
283 int res
= dl_cet_disable_cet (cet_feature
);
287 _dl_fatal_printf ("%s: can't disable CET\n", program
);
289 _dl_signal_error (-res
, l
->l_name
, "dlopen",
290 N_("can't disable CET"));
293 /* Clear the disabled bits in dl_x86_feature_1. */
294 GL(dl_x86_feature_1
)[0] &= ~cet_feature
;
296 cet_feature_changed
= true;
302 || enable_shstk_type
!= CET_PERMISSIVE
)
303 && (ibt_enabled
|| shstk_enabled
))
305 /* Lock CET if IBT or SHSTK is enabled in executable. Don't
306 lock CET if SHSTK is enabled permissively. */
307 int res
= dl_cet_lock_cet ();
309 _dl_fatal_printf ("%s: can't lock CET\n", program
);
311 cet_feature_changed
= true;
315 if (cet_feature_changed
)
317 unsigned int feature_1
= 0;
319 feature_1
|= GNU_PROPERTY_X86_FEATURE_1_IBT
;
321 feature_1
|= GNU_PROPERTY_X86_FEATURE_1_SHSTK
;
322 struct pthread
*self
= THREAD_SELF
;
323 THREAD_SETMEM (self
, header
.feature_1
, feature_1
);
329 _dl_cet_open_check (struct link_map
*l
)
331 dl_cet_check (l
, NULL
);
342 _dl_cet_check (struct link_map
*main_map
, const char *program
)
344 dl_cet_check (main_map
, program
);