FD.io VPP  v20.09-64-g4f7b92f0a
Vector Packet Processing
elftool.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16  Copyright (c) 2008 Eliot Dresselhaus
17 
18  Permission is hereby granted, free of charge, to any person obtaining
19  a copy of this software and associated documentation files (the
20  "Software"), to deal in the Software without restriction, including
21  without limitation the rights to use, copy, modify, merge, publish,
22  distribute, sublicense, and/or sell copies of the Software, and to
23  permit persons to whom the Software is furnished to do so, subject to
24  the following conditions:
25 
26  The above copyright notice and this permission notice shall be
27  included in all copies or substantial portions of the Software.
28 
29  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 */
37 
38 #include <vppinfra/elf.h>
39 
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <fcntl.h>
43 
44 #ifndef CLIB_UNIX
45 #error "unix only"
46 #endif
47 
48 typedef struct {
50  char * input_file;
51  char * output_file;
53  char * set_rpath;
55  int verbose;
56  int quiet;
58  /* for use in the optimized / simplified case */
63 
65  elf_tool_main_t * tm)
66 {
67  elf_segment_t * g;
68  elf_section_t * s;
69  clib_error_t * error;
70  char * interp = tm->set_interpreter;
71 
72  switch (em->first_header.file_type)
73  {
74  case ELF_EXEC:
75  break;
76 
77  case ELF_SHARED:
78  if (tm->allow_elf_shared)
79  break;
80  /* Note flowthrough */
81  default:
82  return clib_error_return (0, "unacceptable file_type");
83  }
84 
85  vec_foreach (g, em->segments)
86  {
87  if (g->header.type == ELF_SEGMENT_INTERP)
88  break;
89  }
90 
91  if (g >= vec_end (em->segments))
92  return clib_error_return (0, "interpreter not found");
93 
94  if (g->header.memory_size < 1 + strlen (interp))
95  return clib_error_return (0, "given interpreter does not fit; must be less than %d bytes (`%s' given)",
96  g->header.memory_size, interp);
97 
98  error = elf_get_section_by_start_address (em, g->header.virtual_address, &s);
99  if (error)
100  return error;
101 
102  /* Put in new null terminated string. */
103  clib_memset (s->contents, 0, vec_len (s->contents));
104  clib_memcpy (s->contents, interp, strlen (interp));
105 
106  return 0;
107 }
108 
109 static void
111 {
113  elf64_dynamic_entry_t * new_es = 0;
114 
116  {
117  switch (e->type)
118  {
119  case ELF_DYNAMIC_ENTRY_RPATH:
120  case ELF_DYNAMIC_ENTRY_RUN_PATH:
121  break;
122 
123  default:
124  vec_add1 (new_es, e[0]);
125  break;
126  }
127  }
128 
129  /* Pad so as to keep section size constant. */
130  {
131  elf64_dynamic_entry_t e_end;
132  e_end.type = ELF_DYNAMIC_ENTRY_END;
133  e_end.data = 0;
134  while (vec_len (new_es) < vec_len (em->dynamic_entries))
135  vec_add1 (new_es, e_end);
136  }
137 
139  em->dynamic_entries = new_es;
140 
142 }
143 
144 static void delete_rpath (elf_main_t * em)
145 {
146  elf_section_t * s;
147 
148  vec_foreach (s, em->sections)
149  {
150  switch (s->header.type)
151  {
152  case ELF_SECTION_DYNAMIC:
153  delete_rpath_for_section (em, s);
154  break;
155 
156  default:
157  break;
158  }
159  }
160 }
161 
162 static clib_error_t *
163 set_rpath_for_section (elf_main_t * em, elf_section_t * s, char * new_rpath)
164 {
166  char * old_rpath;
167  int old_len, new_len = strlen (new_rpath);
168  u8 * new_string_table = vec_dup (em->dynamic_string_table);
169 
171  {
172  switch (e->type)
173  {
174  case ELF_DYNAMIC_ENTRY_RPATH:
175  case ELF_DYNAMIC_ENTRY_RUN_PATH:
176  old_rpath = (char *) new_string_table + e->data;
177  old_len = strlen (old_rpath);
178  if (old_len < new_len)
179  return clib_error_return (0, "rpath of `%s' does not fit (old rpath `%s')",
180  new_rpath, old_rpath);
181  strcpy (old_rpath, new_rpath); //NOSONAR
182  break;
183 
184  default:
185  break;
186  }
187  }
188 
190  new_string_table,
191  vec_bytes (new_string_table));
192 
193  return 0;
194 }
195 
196 static clib_error_t *
197 set_rpath (elf_main_t * em, char * rpath)
198 {
199  clib_error_t * error = 0;
200  elf_section_t * s;
201 
202  vec_foreach (s, em->sections)
203  {
204  switch (s->header.type)
205  {
206  case ELF_SECTION_DYNAMIC:
207  error = set_rpath_for_section (em, s, rpath);
208  if (error)
209  return error;
210  break;
211 
212  default:
213  break;
214  }
215  }
216 
217  return error;
218 }
219 
220 static clib_error_t *
222 {
223  int ifd = -1, ofd = -1;
224  struct stat fd_stat;
225  u8 *idp = 0; /* warning be gone */
226  u64 mmap_length = 0, i;
227  u32 run_length;
228  u8 in_run;
229  u64 offset0 = 0, offset1 = 0;
230  clib_error_t * error = 0;
231  int fix_in_place = 0;
232 
233  if (!strcmp (tm->input_file, tm->output_file))
234  fix_in_place = 1;
235 
236  ifd = open (tm->input_file, O_RDWR);
237  if (ifd < 0)
238  {
239  error = clib_error_return_unix (0, "open `%s'", tm->input_file);
240  goto done;
241  }
242 
243  if (fstat (ifd, &fd_stat) < 0)
244  {
245  error = clib_error_return_unix (0, "fstat `%s'", tm->input_file);
246  goto done;
247  }
248 
249  if (!(fd_stat.st_mode & S_IFREG))
250  {
251  error = clib_error_return (0, "%s is not a regular file", tm->input_file);
252  goto done;
253  }
254 
255  mmap_length = fd_stat.st_size;
256  if (mmap_length < 4)
257  {
258  error = clib_error_return (0, "%s too short", tm->input_file);
259  goto done;
260  }
261 
262  /* COW-mapping, since we intend to write the fixups */
263  if (fix_in_place)
264  idp = mmap (0, mmap_length, PROT_READ | PROT_WRITE, MAP_SHARED,
265  ifd, /* offset */ 0);
266  else
267  idp = mmap (0, mmap_length, PROT_READ | PROT_WRITE, MAP_PRIVATE,
268  ifd, /* offset */ 0);
269  if (~pointer_to_uword (idp) == 0)
270  {
271  mmap_length = 0;
272  error = clib_error_return_unix (0, "mmap `%s'", tm->input_file);
273  goto done;
274  }
275 
276  if (idp[0] != 0x7f || idp[1] != 'E' || idp[2] != 'L' || idp[3] != 'F')
277  {
278  error = clib_error_return (0, "not an ELF file '%s'", tm->input_file);
279  goto done;
280  }
281 
282  in_run = 0;
283  run_length = 0;
284 
285  for (i = 0; i < mmap_length; i++)
286  {
287  if (idp[i] == '/')
288  {
289  if (in_run)
290  run_length++;
291  else
292  {
293  in_run = 1;
294  run_length = 1;
295  }
296  }
297  else
298  {
299  if (in_run && run_length >= 16)
300  {
301  if (offset0 == 0)
302  offset0 = (i - run_length);
303  else if (offset1 == 0)
304  {
305  offset1 = (i - run_length);
306  goto found_both;
307  }
308  }
309  in_run = 0;
310  run_length = 0;
311  }
312  }
313 
314  if (offset0 == 0)
315  {
316  error = clib_error_return (0, "no fixup markers in %s",
317  tm->input_file);
318  goto done;
319  }
320 
321  found_both:
322  if (0)
323  clib_warning ("offset0 %lld (0x%llx), offset1 %lld (0x%llx)",
324  offset0, offset0, offset1, offset1);
325 
326  /* Executable file case */
327  if (offset0 && offset1)
328  {
329  tm->interpreter_offset = offset0;
330  tm->rpath_offset = offset1;
331  }
332  else /* shared library case */
333  {
334  tm->interpreter_offset = 0;
335  tm->rpath_offset = offset0;
336  }
337 
338  if (tm->interpreter_offset)
340  strlen (tm->set_interpreter)+1);
341 
342  if (tm->rpath_offset)
343  clib_memcpy (&idp[tm->rpath_offset], tm->set_rpath,
344  strlen (tm->set_rpath)+1);
345 
346  /* Write the output file... */
347  if (fix_in_place == 0)
348  {
349  ofd = open (tm->output_file, O_RDWR | O_CREAT | O_TRUNC, 0644);
350  if (ofd < 0)
351  {
352  error = clib_error_return_unix (0, "create `%s'", tm->output_file);
353  goto done;
354  }
355 
356  if (write (ofd, idp, mmap_length) != mmap_length)
357  error = clib_error_return_unix (0, "write `%s'", tm->output_file);
358  }
359 
360  done:
361  if (mmap_length > 0 && idp)
362  munmap (idp, mmap_length);
363  if (ifd >= 0)
364  close (ifd);
365  if (ofd >= 0)
366  close (ofd);
367  return error;
368 }
369 
370 
371 int main (int argc, char * argv[])
372 {
373  elf_tool_main_t _tm, * tm = &_tm;
374  elf_main_t * em = &tm->elf_main;
376  clib_error_t * error = 0;
377 
378  clib_memset (tm, 0, sizeof (tm[0]));
379  unformat_init_command_line (&i, argv);
380 
382  {
383  if (unformat (&i, "in %s", &tm->input_file))
384  ;
385  else if (unformat (&i, "out %s", &tm->output_file))
386  ;
387  else if (unformat (&i, "set-interpreter %s", &tm->set_interpreter))
388  ;
389  else if (unformat (&i, "set-rpath %s", &tm->set_rpath))
390  ;
391  else if (unformat (&i, "unset-rpath"))
392  tm->unset_rpath = 1;
393  else if (unformat (&i, "verbose"))
394  tm->verbose = ~0;
395  else if (unformat (&i, "verbose-symbols"))
397  else if (unformat (&i, "verbose-relocations"))
399  else if (unformat (&i, "verbose-dynamic"))
401  else if (unformat (&i, "quiet"))
402  tm->quiet = 1;
403  else if (unformat (&i, "allow-elf-shared"))
404  tm->allow_elf_shared = 1;
405  else
406  {
407  error = unformat_parse_error (&i);
408  goto done;
409  }
410  }
411 
412  if (! tm->input_file)
413  {
414  error = clib_error_return (0, "no input file");
415  goto done;
416  }
417 
418  /* Do the typical case a stone-simple way... */
419  if (tm->quiet && tm->set_interpreter && tm->set_rpath && tm->output_file)
420  {
421  error = set_interpreter_rpath (tm);
422  goto done;
423  }
424 
425  error = elf_read_file (em, tm->input_file);
426 
427  if (error)
428  goto done;
429 
430  if (tm->verbose)
431  fformat (stdout, "%U", format_elf_main, em, tm->verbose);
432 
433  if (tm->set_interpreter)
434  {
435  error = elf_set_interpreter (em, tm);
436  if (error)
437  goto done;
438  }
439 
440  if (tm->set_rpath)
441  {
442  error = set_rpath (em, tm->set_rpath);
443  if (error)
444  goto done;
445  }
446 
447  if (tm->unset_rpath)
448  delete_rpath (em);
449 
450  if (tm->output_file)
451  error = elf_write_file (em, tm->output_file);
452 
453  elf_main_free (em);
454 
455  done:
456  if (error)
457  {
458  if (tm->quiet == 0)
459  clib_error_report (error);
460  return 1;
461  }
462  else
463  return 0;
464 }
static void elf_main_free(elf_main_t *em)
Definition: elf.h:926
int allow_elf_shared
Definition: elftool.c:57
elf64_segment_header_t header
Definition: elf.h:873
static clib_error_t * set_interpreter_rpath(elf_tool_main_t *tm)
Definition: elftool.c:221
static clib_error_t * set_rpath(elf_main_t *em, char *rpath)
Definition: elftool.c:197
static void delete_rpath_for_section(elf_main_t *em, elf_section_t *s)
Definition: elftool.c:110
unsigned long u64
Definition: types.h:89
void elf_set_dynamic_entries(elf_main_t *em)
Definition: elf.c:899
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
u64 rpath_offset
Definition: elftool.c:61
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:592
static void delete_rpath(elf_main_t *em)
Definition: elftool.c:144
#define vec_bytes(v)
Number of data bytes in vector.
unsigned char u8
Definition: types.h:56
#define FORMAT_ELF_MAIN_RELOCATIONS
Definition: elf.h:1027
#define clib_memcpy(d, s, n)
Definition: string.h:180
u8 * contents
Definition: elf.h:868
#define clib_error_return(e, args...)
Definition: error.h:99
unsigned int u32
Definition: types.h:88
#define vec_end(v)
End (last data address) of vector.
u64 interpreter_offset
Definition: elftool.c:60
elf_segment_t * segments
Definition: elf.h:895
elf_main_t elf_main
Definition: elftool.c:49
clib_error_t * elf_write_file(elf_main_t *em, char *file_name)
Definition: elf.c:1754
u8 * dynamic_string_table
Definition: elf.h:908
struct _unformat_input_t unformat_input_t
#define clib_error_return_unix(e, args...)
Definition: error.h:102
void unformat_init_command_line(unformat_input_t *input, char *argv[])
Definition: unformat.c:1013
#define vec_dup(V)
Return copy of vector (no header, no alignment)
Definition: vec.h:429
static clib_error_t * set_rpath_for_section(elf_main_t *em, elf_section_t *s, char *new_rpath)
Definition: elftool.c:163
word fformat(FILE *f, char *fmt,...)
Definition: format.c:462
static void elf_set_section_contents(elf_main_t *em, uword section_index, void *new_contents, uword n_content_bytes)
Definition: elf.h:982
elf_first_header_t first_header
Definition: elf.h:891
#define UNFORMAT_END_OF_INPUT
Definition: format.h:145
Definition: elf.h:567
char * output_file
Definition: elftool.c:51
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:317
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:380
#define clib_warning(format, args...)
Definition: error.h:59
clib_error_t * elf_read_file(elf_main_t *em, char *file_name)
Definition: elf.c:1329
char * input_file
Definition: elftool.c:50
char * set_interpreter
Definition: elftool.c:52
static clib_error_t * elf_set_interpreter(elf_main_t *em, elf_tool_main_t *tm)
Definition: elftool.c:64
elf64_dynamic_entry_t * dynamic_entries
Definition: elf.h:907
#define clib_error_report(e)
Definition: error.h:113
elf_section_t * sections
Definition: elf.h:897
static uword pointer_to_uword(const void *p)
Definition: types.h:131
#define FORMAT_ELF_MAIN_SYMBOLS
Definition: elf.h:1026
#define unformat_parse_error(input)
Definition: format.h:269
#define FORMAT_ELF_MAIN_DYNAMIC
Definition: elf.h:1028
format_function_t format_elf_main
Definition: elf.h:1030
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
char * set_rpath
Definition: elftool.c:53
elf64_section_header_t header
Definition: elf.h:855
#define vec_foreach(var, vec)
Vector iterator.
int main(int argc, char *argv[])
Definition: elftool.c:371
elf_file_type_t file_type
Definition: elf.h:210
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
clib_error_t * elf_get_section_by_start_address(elf_main_t *em, uword start_address, elf_section_t **result)
Definition: elf.c:69
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:171
int unset_rpath
Definition: elftool.c:54
u32 dynamic_string_table_section_index
Definition: elf.h:909