1/* Support for GNU properties. x86 version.
2 Copyright (C) 2018 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
18
19#ifndef _DL_PROP_H
20#define _DL_PROP_H
21
22#include <not-cancel.h>
23
24extern void _dl_cet_check (struct link_map *, const char *)
25 attribute_hidden;
26extern void _dl_cet_open_check (struct link_map *)
27 attribute_hidden;
28
29static inline void __attribute__ ((always_inline))
30_rtld_main_check (struct link_map *m, const char *program)
31{
32#if CET_ENABLED
33 _dl_cet_check (m, program);
34#endif
35}
36
37static inline void __attribute__ ((always_inline))
38_dl_open_check (struct link_map *m)
39{
40#if CET_ENABLED
41 _dl_cet_open_check (m);
42#endif
43}
44
45static inline void __attribute__ ((unused))
46_dl_process_cet_property_note (struct link_map *l,
47 const ElfW(Nhdr) *note,
48 const ElfW(Addr) size,
49 const ElfW(Addr) align)
50{
51#if CET_ENABLED
52 /* The NT_GNU_PROPERTY_TYPE_0 note must be aliged to 4 bytes in
53 32-bit objects and to 8 bytes in 64-bit objects. Skip notes
54 with incorrect alignment. */
55 if (align != (__ELF_NATIVE_CLASS / 8))
56 return;
57
58 const ElfW(Addr) start = (ElfW(Addr)) note;
59
60 while ((ElfW(Addr)) (note + 1) - start < size)
61 {
62 /* Find the NT_GNU_PROPERTY_TYPE_0 note. */
63 if (note->n_namesz == 4
64 && note->n_type == NT_GNU_PROPERTY_TYPE_0
65 && memcmp (note + 1, "GNU", 4) == 0)
66 {
67 /* Check for invalid property. */
68 if (note->n_descsz < 8
69 || (note->n_descsz % sizeof (ElfW(Addr))) != 0)
70 break;
71
72 /* Start and end of property array. */
73 unsigned char *ptr = (unsigned char *) (note + 1) + 4;
74 unsigned char *ptr_end = ptr + note->n_descsz;
75
76 do
77 {
78 unsigned int type = *(unsigned int *) ptr;
79 unsigned int datasz = *(unsigned int *) (ptr + 4);
80
81 ptr += 8;
82 if ((ptr + datasz) > ptr_end)
83 break;
84
85 if (type == GNU_PROPERTY_X86_FEATURE_1_AND)
86 {
87 /* The size of GNU_PROPERTY_X86_FEATURE_1_AND is 4
88 bytes. When seeing GNU_PROPERTY_X86_FEATURE_1_AND,
89 we stop the search regardless if its size is correct
90 or not. There is no point to continue if this note
91 is ill-formed. */
92 if (datasz == 4)
93 {
94 unsigned int feature_1 = *(unsigned int *) ptr;
95 if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_IBT))
96 l->l_cet |= lc_ibt;
97 if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_SHSTK))
98 l->l_cet |= lc_shstk;
99 }
100 return;
101 }
102
103 /* Check the next property item. */
104 ptr += ALIGN_UP (datasz, sizeof (ElfW(Addr)));
105 }
106 while ((ptr_end - ptr) >= 8);
107 }
108
109 /* NB: Note sections like .note.ABI-tag and .note.gnu.build-id are
110 aligned to 4 bytes in 64-bit ELF objects. */
111 note = ((const void *) note
112 + ELF_NOTE_NEXT_OFFSET (note->n_namesz, note->n_descsz,
113 align));
114 }
115#endif
116}
117
118#ifdef FILEBUF_SIZE
119static inline int __attribute__ ((unused))
120_dl_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph,
121 int fd, struct filebuf *fbp)
122{
123# if CET_ENABLED
124 const ElfW(Nhdr) *note;
125 ElfW(Nhdr) *note_malloced = NULL;
126 ElfW(Addr) size = ph->p_filesz;
127
128 if (ph->p_offset + size <= (size_t) fbp->len)
129 note = (const void *) (fbp->buf + ph->p_offset);
130 else
131 {
132 if (size < __MAX_ALLOCA_CUTOFF)
133 note = alloca (size);
134 else
135 {
136 note_malloced = malloc (size);
137 note = note_malloced;
138 }
139 __lseek (fd, ph->p_offset, SEEK_SET);
140 if (__read_nocancel (fd, (void *) note, size) != size)
141 {
142 if (note_malloced)
143 free (note_malloced);
144 return -1;
145 }
146 }
147
148 _dl_process_cet_property_note (l, note, size, ph->p_align);
149 if (note_malloced)
150 free (note_malloced);
151# endif
152 return 0;
153}
154#endif
155
156static inline int __attribute__ ((unused))
157_rtld_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph)
158{
159 const ElfW(Nhdr) *note = (const void *) (ph->p_vaddr + l->l_addr);
160 _dl_process_cet_property_note (l, note, ph->p_memsz, ph->p_align);
161 return 0;
162}
163
164#endif /* _DL_PROP_H */
165