xref: /aosp_15_r20/bionic/linker/linker_note_gnu_property.cpp (revision 8d67ca893c1523eb926b9080dbe4e2ffd2a27ba1)
1*8d67ca89SAndroid Build Coastguard Worker /*
2*8d67ca89SAndroid Build Coastguard Worker  * Copyright (C) 2020 The Android Open Source Project
3*8d67ca89SAndroid Build Coastguard Worker  * All rights reserved.
4*8d67ca89SAndroid Build Coastguard Worker  *
5*8d67ca89SAndroid Build Coastguard Worker  * Redistribution and use in source and binary forms, with or without
6*8d67ca89SAndroid Build Coastguard Worker  * modification, are permitted provided that the following conditions
7*8d67ca89SAndroid Build Coastguard Worker  * are met:
8*8d67ca89SAndroid Build Coastguard Worker  *  * Redistributions of source code must retain the above copyright
9*8d67ca89SAndroid Build Coastguard Worker  *    notice, this list of conditions and the following disclaimer.
10*8d67ca89SAndroid Build Coastguard Worker  *  * Redistributions in binary form must reproduce the above copyright
11*8d67ca89SAndroid Build Coastguard Worker  *    notice, this list of conditions and the following disclaimer in
12*8d67ca89SAndroid Build Coastguard Worker  *    the documentation and/or other materials provided with the
13*8d67ca89SAndroid Build Coastguard Worker  *    distribution.
14*8d67ca89SAndroid Build Coastguard Worker  *
15*8d67ca89SAndroid Build Coastguard Worker  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16*8d67ca89SAndroid Build Coastguard Worker  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17*8d67ca89SAndroid Build Coastguard Worker  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18*8d67ca89SAndroid Build Coastguard Worker  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19*8d67ca89SAndroid Build Coastguard Worker  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20*8d67ca89SAndroid Build Coastguard Worker  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21*8d67ca89SAndroid Build Coastguard Worker  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22*8d67ca89SAndroid Build Coastguard Worker  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23*8d67ca89SAndroid Build Coastguard Worker  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24*8d67ca89SAndroid Build Coastguard Worker  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25*8d67ca89SAndroid Build Coastguard Worker  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*8d67ca89SAndroid Build Coastguard Worker  * SUCH DAMAGE.
27*8d67ca89SAndroid Build Coastguard Worker  */
28*8d67ca89SAndroid Build Coastguard Worker 
29*8d67ca89SAndroid Build Coastguard Worker #include "linker_note_gnu_property.h"
30*8d67ca89SAndroid Build Coastguard Worker 
31*8d67ca89SAndroid Build Coastguard Worker #include <elf.h>
32*8d67ca89SAndroid Build Coastguard Worker #include <link.h>
33*8d67ca89SAndroid Build Coastguard Worker 
34*8d67ca89SAndroid Build Coastguard Worker #include "linker.h"
35*8d67ca89SAndroid Build Coastguard Worker #include "linker_debug.h"
36*8d67ca89SAndroid Build Coastguard Worker #include "linker_globals.h"
37*8d67ca89SAndroid Build Coastguard Worker #include "linker_soinfo.h"
38*8d67ca89SAndroid Build Coastguard Worker 
GnuPropertySection(const soinfo * si)39*8d67ca89SAndroid Build Coastguard Worker GnuPropertySection::GnuPropertySection(const soinfo* si)
40*8d67ca89SAndroid Build Coastguard Worker     : GnuPropertySection(si->phdr, si->phnum, si->load_bias, si->get_realpath()) {}
41*8d67ca89SAndroid Build Coastguard Worker 
GnuPropertySection(const ElfW (Phdr)* phdr,size_t phdr_count,const ElfW (Addr)load_bias,const char * name)42*8d67ca89SAndroid Build Coastguard Worker GnuPropertySection::GnuPropertySection(const ElfW(Phdr)* phdr, size_t phdr_count,
43*8d67ca89SAndroid Build Coastguard Worker                                        const ElfW(Addr) load_bias, const char* name) {
44*8d67ca89SAndroid Build Coastguard Worker   // Try to find PT_GNU_PROPERTY segment.
45*8d67ca89SAndroid Build Coastguard Worker   auto note_gnu_property = FindSegment(phdr, phdr_count, load_bias, name);
46*8d67ca89SAndroid Build Coastguard Worker   // Perform some validity checks.
47*8d67ca89SAndroid Build Coastguard Worker   if (note_gnu_property && SanityCheck(note_gnu_property, name)) {
48*8d67ca89SAndroid Build Coastguard Worker     // Parse section.
49*8d67ca89SAndroid Build Coastguard Worker     Parse(note_gnu_property, name);
50*8d67ca89SAndroid Build Coastguard Worker   }
51*8d67ca89SAndroid Build Coastguard Worker }
52*8d67ca89SAndroid Build Coastguard Worker 
ElfW(NhdrGNUProperty)53*8d67ca89SAndroid Build Coastguard Worker const ElfW(NhdrGNUProperty)* GnuPropertySection::FindSegment(const ElfW(Phdr)* phdr,
54*8d67ca89SAndroid Build Coastguard Worker                                                              size_t phdr_count,
55*8d67ca89SAndroid Build Coastguard Worker                                                              const ElfW(Addr) load_bias,
56*8d67ca89SAndroid Build Coastguard Worker                                                              const char* name) const {
57*8d67ca89SAndroid Build Coastguard Worker   // According to Linux gABI extension this segment should contain
58*8d67ca89SAndroid Build Coastguard Worker   // .note.gnu.property section only.
59*8d67ca89SAndroid Build Coastguard Worker   if (phdr != nullptr) {
60*8d67ca89SAndroid Build Coastguard Worker     for (size_t i = 0; i < phdr_count; ++i) {
61*8d67ca89SAndroid Build Coastguard Worker       if (phdr[i].p_type != PT_GNU_PROPERTY) {
62*8d67ca89SAndroid Build Coastguard Worker         continue;
63*8d67ca89SAndroid Build Coastguard Worker       }
64*8d67ca89SAndroid Build Coastguard Worker 
65*8d67ca89SAndroid Build Coastguard Worker       LD_DEBUG(props, "\"%s\" PT_GNU_PROPERTY: found at segment index %zu", name, i);
66*8d67ca89SAndroid Build Coastguard Worker 
67*8d67ca89SAndroid Build Coastguard Worker       // Check segment size.
68*8d67ca89SAndroid Build Coastguard Worker       if (phdr[i].p_memsz < sizeof(ElfW(NhdrGNUProperty))) {
69*8d67ca89SAndroid Build Coastguard Worker         DL_ERR_AND_LOG(
70*8d67ca89SAndroid Build Coastguard Worker             "\"%s\" PT_GNU_PROPERTY segment is too small. Segment "
71*8d67ca89SAndroid Build Coastguard Worker             "size is %zu, minimum is %zu.",
72*8d67ca89SAndroid Build Coastguard Worker             name, static_cast<size_t>(phdr[i].p_memsz), sizeof(ElfW(NhdrGNUProperty)));
73*8d67ca89SAndroid Build Coastguard Worker         return nullptr;
74*8d67ca89SAndroid Build Coastguard Worker       }
75*8d67ca89SAndroid Build Coastguard Worker 
76*8d67ca89SAndroid Build Coastguard Worker       // PT_GNU_PROPERTY contains .note.gnu.property which has SHF_ALLOC
77*8d67ca89SAndroid Build Coastguard Worker       // attribute, therefore it is loaded.
78*8d67ca89SAndroid Build Coastguard Worker       auto note_nhdr = reinterpret_cast<ElfW(NhdrGNUProperty)*>(load_bias + phdr[i].p_vaddr);
79*8d67ca89SAndroid Build Coastguard Worker 
80*8d67ca89SAndroid Build Coastguard Worker       // Check that the n_descsz <= p_memsz
81*8d67ca89SAndroid Build Coastguard Worker       if ((phdr[i].p_memsz - sizeof(ElfW(NhdrGNUProperty))) < note_nhdr->nhdr.n_descsz) {
82*8d67ca89SAndroid Build Coastguard Worker         DL_ERR_AND_LOG(
83*8d67ca89SAndroid Build Coastguard Worker             "\"%s\" PT_GNU_PROPERTY segment p_memsz (%zu) is too small for note n_descsz (%zu).",
84*8d67ca89SAndroid Build Coastguard Worker             name, static_cast<size_t>(phdr[i].p_memsz),
85*8d67ca89SAndroid Build Coastguard Worker             static_cast<size_t>(note_nhdr->nhdr.n_descsz));
86*8d67ca89SAndroid Build Coastguard Worker         return nullptr;
87*8d67ca89SAndroid Build Coastguard Worker       }
88*8d67ca89SAndroid Build Coastguard Worker 
89*8d67ca89SAndroid Build Coastguard Worker       return note_nhdr;
90*8d67ca89SAndroid Build Coastguard Worker     }
91*8d67ca89SAndroid Build Coastguard Worker   }
92*8d67ca89SAndroid Build Coastguard Worker 
93*8d67ca89SAndroid Build Coastguard Worker   LD_DEBUG(props, "\"%s\" PT_GNU_PROPERTY: not found", name);
94*8d67ca89SAndroid Build Coastguard Worker   return nullptr;
95*8d67ca89SAndroid Build Coastguard Worker }
96*8d67ca89SAndroid Build Coastguard Worker 
SanityCheck(const ElfW (NhdrGNUProperty)* note_nhdr,const char * name) const97*8d67ca89SAndroid Build Coastguard Worker bool GnuPropertySection::SanityCheck(const ElfW(NhdrGNUProperty)* note_nhdr,
98*8d67ca89SAndroid Build Coastguard Worker                                      const char* name) const {
99*8d67ca89SAndroid Build Coastguard Worker   // Check .note section type
100*8d67ca89SAndroid Build Coastguard Worker   if (note_nhdr->nhdr.n_type != NT_GNU_PROPERTY_TYPE_0) {
101*8d67ca89SAndroid Build Coastguard Worker     DL_ERR_AND_LOG("\"%s\" .note.gnu.property: unexpected note type. Expected %u, got %u.", name,
102*8d67ca89SAndroid Build Coastguard Worker                    NT_GNU_PROPERTY_TYPE_0, note_nhdr->nhdr.n_type);
103*8d67ca89SAndroid Build Coastguard Worker     return false;
104*8d67ca89SAndroid Build Coastguard Worker   }
105*8d67ca89SAndroid Build Coastguard Worker 
106*8d67ca89SAndroid Build Coastguard Worker   if (note_nhdr->nhdr.n_namesz != 4) {
107*8d67ca89SAndroid Build Coastguard Worker     DL_ERR_AND_LOG("\"%s\" .note.gnu.property: unexpected name size. Expected 4, got %u.", name,
108*8d67ca89SAndroid Build Coastguard Worker                    note_nhdr->nhdr.n_namesz);
109*8d67ca89SAndroid Build Coastguard Worker     return false;
110*8d67ca89SAndroid Build Coastguard Worker   }
111*8d67ca89SAndroid Build Coastguard Worker 
112*8d67ca89SAndroid Build Coastguard Worker   if (strncmp(note_nhdr->n_name, "GNU", 4) != 0) {
113*8d67ca89SAndroid Build Coastguard Worker     DL_ERR_AND_LOG("\"%s\" .note.gnu.property: unexpected name. Expected 'GNU', got '%s'.", name,
114*8d67ca89SAndroid Build Coastguard Worker                    note_nhdr->n_name);
115*8d67ca89SAndroid Build Coastguard Worker     return false;
116*8d67ca89SAndroid Build Coastguard Worker   }
117*8d67ca89SAndroid Build Coastguard Worker 
118*8d67ca89SAndroid Build Coastguard Worker   return true;
119*8d67ca89SAndroid Build Coastguard Worker }
120*8d67ca89SAndroid Build Coastguard Worker 
Parse(const ElfW (NhdrGNUProperty)* note_nhdr,const char * name)121*8d67ca89SAndroid Build Coastguard Worker bool GnuPropertySection::Parse(const ElfW(NhdrGNUProperty)* note_nhdr, const char* name) {
122*8d67ca89SAndroid Build Coastguard Worker   // The total length of the program property array is in _bytes_.
123*8d67ca89SAndroid Build Coastguard Worker   ElfW(Word) offset = 0;
124*8d67ca89SAndroid Build Coastguard Worker   while (offset < note_nhdr->nhdr.n_descsz) {
125*8d67ca89SAndroid Build Coastguard Worker     LD_DEBUG(props, "\"%s\" .note.gnu.property: processing at offset 0x%x", name, offset);
126*8d67ca89SAndroid Build Coastguard Worker 
127*8d67ca89SAndroid Build Coastguard Worker     // At least the "header" part must fit.
128*8d67ca89SAndroid Build Coastguard Worker     // The ABI doesn't say that pr_datasz can't be 0.
129*8d67ca89SAndroid Build Coastguard Worker     if ((note_nhdr->nhdr.n_descsz - offset) < sizeof(ElfW(Prop))) {
130*8d67ca89SAndroid Build Coastguard Worker       DL_ERR_AND_LOG(
131*8d67ca89SAndroid Build Coastguard Worker           "\"%s\" .note.gnu.property: no more space left for a "
132*8d67ca89SAndroid Build Coastguard Worker           "Program Property Note header.",
133*8d67ca89SAndroid Build Coastguard Worker           name);
134*8d67ca89SAndroid Build Coastguard Worker       return false;
135*8d67ca89SAndroid Build Coastguard Worker     }
136*8d67ca89SAndroid Build Coastguard Worker 
137*8d67ca89SAndroid Build Coastguard Worker     // Loop on program property array.
138*8d67ca89SAndroid Build Coastguard Worker     const ElfW(Prop)* property = reinterpret_cast<const ElfW(Prop)*>(&note_nhdr->n_desc[offset]);
139*8d67ca89SAndroid Build Coastguard Worker     const ElfW(Word) property_size =
140*8d67ca89SAndroid Build Coastguard Worker         align_up(sizeof(ElfW(Prop)) + property->pr_datasz, sizeof(ElfW(Addr)));
141*8d67ca89SAndroid Build Coastguard Worker     if ((note_nhdr->nhdr.n_descsz - offset) < property_size) {
142*8d67ca89SAndroid Build Coastguard Worker       DL_ERR_AND_LOG(
143*8d67ca89SAndroid Build Coastguard Worker           "\"%s\" .note.gnu.property: property descriptor size is "
144*8d67ca89SAndroid Build Coastguard Worker           "invalid. Expected at least %u bytes, got %u.",
145*8d67ca89SAndroid Build Coastguard Worker           name, property_size, note_nhdr->nhdr.n_descsz - offset);
146*8d67ca89SAndroid Build Coastguard Worker       return false;
147*8d67ca89SAndroid Build Coastguard Worker     }
148*8d67ca89SAndroid Build Coastguard Worker 
149*8d67ca89SAndroid Build Coastguard Worker     // Cache found properties.
150*8d67ca89SAndroid Build Coastguard Worker     switch (property->pr_type) {
151*8d67ca89SAndroid Build Coastguard Worker #if defined(__aarch64__)
152*8d67ca89SAndroid Build Coastguard Worker       case GNU_PROPERTY_AARCH64_FEATURE_1_AND: {
153*8d67ca89SAndroid Build Coastguard Worker         if (property->pr_datasz != 4) {
154*8d67ca89SAndroid Build Coastguard Worker           DL_ERR_AND_LOG(
155*8d67ca89SAndroid Build Coastguard Worker               "\"%s\" .note.gnu.property: property descriptor size is "
156*8d67ca89SAndroid Build Coastguard Worker               "invalid. Expected %u bytes for GNU_PROPERTY_AARCH64_FEATURE_1_AND, got %u.",
157*8d67ca89SAndroid Build Coastguard Worker               name, 4, property->pr_datasz);
158*8d67ca89SAndroid Build Coastguard Worker           return false;
159*8d67ca89SAndroid Build Coastguard Worker         }
160*8d67ca89SAndroid Build Coastguard Worker 
161*8d67ca89SAndroid Build Coastguard Worker         const ElfW(Word) flags = *reinterpret_cast<const ElfW(Word)*>(&property->pr_data[0]);
162*8d67ca89SAndroid Build Coastguard Worker         properties_.bti_compatible = (flags & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) != 0;
163*8d67ca89SAndroid Build Coastguard Worker         if (properties_.bti_compatible) {
164*8d67ca89SAndroid Build Coastguard Worker           LD_DEBUG(props, "[ BTI compatible: \"%s\" ]", name);
165*8d67ca89SAndroid Build Coastguard Worker         }
166*8d67ca89SAndroid Build Coastguard Worker         break;
167*8d67ca89SAndroid Build Coastguard Worker       }
168*8d67ca89SAndroid Build Coastguard Worker #endif
169*8d67ca89SAndroid Build Coastguard Worker       default:
170*8d67ca89SAndroid Build Coastguard Worker         LD_DEBUG(props, "\"%s\" .note.gnu.property: found property pr_type %u pr_datasz 0x%x",
171*8d67ca89SAndroid Build Coastguard Worker                  name, property->pr_type, property->pr_datasz);
172*8d67ca89SAndroid Build Coastguard Worker         break;
173*8d67ca89SAndroid Build Coastguard Worker     }
174*8d67ca89SAndroid Build Coastguard Worker 
175*8d67ca89SAndroid Build Coastguard Worker     // Move offset, this should be safe to add because of previous checks.
176*8d67ca89SAndroid Build Coastguard Worker     offset += property_size;
177*8d67ca89SAndroid Build Coastguard Worker   }
178*8d67ca89SAndroid Build Coastguard Worker 
179*8d67ca89SAndroid Build Coastguard Worker   return true;
180*8d67ca89SAndroid Build Coastguard Worker }
181*8d67ca89SAndroid Build Coastguard Worker 
182*8d67ca89SAndroid Build Coastguard Worker #if defined(__aarch64__)
IsBTICompatible() const183*8d67ca89SAndroid Build Coastguard Worker bool GnuPropertySection::IsBTICompatible() const {
184*8d67ca89SAndroid Build Coastguard Worker   return (g_platform_properties.bti_supported && properties_.bti_compatible);
185*8d67ca89SAndroid Build Coastguard Worker }
186*8d67ca89SAndroid Build Coastguard Worker #endif
187