]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/x86/dl-cet.c
Update copyright dates with scripts/update-copyrights
[thirdparty/glibc.git] / sysdeps / x86 / dl-cet.c
CommitLineData
f753fa7d 1/* x86 CET initializers function.
2b778ceb 2 Copyright (C) 2018-2021 Free Software Foundation, Inc.
f753fa7d
L
3
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.
8
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.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
5a82c748 16 <https://www.gnu.org/licenses/>. */
f753fa7d
L
17
18#include <unistd.h>
19#include <errno.h>
20#include <libintl.h>
21#include <ldsodefs.h>
22#include <dl-cet.h>
f753fa7d
L
23
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
34
f753fa7d
L
35/* Check if object M is compatible with CET. */
36
37static void
38dl_cet_check (struct link_map *m, const char *program)
39{
40 /* Check how IBT should be enabled. */
674ea882
L
41 enum dl_x86_cet_control enable_ibt_type
42 = GL(dl_x86_feature_control).ibt;
f753fa7d 43 /* Check how SHSTK should be enabled. */
674ea882
L
44 enum dl_x86_cet_control enable_shstk_type
45 = GL(dl_x86_feature_control).shstk;
f753fa7d
L
46
47 /* No legacy object check if both IBT and SHSTK are always on. */
674ea882
L
48 if (enable_ibt_type == cet_always_on
49 && enable_shstk_type == cet_always_on)
f753fa7d
L
50 return;
51
52 /* Check if IBT is enabled by kernel. */
53 bool ibt_enabled
674ea882 54 = (GL(dl_x86_feature_1) & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0;
f753fa7d
L
55 /* Check if SHSTK is enabled by kernel. */
56 bool shstk_enabled
674ea882 57 = (GL(dl_x86_feature_1) & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0;
f753fa7d
L
58
59 if (ibt_enabled || shstk_enabled)
60 {
61 struct link_map *l = NULL;
1fabdb99
L
62 unsigned int ibt_legacy = 0, shstk_legacy = 0;
63 bool found_ibt_legacy = false, found_shstk_legacy = false;
f753fa7d
L
64
65 /* Check if IBT and SHSTK are enabled in object. */
66 bool enable_ibt = (ibt_enabled
674ea882 67 && enable_ibt_type != cet_always_off);
f753fa7d 68 bool enable_shstk = (shstk_enabled
674ea882 69 && enable_shstk_type != cet_always_off);
f753fa7d
L
70 if (program)
71 {
72 /* Enable IBT and SHSTK only if they are enabled in executable.
73 NB: IBT and SHSTK may be disabled by environment variable:
74
dce452dc 75 GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK
f753fa7d 76 */
94cd37eb 77 enable_ibt &= (HAS_CPU_FEATURE (IBT)
674ea882 78 && (enable_ibt_type == cet_always_on
f753fa7d 79 || (m->l_cet & lc_ibt) != 0));
94cd37eb 80 enable_shstk &= (HAS_CPU_FEATURE (SHSTK)
674ea882 81 && (enable_shstk_type == cet_always_on
f753fa7d
L
82 || (m->l_cet & lc_shstk) != 0));
83 }
84
85 /* ld.so is CET-enabled by kernel. But shared objects may not
86 support IBT nor SHSTK. */
87 if (enable_ibt || enable_shstk)
88 {
f753fa7d 89 unsigned int i;
f753fa7d
L
90
91 i = m->l_searchlist.r_nlist;
92 while (i-- > 0)
93 {
94 /* Check each shared object to see if IBT and SHSTK are
95 enabled. */
96 l = m->l_initfini[i];
97
98 if (l->l_init_called)
99 continue;
100
101#ifdef SHARED
102 /* Skip CET check for ld.so since ld.so is CET-enabled.
103 CET will be disabled later if CET isn't enabled in
104 executable. */
105 if (l == &GL(dl_rtld_map)
106 || l->l_real == &GL(dl_rtld_map)
107 || (program && l == m))
108 continue;
109#endif
110
1fabdb99
L
111 /* IBT is enabled only if it is enabled in executable as
112 well as all shared objects. */
674ea882 113 enable_ibt &= (enable_ibt_type == cet_always_on
1fabdb99
L
114 || (l->l_cet & lc_ibt) != 0);
115 if (!found_ibt_legacy && enable_ibt != ibt_enabled)
f753fa7d 116 {
1fabdb99
L
117 found_ibt_legacy = true;
118 ibt_legacy = i;
f753fa7d
L
119 }
120
121 /* SHSTK is enabled only if it is enabled in executable as
122 well as all shared objects. */
674ea882 123 enable_shstk &= (enable_shstk_type == cet_always_on
f753fa7d 124 || (l->l_cet & lc_shstk) != 0);
1fabdb99 125 if (enable_shstk != shstk_enabled)
f753fa7d 126 {
1fabdb99
L
127 found_shstk_legacy = true;
128 shstk_legacy = i;
f753fa7d 129 }
f753fa7d
L
130 }
131 }
132
133 bool cet_feature_changed = false;
134
135 if (enable_ibt != ibt_enabled || enable_shstk != shstk_enabled)
136 {
1fabdb99 137 if (!program)
f753fa7d 138 {
674ea882 139 if (enable_ibt_type != cet_permissive)
1fabdb99
L
140 {
141 /* When IBT is enabled, we cannot dlopen a shared
142 object without IBT. */
143 if (found_ibt_legacy)
144 _dl_signal_error (0,
145 m->l_initfini[ibt_legacy]->l_name,
146 "dlopen",
147 N_("rebuild shared object with IBT support enabled"));
148 }
149
674ea882 150 if (enable_shstk_type != cet_permissive)
1fabdb99
L
151 {
152 /* When SHSTK is enabled, we cannot dlopen a shared
153 object without SHSTK. */
154 if (found_shstk_legacy)
155 _dl_signal_error (0,
156 m->l_initfini[shstk_legacy]->l_name,
157 "dlopen",
158 N_("rebuild shared object with SHSTK support enabled"));
159 }
160
674ea882
L
161 if (enable_ibt_type != cet_permissive
162 && enable_shstk_type != cet_permissive)
1fabdb99 163 return;
f753fa7d
L
164 }
165
166 /* Disable IBT and/or SHSTK if they are enabled by kernel, but
167 disabled in executable or shared objects. */
168 unsigned int cet_feature = 0;
169
1fabdb99 170 if (!enable_ibt)
f753fa7d
L
171 cet_feature |= GNU_PROPERTY_X86_FEATURE_1_IBT;
172 if (!enable_shstk)
173 cet_feature |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
174
175 int res = dl_cet_disable_cet (cet_feature);
176 if (res != 0)
177 {
178 if (program)
179 _dl_fatal_printf ("%s: can't disable CET\n", program);
180 else
1fabdb99
L
181 {
182 if (found_ibt_legacy)
183 l = m->l_initfini[ibt_legacy];
184 else
185 l = m->l_initfini[shstk_legacy];
186 _dl_signal_error (-res, l->l_name, "dlopen",
187 N_("can't disable CET"));
188 }
f753fa7d
L
189 }
190
191 /* Clear the disabled bits in dl_x86_feature_1. */
674ea882 192 GL(dl_x86_feature_1) &= ~cet_feature;
f753fa7d
L
193
194 cet_feature_changed = true;
195 }
196
197#ifdef SHARED
1fabdb99 198 if (program && (ibt_enabled || shstk_enabled))
f753fa7d 199 {
1fabdb99 200 if ((!ibt_enabled
674ea882 201 || enable_ibt_type != cet_permissive)
1fabdb99 202 && (!shstk_enabled
674ea882 203 || enable_shstk_type != cet_permissive))
1fabdb99
L
204 {
205 /* Lock CET if IBT or SHSTK is enabled in executable unless
206 IBT or SHSTK is enabled permissively. */
207 int res = dl_cet_lock_cet ();
208 if (res != 0)
209 _dl_fatal_printf ("%s: can't lock CET\n", program);
210 }
f753fa7d 211
1fabdb99 212 /* Set feature_1 if IBT or SHSTK is enabled in executable. */
f753fa7d
L
213 cet_feature_changed = true;
214 }
215#endif
216
217 if (cet_feature_changed)
218 {
219 unsigned int feature_1 = 0;
220 if (enable_ibt)
221 feature_1 |= GNU_PROPERTY_X86_FEATURE_1_IBT;
222 if (enable_shstk)
223 feature_1 |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
224 struct pthread *self = THREAD_SELF;
225 THREAD_SETMEM (self, header.feature_1, feature_1);
226 }
227 }
228}
229
230void
231_dl_cet_open_check (struct link_map *l)
232{
233 dl_cet_check (l, NULL);
234}
235
236#ifdef SHARED
237
238# ifndef LINKAGE
239# define LINKAGE
240# endif
241
242LINKAGE
243void
244_dl_cet_check (struct link_map *main_map, const char *program)
245{
246 dl_cet_check (main_map, program);
247}
248#endif /* SHARED */