1 /* Conversion functions for versioning information.
2 Copyright (C) 1998, 1999, 2000, 2002, 2003, 2015 Red Hat, Inc.
3 Copyright (C) 2022 Mark J. Wielaard <mark@klomp.org>
4 This file is part of elfutils.
5 Written by Ulrich Drepper <drepper@redhat.com>, 1998.
6
7 This file is free software; you can redistribute it and/or modify
8 it under the terms of either
9
10 * the GNU Lesser General Public License as published by the Free
11 Software Foundation; either version 3 of the License, or (at
12 your option) any later version
13
14 or
15
16 * the GNU General Public License as published by the Free
17 Software Foundation; either version 2 of the License, or (at
18 your option) any later version
19
20 or both in parallel, as here.
21
22 elfutils is distributed in the hope that it will be useful, but
23 WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 General Public License for more details.
26
27 You should have received copies of the GNU General Public License and
28 the GNU Lesser General Public License along with this program. If
29 not, see <http://www.gnu.org/licenses/>. */
30
31 #include <assert.h>
32 #include <gelf.h>
33
34 #include "libelfP.h"
35
36
37 static void
elf_cvt_Verdef(void * dest,const void * src,size_t len,int encode)38 elf_cvt_Verdef (void *dest, const void *src, size_t len, int encode)
39 {
40 /* We have two different record types: ElfXX_Verndef and ElfXX_Verdaux.
41 To recognize them we have to walk the data structure and convert
42 them one after the other. The ENCODE parameter specifies whether
43 we are encoding or decoding. When we are encoding we can immediately
44 use the data in the buffer; if not, we have to decode the data before
45 using it. */
46 size_t def_offset = 0;
47 GElf_Verdef *ddest;
48 GElf_Verdef *dsrc;
49
50 /* We rely on the types being all the same size. */
51 assert (sizeof (GElf_Verdef) == sizeof (Elf32_Verdef));
52 assert (sizeof (GElf_Verdaux) == sizeof (Elf32_Verdaux));
53 assert (sizeof (GElf_Verdef) == sizeof (Elf64_Verdef));
54 assert (sizeof (GElf_Verdaux) == sizeof (Elf64_Verdaux));
55
56 if (len == 0)
57 return;
58
59 /* Below we rely on the next field offsets to be correct, start by
60 copying over all data as is in case some data isn't translated.
61 We don't want to leave (undefined) garbage in the dest buffer. */
62 memmove (dest, src, len);
63
64 do
65 {
66 size_t aux_offset;
67 GElf_Verdaux *asrc;
68
69 /* Test for correct offset. */
70 if (def_offset > len
71 || len - def_offset < sizeof (GElf_Verdef)
72 || (def_offset & (__alignof__ (GElf_Verdef) - 1)) != 0)
73 return;
74
75 /* Work the tree from the first record. */
76 ddest = (GElf_Verdef *) ((char *) dest + def_offset);
77 dsrc = (GElf_Verdef *) ((char *) src + def_offset);
78
79 /* Decode first if necessary. */
80 if (! encode)
81 {
82 ddest->vd_version = bswap_16 (dsrc->vd_version);
83 ddest->vd_flags = bswap_16 (dsrc->vd_flags);
84 ddest->vd_ndx = bswap_16 (dsrc->vd_ndx);
85 ddest->vd_cnt = bswap_16 (dsrc->vd_cnt);
86 ddest->vd_hash = bswap_32 (dsrc->vd_hash);
87 ddest->vd_aux = bswap_32 (dsrc->vd_aux);
88 ddest->vd_next = bswap_32 (dsrc->vd_next);
89
90 if (ddest->vd_aux > len - def_offset)
91 return;
92 aux_offset = def_offset + ddest->vd_aux;
93 }
94 else
95 {
96 if (dsrc->vd_aux > len - def_offset)
97 return;
98 aux_offset = def_offset + dsrc->vd_aux;
99 }
100
101 /* Handle all the auxiliary records belonging to this definition. */
102 do
103 {
104 GElf_Verdaux *adest;
105
106 /* Test for correct offset. */
107 if (aux_offset > len
108 || len - aux_offset < sizeof (GElf_Verdaux)
109 || (aux_offset & (__alignof__ (GElf_Verdaux) - 1)) != 0)
110 return;
111
112 adest = (GElf_Verdaux *) ((char *) dest + aux_offset);
113 asrc = (GElf_Verdaux *) ((char *) src + aux_offset);
114
115 if (encode)
116 {
117 if (asrc->vda_next > len - aux_offset)
118 return;
119 aux_offset += asrc->vda_next;
120 }
121
122 adest->vda_name = bswap_32 (asrc->vda_name);
123 adest->vda_next = bswap_32 (asrc->vda_next);
124
125 if (! encode)
126 {
127 if (adest->vda_next > len - aux_offset)
128 return;
129 aux_offset += adest->vda_next;
130 }
131 }
132 while (asrc->vda_next != 0);
133
134 /* Encode now if necessary. */
135 if (encode)
136 {
137 if (dsrc->vd_next > len - def_offset)
138 return;
139 def_offset += dsrc->vd_next;
140
141 ddest->vd_version = bswap_16 (dsrc->vd_version);
142 ddest->vd_flags = bswap_16 (dsrc->vd_flags);
143 ddest->vd_ndx = bswap_16 (dsrc->vd_ndx);
144 ddest->vd_cnt = bswap_16 (dsrc->vd_cnt);
145 ddest->vd_hash = bswap_32 (dsrc->vd_hash);
146 ddest->vd_aux = bswap_32 (dsrc->vd_aux);
147 ddest->vd_next = bswap_32 (dsrc->vd_next);
148 }
149 else
150 {
151 if (ddest->vd_next > len - def_offset)
152 return;
153 def_offset += ddest->vd_next;
154 }
155 }
156 while (dsrc->vd_next != 0);
157 }
158
159
160 static void
elf_cvt_Verneed(void * dest,const void * src,size_t len,int encode)161 elf_cvt_Verneed (void *dest, const void *src, size_t len, int encode)
162 {
163 /* We have two different record types: ElfXX_Verndef and ElfXX_Verdaux.
164 To recognize them we have to walk the data structure and convert
165 them one after the other. The ENCODE parameter specifies whether
166 we are encoding or decoding. When we are encoding we can immediately
167 use the data in the buffer; if not, we have to decode the data before
168 using it. */
169 size_t need_offset = 0;
170 GElf_Verneed *ndest;
171 GElf_Verneed *nsrc;
172
173 /* We rely on the types being all the same size. */
174 assert (sizeof (GElf_Verneed) == sizeof (Elf32_Verneed));
175 assert (sizeof (GElf_Vernaux) == sizeof (Elf32_Vernaux));
176 assert (sizeof (GElf_Verneed) == sizeof (Elf64_Verneed));
177 assert (sizeof (GElf_Vernaux) == sizeof (Elf64_Vernaux));
178
179 if (len == 0)
180 return;
181
182 /* Below we rely on the next field offsets to be correct, start by
183 copying over all data as is in case some data isn't translated.
184 We don't want to leave (undefined) garbage in the dest buffer. */
185 memmove (dest, src, len);
186
187 do
188 {
189 size_t aux_offset;
190 GElf_Vernaux *asrc;
191
192 /* Test for correct offset. */
193 if (need_offset > len
194 || len - need_offset < sizeof (GElf_Verneed)
195 || (need_offset & (__alignof__ (GElf_Verneed) - 1)) != 0)
196 return;
197
198 /* Work the tree from the first record. */
199 ndest = (GElf_Verneed *) ((char *) dest + need_offset);
200 nsrc = (GElf_Verneed *) ((char *) src + need_offset);
201
202 /* Decode first if necessary. */
203 if (! encode)
204 {
205 ndest->vn_version = bswap_16 (nsrc->vn_version);
206 ndest->vn_cnt = bswap_16 (nsrc->vn_cnt);
207 ndest->vn_file = bswap_32 (nsrc->vn_file);
208 ndest->vn_aux = bswap_32 (nsrc->vn_aux);
209 ndest->vn_next = bswap_32 (nsrc->vn_next);
210
211 if (ndest->vn_aux > len - need_offset)
212 return;
213 aux_offset = need_offset + ndest->vn_aux;
214 }
215 else
216 {
217 if (nsrc->vn_aux > len - need_offset)
218 return;
219 aux_offset = need_offset + nsrc->vn_aux;
220 }
221
222 /* Handle all the auxiliary records belonging to this requirement. */
223 do
224 {
225 GElf_Vernaux *adest;
226
227 /* Test for correct offset. */
228 if (aux_offset > len
229 || len - aux_offset < sizeof (GElf_Vernaux)
230 || (aux_offset & (__alignof__ (GElf_Vernaux) - 1)) != 0)
231 return;
232
233 adest = (GElf_Vernaux *) ((char *) dest + aux_offset);
234 asrc = (GElf_Vernaux *) ((char *) src + aux_offset);
235
236 if (encode)
237 {
238 if (asrc->vna_next > len - aux_offset)
239 return;
240 aux_offset += asrc->vna_next;
241 }
242
243 adest->vna_hash = bswap_32 (asrc->vna_hash);
244 adest->vna_flags = bswap_16 (asrc->vna_flags);
245 adest->vna_other = bswap_16 (asrc->vna_other);
246 adest->vna_name = bswap_32 (asrc->vna_name);
247 adest->vna_next = bswap_32 (asrc->vna_next);
248
249 if (! encode)
250 {
251 if (adest->vna_next > len - aux_offset)
252 return;
253 aux_offset += adest->vna_next;
254 }
255 }
256 while (asrc->vna_next != 0);
257
258 /* Encode now if necessary. */
259 if (encode)
260 {
261 if (nsrc->vn_next > len - need_offset)
262 return;
263 need_offset += nsrc->vn_next;
264
265 ndest->vn_version = bswap_16 (nsrc->vn_version);
266 ndest->vn_cnt = bswap_16 (nsrc->vn_cnt);
267 ndest->vn_file = bswap_32 (nsrc->vn_file);
268 ndest->vn_aux = bswap_32 (nsrc->vn_aux);
269 ndest->vn_next = bswap_32 (nsrc->vn_next);
270 }
271 else
272 {
273 if (ndest->vn_next > len - need_offset)
274 return;
275 need_offset += ndest->vn_next;
276 }
277 }
278 while (nsrc->vn_next != 0);
279 }
280