1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <stdlib.h>
30 #include <iostream>
31 #include <sstream>
32 #include <string>
33
34 #include <gtest/gtest.h>
35
36 #include "linker.h"
37 #include "linker_globals.h"
38 #include "linker_note_gnu_property.h"
39 #include "platform/bionic/macros.h"
40
41 #define SONAME "test_so"
42
43 static char error_buffer[1024];
44
linker_get_error_buffer()45 char* linker_get_error_buffer() {
46 return error_buffer;
47 }
48
linker_get_error_buffer_size()49 size_t linker_get_error_buffer_size() {
50 return std::size(error_buffer);
51 }
52
reset_error_buffer()53 static void reset_error_buffer() {
54 error_buffer[0] = '\0';
55 }
56
57 platform_properties g_platform_properties {
58 #if defined(__aarch64__)
59 // Assume "hardware" supports Armv8.5-A BTI.
60 .bti_supported = true
61 #endif
62 };
63
64 // Helper macro to make the test cleaner.
65 #define PHDR_WITH_NOTE_GNU_PROPERTY(__prop) \
66 reset_error_buffer(); \
67 ElfW(Phdr) phdrs[] = { \
68 {.p_type = PT_LOAD}, \
69 { \
70 .p_type = PT_GNU_PROPERTY, \
71 .p_vaddr = reinterpret_cast<ElfW(Addr)>(__prop), \
72 .p_memsz = sizeof(ElfW(NhdrGNUProperty)) + (__prop)->nhdr.n_descsz, \
73 }, \
74 {.p_type = PT_NULL}, \
75 }; \
76 auto note = GnuPropertySection(&phdrs[0], std::size(phdrs), 0, SONAME)
77
78 // Helper to check for no error message.
79 #define ASSERT_NO_ERROR_MSG() ASSERT_STREQ(error_buffer, "")
80
81 // Helper to check expected error message.
82 #define ASSERT_ERROR_MSG_EQ(__expected) ASSERT_STREQ(error_buffer, "\"" SONAME "\" " __expected)
83
test_bti_not_supported(GnuPropertySection & note __unused)84 static void test_bti_not_supported(GnuPropertySection& note __unused) {
85 #if defined(__aarch64__)
86 ASSERT_FALSE(note.IsBTICompatible());
87 #endif
88 }
89
90 #if defined(__aarch64__)
test_bti_supported(GnuPropertySection & note __unused)91 static void test_bti_supported(GnuPropertySection& note __unused) {
92 ASSERT_TRUE(note.IsBTICompatible());
93 }
94 #endif
95
96 // Helper class to build a well-formed .note.gnu.property section.
97 class GnuPropertySectionBuilder {
98 public:
GnuPropertySectionBuilder()99 GnuPropertySectionBuilder() {
100 note = reinterpret_cast<ElfW(NhdrGNUProperty)*>(§ion[0]);
101 note->nhdr.n_namesz = 4;
102 note->nhdr.n_descsz = 0;
103 note->nhdr.n_type = NT_GNU_PROPERTY_TYPE_0;
104 memcpy(note->n_name, "GNU", 4);
105 }
106
107 template <typename T>
push(ElfW (Word)pr_type,ElfW (Word)pr_datasz,const T * pr_data)108 bool push(ElfW(Word) pr_type, ElfW(Word) pr_datasz, const T* pr_data) {
109 // Must be aligned.
110 const uintptr_t addition = align_up(pr_datasz, sizeof(ElfW(Addr)));
111 if ((offset() + addition) > kMaxSectionSize) {
112 return false;
113 }
114 ++entries;
115 ElfW(Prop)* prop = reinterpret_cast<ElfW(Prop)*>(§ion[offset()]);
116 // Header
117 prop->pr_type = pr_type;
118 prop->pr_datasz = pr_datasz;
119 step(2 * sizeof(ElfW(Word)));
120 // Data
121 memcpy(§ion[offset()], reinterpret_cast<const void*>(pr_data), pr_datasz);
122 step(pr_datasz);
123 // Padding
124 memset(§ion[offset()], 0xAA, addition - pr_datasz);
125 step(addition - pr_datasz);
126 return true;
127 }
128
ElfW(NhdrGNUProperty)129 ElfW(NhdrGNUProperty)* data() const { return note; }
130
dump() const131 void dump() const {
132 std::cout << ".note.gnu.property\n";
133 dump_member("n_namesz", note->nhdr.n_namesz);
134 dump_member("n_descsz", note->nhdr.n_descsz);
135 dump_member("n_type ", note->nhdr.n_type);
136 dump_member("n_name ", note->n_name);
137 dump_member("entries ", entries);
138 if (entries > 0) {
139 std::cout << " raw data:";
140 const uintptr_t offset = note->nhdr.n_descsz + 16;
141 for (uintptr_t offs = 16; offs < offset; ++offs) {
142 std::cout << std::hex;
143 if ((offs % 8) == 0) {
144 std::cout << "\n ";
145 }
146 auto value = static_cast<unsigned>(section[offs]);
147 std::cout << " ";
148 if (value < 0x10) {
149 std::cout << "0";
150 }
151 std::cout << static_cast<unsigned>(section[offs]);
152 }
153 std::cout << std::dec << "\n";
154 }
155 }
156
corrupt_n_descsz(ElfW (Word)n_descsz)157 void corrupt_n_descsz(ElfW(Word) n_descsz) { note->nhdr.n_descsz = n_descsz; }
158
159 private:
160 template <typename T>
dump_member(const char * name,T value) const161 void dump_member(const char* name, T value) const {
162 std::cout << " " << name << " " << value << "\n";
163 }
164
offset() const165 ElfW(Word) offset() const { return note->nhdr.n_descsz + 16; }
166
167 template <typename T>
step(T value)168 void step(T value) {
169 note->nhdr.n_descsz += static_cast<ElfW(Word)>(value);
170 }
171
172 static const size_t kMaxSectionSize = 1024;
173
174 alignas(8) uint8_t section[kMaxSectionSize];
175 ElfW(NhdrGNUProperty)* note;
176 size_t entries = 0;
177 };
178
179 // Tests that the default constructed instance does not report support
180 // for Armv8.5-A BTI.
TEST(note_gnu_property,default)181 TEST(note_gnu_property, default) {
182 GnuPropertySection note;
183 test_bti_not_supported(note);
184 ASSERT_NO_ERROR_MSG();
185 }
186
187 // Tests that an instance without valid phdr pointer does not report
188 // support for Armv8.5-A BTI.
TEST(note_gnu_property,phdr_null)189 TEST(note_gnu_property, phdr_null) {
190 auto note = GnuPropertySection(nullptr, 0, 0, SONAME);
191 test_bti_not_supported(note);
192 ASSERT_NO_ERROR_MSG();
193 }
194
195 // Tests that an instance without finding PT_GNU_PROPERTY does not
196 // report support for Armv8.5-A BTI.
TEST(note_gnu_property,no_pt_gnu_property)197 TEST(note_gnu_property, no_pt_gnu_property) {
198 ElfW(Phdr) phdrs[] = {
199 {.p_type = PT_LOAD},
200 {.p_type = PT_NULL},
201 };
202
203 reset_error_buffer();
204 auto note = GnuPropertySection(&phdrs[0], std::size(phdrs), 0, SONAME);
205 test_bti_not_supported(note);
206 ASSERT_NO_ERROR_MSG();
207 }
208
209 // Tests the validity check for invalid PT_GNU_PROPERTY size.
TEST(note_gnu_property,pt_gnu_property_bad_size)210 TEST(note_gnu_property, pt_gnu_property_bad_size) {
211 ElfW(Phdr) phdrs[] = {
212 {.p_type = PT_LOAD},
213 {
214 .p_type = PT_GNU_PROPERTY,
215 .p_vaddr = 0,
216 .p_memsz = sizeof(ElfW(NhdrGNUProperty)) - 1, // Invalid
217 },
218 {.p_type = PT_NULL},
219 };
220
221 reset_error_buffer();
222 auto note = GnuPropertySection(&phdrs[0], std::size(phdrs), 0, SONAME);
223 test_bti_not_supported(note);
224 ASSERT_ERROR_MSG_EQ("PT_GNU_PROPERTY segment is too small. Segment size is 15, minimum is 16.");
225 }
226
227 // Tests that advertised n_descsz should still fit into p_memsz.
TEST(note_gnu_property,pt_gnu_property_too_small)228 TEST(note_gnu_property, pt_gnu_property_too_small) {
229 ElfW(NhdrGNUProperty) prop = {
230 .nhdr = {.n_namesz = PT_GNU_PROPERTY, .n_descsz = 1, .n_type = NT_GNU_PROPERTY_TYPE_0},
231 .n_name = "GNU",
232 };
233 ElfW(Phdr) phdrs[] = {
234 {
235 .p_type = PT_GNU_PROPERTY,
236 .p_vaddr = reinterpret_cast<ElfW(Addr)>(&prop),
237 .p_memsz = sizeof(ElfW(NhdrGNUProperty)), // Off by one
238 },
239 };
240
241 reset_error_buffer();
242 auto note = GnuPropertySection(&phdrs[0], std::size(phdrs), 0, SONAME);
243 test_bti_not_supported(note);
244 ASSERT_ERROR_MSG_EQ("PT_GNU_PROPERTY segment p_memsz (16) is too small for note n_descsz (1).");
245 }
246
247 // Tests the validity check for invalid .note.gnu.property type.
TEST(note_gnu_property,pt_gnu_property_bad_type)248 TEST(note_gnu_property, pt_gnu_property_bad_type) {
249 ElfW(NhdrGNUProperty) prop = {
250 .nhdr =
251 {
252 .n_namesz = 4,
253 .n_descsz = 0,
254 .n_type = NT_GNU_PROPERTY_TYPE_0 - 1 // Invalid
255 },
256 .n_name = "GNU",
257 };
258 PHDR_WITH_NOTE_GNU_PROPERTY(&prop);
259 test_bti_not_supported(note);
260 ASSERT_ERROR_MSG_EQ(".note.gnu.property: unexpected note type. Expected 5, got 4.");
261 }
262
263 // Tests the validity check for invalid .note.gnu.property name size.
TEST(note_gnu_property,pt_gnu_property_bad_namesz)264 TEST(note_gnu_property, pt_gnu_property_bad_namesz) {
265 ElfW(NhdrGNUProperty) prop = {
266 .nhdr = {.n_namesz = 3, // Invalid
267 .n_descsz = 0,
268 .n_type = NT_GNU_PROPERTY_TYPE_0},
269 .n_name = "GNU",
270 };
271 PHDR_WITH_NOTE_GNU_PROPERTY(&prop);
272 test_bti_not_supported(note);
273 ASSERT_ERROR_MSG_EQ(".note.gnu.property: unexpected name size. Expected 4, got 3.");
274 }
275
276 // Tests the validity check for invalid .note.gnu.property name.
TEST(note_gnu_property,pt_gnu_property_bad_name)277 TEST(note_gnu_property, pt_gnu_property_bad_name) {
278 ElfW(NhdrGNUProperty) prop = {
279 .nhdr = {.n_namesz = 4, .n_descsz = 0, .n_type = NT_GNU_PROPERTY_TYPE_0},
280 .n_name = "ABC", // Invalid
281 };
282 PHDR_WITH_NOTE_GNU_PROPERTY(&prop);
283 test_bti_not_supported(note);
284 ASSERT_ERROR_MSG_EQ(".note.gnu.property: unexpected name. Expected 'GNU', got 'ABC'.");
285 }
286
287 // Tests the validity check for not enough space for a Program Property header.
TEST(note_gnu_property,pt_gnu_property_pphdr_no_space)288 TEST(note_gnu_property, pt_gnu_property_pphdr_no_space) {
289 ElfW(NhdrGNUProperty) prop = {
290 .nhdr = {.n_namesz = 4,
291 .n_descsz = 7, // Invalid
292 .n_type = NT_GNU_PROPERTY_TYPE_0},
293 .n_name = "GNU",
294 };
295 PHDR_WITH_NOTE_GNU_PROPERTY(&prop);
296 test_bti_not_supported(note);
297 ASSERT_ERROR_MSG_EQ(".note.gnu.property: no more space left for a Program Property Note header.");
298 }
299
300 // Tests an empty .note.gnu.property.
TEST(note_gnu_property,pt_gnu_property_no_data)301 TEST(note_gnu_property, pt_gnu_property_no_data) {
302 GnuPropertySectionBuilder prop;
303 PHDR_WITH_NOTE_GNU_PROPERTY(prop.data());
304 test_bti_not_supported(note);
305 ASSERT_NO_ERROR_MSG();
306 }
307
308 // Tests a .note.gnu.property section with elements with pr_datasz = 0.
TEST(note_gnu_property,pt_gnu_property_no_prop)309 TEST(note_gnu_property, pt_gnu_property_no_prop) {
310 GnuPropertySectionBuilder prop;
311 ASSERT_TRUE(prop.push(1, 0, (void*)nullptr));
312 ASSERT_TRUE(prop.push(2, 0, (void*)nullptr));
313 ASSERT_TRUE(prop.push(3, 0, (void*)nullptr));
314 PHDR_WITH_NOTE_GNU_PROPERTY(prop.data());
315 test_bti_not_supported(note);
316 ASSERT_NO_ERROR_MSG();
317 }
318
319 // Tests that GNU_PROPERTY_AARCH64_FEATURE_1_AND must have pr_datasz = 4.
TEST(note_gnu_property,pt_gnu_property_bad_pr_datasz)320 TEST(note_gnu_property, pt_gnu_property_bad_pr_datasz) {
321 #if defined(__aarch64__)
322 GnuPropertySectionBuilder prop;
323 ElfW(Word) pr_data[] = {GNU_PROPERTY_AARCH64_FEATURE_1_BTI, 0, 0};
324 ASSERT_TRUE(prop.push(GNU_PROPERTY_AARCH64_FEATURE_1_AND, 12, &pr_data));
325 PHDR_WITH_NOTE_GNU_PROPERTY(prop.data());
326 test_bti_not_supported(note);
327 ASSERT_ERROR_MSG_EQ(
328 ".note.gnu.property: property descriptor size is invalid. Expected 4 bytes for "
329 "GNU_PROPERTY_AARCH64_FEATURE_1_AND, got 12.");
330 #else
331 GTEST_SKIP() << "BTI is not supported on this architecture.";
332 #endif
333 }
334
335 // Tests a .note.gnu.property section with only GNU_PROPERTY_AARCH64_FEATURE_1_BTI property array.
TEST(note_gnu_property,pt_gnu_property_ok_1)336 TEST(note_gnu_property, pt_gnu_property_ok_1) {
337 #if defined(__aarch64__)
338 GnuPropertySectionBuilder prop;
339 ElfW(Word) pr_data[] = {GNU_PROPERTY_AARCH64_FEATURE_1_BTI};
340 ASSERT_TRUE(prop.push(GNU_PROPERTY_AARCH64_FEATURE_1_AND, sizeof(pr_data), &pr_data));
341 PHDR_WITH_NOTE_GNU_PROPERTY(prop.data());
342 ASSERT_NO_ERROR_MSG();
343 test_bti_supported(note);
344 #else
345 GTEST_SKIP() << "BTI is not supported on this architecture.";
346 #endif
347 }
348
349 // Tests a .note.gnu.property section with only GNU_PROPERTY_AARCH64_FEATURE_1_BTI property array.
TEST(note_gnu_property,pt_gnu_property_ok_2)350 TEST(note_gnu_property, pt_gnu_property_ok_2) {
351 #if defined(__aarch64__)
352 GnuPropertySectionBuilder prop;
353 ElfW(Word) pr_data[] = {static_cast<ElfW(Word)>(~GNU_PROPERTY_AARCH64_FEATURE_1_BTI)};
354 ASSERT_TRUE(prop.push(GNU_PROPERTY_AARCH64_FEATURE_1_AND, sizeof(pr_data), &pr_data));
355 PHDR_WITH_NOTE_GNU_PROPERTY(prop.data());
356 ASSERT_NO_ERROR_MSG();
357 test_bti_not_supported(note);
358 #else
359 GTEST_SKIP() << "BTI is not supported on this architecture.";
360 #endif
361 }
362
363 // Tests a .note.gnu.property section with more property arrays.
TEST(note_gnu_property,pt_gnu_property_ok_3)364 TEST(note_gnu_property, pt_gnu_property_ok_3) {
365 #if defined(__aarch64__)
366 GnuPropertySectionBuilder prop;
367
368 ElfW(Word) pr_data_0[8] = {0xCD};
369 ASSERT_TRUE(prop.push(1, 4, &pr_data_0));
370 ASSERT_TRUE(prop.push(2, 3, &pr_data_0));
371 ASSERT_TRUE(prop.push(3, 8, &pr_data_0));
372
373 ElfW(Word) pr_data[] = {GNU_PROPERTY_AARCH64_FEATURE_1_BTI};
374 ASSERT_TRUE(prop.push(GNU_PROPERTY_AARCH64_FEATURE_1_AND, sizeof(pr_data), &pr_data));
375
376 ASSERT_TRUE(prop.push(4, 1, &pr_data_0));
377
378 PHDR_WITH_NOTE_GNU_PROPERTY(prop.data());
379 ASSERT_NO_ERROR_MSG();
380 test_bti_supported(note);
381 #else
382 GTEST_SKIP() << "BTI is not supported on this architecture.";
383 #endif
384 }
385
386 // Tests a .note.gnu.property but with bad property descriptor size.
TEST(note_gnu_property,pt_gnu_property_bad_n_descsz)387 TEST(note_gnu_property, pt_gnu_property_bad_n_descsz) {
388 #if defined(__aarch64__)
389 GnuPropertySectionBuilder prop;
390 ElfW(Word) pr_data[] = {GNU_PROPERTY_AARCH64_FEATURE_1_BTI};
391 ASSERT_TRUE(prop.push(GNU_PROPERTY_AARCH64_FEATURE_1_AND, sizeof(pr_data), &pr_data));
392
393 ElfW(Word) n_descsz;
394 if (sizeof(ElfW(Addr)) == 4) {
395 n_descsz = 11;
396 } else {
397 n_descsz = 15;
398 }
399
400 prop.corrupt_n_descsz(n_descsz);
401
402 PHDR_WITH_NOTE_GNU_PROPERTY(prop.data());
403 if (sizeof(ElfW(Addr)) == 4) {
404 ASSERT_ERROR_MSG_EQ(
405 ".note.gnu.property: property descriptor size is invalid. Expected at least 12 bytes, got "
406 "11.");
407 } else {
408 ASSERT_ERROR_MSG_EQ(
409 ".note.gnu.property: property descriptor size is invalid. Expected at least 16 bytes, got "
410 "15.");
411 }
412 test_bti_not_supported(note);
413 #else
414 GTEST_SKIP() << "BTI is not supported on this architecture.";
415 #endif
416 }
417
418 // Tests if platform support is missing.
TEST(note_gnu_property,no_platform_support)419 TEST(note_gnu_property, no_platform_support) {
420 #if defined(__aarch64__)
421 auto bti_supported_orig = g_platform_properties.bti_supported;
422 g_platform_properties.bti_supported = false;
423
424 GnuPropertySectionBuilder prop;
425 ElfW(Word) pr_data[] = {GNU_PROPERTY_AARCH64_FEATURE_1_BTI};
426 ASSERT_TRUE(prop.push(GNU_PROPERTY_AARCH64_FEATURE_1_AND, sizeof(pr_data), &pr_data));
427 PHDR_WITH_NOTE_GNU_PROPERTY(prop.data());
428 ASSERT_NO_ERROR_MSG();
429 test_bti_not_supported(note);
430
431 g_platform_properties.bti_supported = bti_supported_orig;
432 #else
433 GTEST_SKIP() << "BTI is not supported on this architecture.";
434 #endif
435 }
436