FD.io VPP  v21.10.1-2-g0a485f517
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;
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  {
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  {
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)
460  return 1;
461  }
462  else
463  return 0;
464 }
elf_tool_main_t::quiet
int quiet
Definition: elftool.c:56
format_elf_main
format_function_t format_elf_main
Definition: elf.h:1029
clib_memcpy
#define clib_memcpy(d, s, n)
Definition: string.h:197
elf_section_t::contents
u8 * contents
Definition: elf.h:867
set_rpath
static clib_error_t * set_rpath(elf_main_t *em, char *rpath)
Definition: elftool.c:197
elf_first_header_t::file_type
elf_file_type_t file_type
Definition: elf.h:210
pointer_to_uword
static uword pointer_to_uword(const void *p)
Definition: types.h:131
elf_main_free
static void elf_main_free(elf_main_t *em)
Definition: elf.h:925
delete_rpath
static void delete_rpath(elf_main_t *em)
Definition: elftool.c:144
vec_end
#define vec_end(v)
End (last data address) of vector.
Definition: vec_bootstrap.h:197
elf_tool_main_t
Definition: elftool.c:48
delete_rpath_for_section
static void delete_rpath_for_section(elf_main_t *em, elf_section_t *s)
Definition: elftool.c:110
clib_error_return
#define clib_error_return(e, args...)
Definition: error.h:99
elf_tool_main_t::verbose
int verbose
Definition: elftool.c:55
FORMAT_ELF_MAIN_SYMBOLS
#define FORMAT_ELF_MAIN_SYMBOLS
Definition: elf.h:1025
elf64_dynamic_entry_t
Definition: elf.h:567
unformat_parse_error
#define unformat_parse_error(input)
Definition: format.h:261
elf_main_t::sections
elf_section_t * sections
Definition: elf.h:896
clib_error_report
#define clib_error_report(e)
Definition: error.h:113
unformat_input_t
struct _unformat_input_t unformat_input_t
error
Definition: cJSON.c:88
elf_tool_main_t::set_rpath
char * set_rpath
Definition: elftool.c:53
unformat
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
elf_tool_main_t::allow_elf_shared
int allow_elf_shared
Definition: elftool.c:57
vec_len
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
Definition: vec_bootstrap.h:142
elf_tool_main_t::file_size
u64 file_size
Definition: elftool.c:59
vec_add1
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:606
vec_dup
#define vec_dup(V)
Return copy of vector (no header, no alignment)
Definition: vec.h:444
elf_tool_main_t::set_interpreter
char * set_interpreter
Definition: elftool.c:52
unformat_check_input
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:163
elf.h
elf_main_t::dynamic_string_table_section_index
u32 dynamic_string_table_section_index
Definition: elf.h:908
elf_get_section_by_start_address
__clib_export clib_error_t * elf_get_section_by_start_address(elf_main_t *em, uword start_address, elf_section_t **result)
Definition: elf.c:69
elf_write_file
__clib_export clib_error_t * elf_write_file(elf_main_t *em, char *file_name)
Definition: elf.c:1754
set_rpath_for_section
static clib_error_t * set_rpath_for_section(elf_main_t *em, elf_section_t *s, char *new_rpath)
Definition: elftool.c:163
elf_main_t::dynamic_string_table
u8 * dynamic_string_table
Definition: elf.h:907
elf_tool_main_t::output_file
char * output_file
Definition: elftool.c:51
FORMAT_ELF_MAIN_RELOCATIONS
#define FORMAT_ELF_MAIN_RELOCATIONS
Definition: elf.h:1026
elf_tool_main_t::elf_main
elf_main_t elf_main
Definition: elftool.c:49
elf_set_dynamic_entries
__clib_export void elf_set_dynamic_entries(elf_main_t *em)
Definition: elf.c:899
elf_tool_main_t::input_file
char * input_file
Definition: elftool.c:50
elf_segment_t::header
elf64_segment_header_t header
Definition: elf.h:872
elf_section_t::header
elf64_section_header_t header
Definition: elf.h:854
elf_segment_t
Definition: elf.h:870
vec_free
#define vec_free(V)
Free vector's memory (no header).
Definition: vec.h:395
elf_set_section_contents
static void elf_set_section_contents(elf_main_t *em, uword section_index, void *new_contents, uword n_content_bytes)
Definition: elf.h:981
elf_read_file
__clib_export clib_error_t * elf_read_file(elf_main_t *em, char *file_name)
Definition: elf.c:1329
u64
unsigned long u64
Definition: types.h:89
elf_section_t
Definition: elf.h:852
elf_tool_main_t::unset_rpath
int unset_rpath
Definition: elftool.c:54
u32
unsigned int u32
Definition: types.h:88
elf_tool_main_t::interpreter_offset
u64 interpreter_offset
Definition: elftool.c:60
vec_foreach
#define vec_foreach(var, vec)
Vector iterator.
Definition: vec_bootstrap.h:213
elf_set_interpreter
static clib_error_t * elf_set_interpreter(elf_main_t *em, elf_tool_main_t *tm)
Definition: elftool.c:64
clib_error_return_unix
#define clib_error_return_unix(e, args...)
Definition: error.h:102
fformat
__clib_export word fformat(FILE *f, char *fmt,...)
Definition: format.c:466
clib_memset
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
elf_main_t::dynamic_entries
elf64_dynamic_entry_t * dynamic_entries
Definition: elf.h:906
u8
unsigned char u8
Definition: types.h:56
clib_error_t
Definition: clib_error.h:21
elf_main_t::first_header
elf_first_header_t first_header
Definition: elf.h:890
i
int i
Definition: flowhash_template.h:376
unformat_init_command_line
void unformat_init_command_line(unformat_input_t *input, char *argv[])
Definition: unformat.c:1013
clib_warning
#define clib_warning(format, args...)
Definition: error.h:59
elf_tool_main_t::rpath_offset
u64 rpath_offset
Definition: elftool.c:61
FORMAT_ELF_MAIN_DYNAMIC
#define FORMAT_ELF_MAIN_DYNAMIC
Definition: elf.h:1027
elf_main_t::segments
elf_segment_t * segments
Definition: elf.h:894
main
int main(int argc, char *argv[])
Definition: elftool.c:371
vec_bytes
#define vec_bytes(v)
Number of data bytes in vector.
Definition: vec_bootstrap.h:161
UNFORMAT_END_OF_INPUT
#define UNFORMAT_END_OF_INPUT
Definition: format.h:137
set_interpreter_rpath
static clib_error_t * set_interpreter_rpath(elf_tool_main_t *tm)
Definition: elftool.c:221
elf_main_t
Definition: elf.h:882