• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)*>(&section[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)*>(&section[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(&section[offset()], reinterpret_cast<const void*>(pr_data), pr_datasz);
122     step(pr_datasz);
123     // Padding
124     memset(&section[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