FD.io VPP  v16.06
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  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);
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)
362  munmap (idp, mmap_length);
363  close (ifd);
364  close (ofd);
365  return error;
366 }
367 
368 
369 int main (int argc, char * argv[])
370 {
371  elf_tool_main_t _tm, * tm = &_tm;
372  elf_main_t * em = &tm->elf_main;
374  clib_error_t * error = 0;
375 
376  memset (tm, 0, sizeof (tm[0]));
377  unformat_init_command_line (&i, argv);
378 
380  {
381  if (unformat (&i, "in %s", &tm->input_file))
382  ;
383  else if (unformat (&i, "out %s", &tm->output_file))
384  ;
385  else if (unformat (&i, "set-interpreter %s", &tm->set_interpreter))
386  ;
387  else if (unformat (&i, "set-rpath %s", &tm->set_rpath))
388  ;
389  else if (unformat (&i, "unset-rpath"))
390  tm->unset_rpath = 1;
391  else if (unformat (&i, "verbose"))
392  tm->verbose = ~0;
393  else if (unformat (&i, "verbose-symbols"))
395  else if (unformat (&i, "verbose-relocations"))
397  else if (unformat (&i, "verbose-dynamic"))
399  else if (unformat (&i, "quiet"))
400  tm->quiet = 1;
401  else if (unformat (&i, "allow-elf-shared"))
402  tm->allow_elf_shared = 1;
403  else
404  {
405  error = unformat_parse_error (&i);
406  goto done;
407  }
408  }
409 
410  if (! tm->input_file)
411  clib_error ("no input file");
412 
413  /* Do the typical case a stone-simple way... */
414  if (tm->quiet && tm->set_interpreter && tm->set_rpath && tm->output_file)
415  {
416  error = set_interpreter_rpath (tm);
417  goto done;
418  }
419 
420  error = elf_read_file (em, tm->input_file);
421 
422  if (error)
423  goto done;
424 
425  if (tm->verbose)
426  fformat (stdout, "%U", format_elf_main, em, tm->verbose);
427 
428  if (tm->set_interpreter)
429  {
430  error = elf_set_interpreter (em, tm);
431  if (error)
432  goto done;
433  }
434 
435  if (tm->set_rpath)
436  {
437  error = set_rpath (em, tm->set_rpath);
438  if (error)
439  goto done;
440  }
441 
442  if (tm->unset_rpath)
443  delete_rpath (em);
444 
445  if (tm->output_file)
446  error = elf_write_file (em, tm->output_file);
447 
448  elf_main_free (em);
449 
450  done:
451  if (error)
452  {
453  if (tm->quiet == 0)
454  clib_error_report (error);
455  return 1;
456  }
457  else
458  return 0;
459 }
int allow_elf_shared
Definition: elftool.c:57
elf64_segment_header_t header
Definition: elf.h:851
static clib_error_t * set_interpreter_rpath(elf_tool_main_t *tm)
Definition: elftool.c:221
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:267
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:942
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
#define UNFORMAT_END_OF_INPUT
Definition: format.h:142
void elf_set_dynamic_entries(elf_main_t *em)
Definition: elf.c:875
#define clib_error(format, args...)
Definition: error.h:62
u64 rpath_offset
Definition: elftool.c:61
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:480
static void delete_rpath(elf_main_t *em)
Definition: elftool.c:144
#define clib_error_report(e)
Definition: error.h:126
always_inline void elf_set_section_contents(elf_main_t *em, uword section_index, void *new_contents, uword n_content_bytes)
Definition: elf.h:961
#define vec_bytes(v)
Number of data bytes in vector.
#define FORMAT_ELF_MAIN_RELOCATIONS
Definition: elf.h:997
always_inline uword unformat_check_input(unformat_input_t *i)
Definition: format.h:168
u8 * contents
Definition: elf.h:847
#define clib_warning(format, args...)
Definition: error.h:59
unsigned long u64
Definition: types.h:89
#define vec_end(v)
End (last data address) of vector.
static uword pointer_to_uword(const void *p)
Definition: types.h:131
u64 interpreter_offset
Definition: elftool.c:60
elf_segment_t * segments
Definition: elf.h:872
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:1678
void unformat_init_command_line(unformat_input_t *input, char *argv[])
Definition: unformat.c:975
u8 * dynamic_string_table
Definition: elf.h:885
#define clib_error_return_unix(e, args...)
Definition: error.h:115
#define vec_dup(V)
Return copy of vector (no header, no alignment)
Definition: vec.h:332
static clib_error_t * set_rpath_for_section(elf_main_t *em, elf_section_t *s, char *new_rpath)
Definition: elftool.c:163
#define unformat_parse_error(input)
Definition: format.h:265
elf_first_header_t first_header
Definition: elf.h:868
Definition: elf.h:553
char * output_file
Definition: elftool.c:51
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:298
always_inline void elf_main_free(elf_main_t *em)
Definition: elf.h:903
clib_error_t * elf_read_file(elf_main_t *em, char *file_name)
Definition: elf.c:1286
#define clib_memcpy(a, b, c)
Definition: string.h:63
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
unsigned int u32
Definition: types.h:88
elf64_dynamic_entry_t * dynamic_entries
Definition: elf.h:884
elf_section_t * sections
Definition: elf.h:874
#define FORMAT_ELF_MAIN_SYMBOLS
Definition: elf.h:996
#define FORMAT_ELF_MAIN_DYNAMIC
Definition: elf.h:998
format_function_t format_elf_main
Definition: elf.h:1000
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
word fformat(FILE *f, char *fmt,...)
Definition: format.c:437
char * set_rpath
Definition: elftool.c:53
elf64_section_header_t header
Definition: elf.h:834
#define vec_foreach(var, vec)
Vector iterator.
#define clib_error_return(e, args...)
Definition: error.h:112
int main(int argc, char *argv[])
Definition: elftool.c:369
struct _unformat_input_t unformat_input_t
elf_file_type_t file_type
Definition: elf.h:206
clib_error_t * elf_get_section_by_start_address(elf_main_t *em, uword start_address, elf_section_t **result)
Definition: elf.c:67
int unset_rpath
Definition: elftool.c:54
u32 dynamic_string_table_section_index
Definition: elf.h:886