xref: /third_party/elfutils/libdwfl/open.c (revision da0c48c4)
1da0c48c4Sopenharmony_ci/* Decompression support for libdwfl: zlib (gzip), bzlib (bzip2) or lzma (xz).
2da0c48c4Sopenharmony_ci   Copyright (C) 2009, 2016 Red Hat, Inc.
3da0c48c4Sopenharmony_ci   Copyright (C) 2022 Google LLC
4da0c48c4Sopenharmony_ci   This file is part of elfutils.
5da0c48c4Sopenharmony_ci
6da0c48c4Sopenharmony_ci   This file is free software; you can redistribute it and/or modify
7da0c48c4Sopenharmony_ci   it under the terms of either
8da0c48c4Sopenharmony_ci
9da0c48c4Sopenharmony_ci     * the GNU Lesser General Public License as published by the Free
10da0c48c4Sopenharmony_ci       Software Foundation; either version 3 of the License, or (at
11da0c48c4Sopenharmony_ci       your option) any later version
12da0c48c4Sopenharmony_ci
13da0c48c4Sopenharmony_ci   or
14da0c48c4Sopenharmony_ci
15da0c48c4Sopenharmony_ci     * the GNU General Public License as published by the Free
16da0c48c4Sopenharmony_ci       Software Foundation; either version 2 of the License, or (at
17da0c48c4Sopenharmony_ci       your option) any later version
18da0c48c4Sopenharmony_ci
19da0c48c4Sopenharmony_ci   or both in parallel, as here.
20da0c48c4Sopenharmony_ci
21da0c48c4Sopenharmony_ci   elfutils is distributed in the hope that it will be useful, but
22da0c48c4Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
23da0c48c4Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24da0c48c4Sopenharmony_ci   General Public License for more details.
25da0c48c4Sopenharmony_ci
26da0c48c4Sopenharmony_ci   You should have received copies of the GNU General Public License and
27da0c48c4Sopenharmony_ci   the GNU Lesser General Public License along with this program.  If
28da0c48c4Sopenharmony_ci   not, see <http://www.gnu.org/licenses/>.  */
29da0c48c4Sopenharmony_ci
30da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H
31da0c48c4Sopenharmony_ci# include <config.h>
32da0c48c4Sopenharmony_ci#endif
33da0c48c4Sopenharmony_ci
34da0c48c4Sopenharmony_ci#include "../libelf/libelfP.h"
35da0c48c4Sopenharmony_ci#undef	_
36da0c48c4Sopenharmony_ci#include "libdwflP.h"
37da0c48c4Sopenharmony_ci
38da0c48c4Sopenharmony_ci#if !USE_BZLIB
39da0c48c4Sopenharmony_ci# define __libdw_bunzip2(...)	DWFL_E_BADELF
40da0c48c4Sopenharmony_ci#endif
41da0c48c4Sopenharmony_ci
42da0c48c4Sopenharmony_ci#if !USE_LZMA
43da0c48c4Sopenharmony_ci# define __libdw_unlzma(...)	DWFL_E_BADELF
44da0c48c4Sopenharmony_ci#endif
45da0c48c4Sopenharmony_ci
46da0c48c4Sopenharmony_ci#if !USE_ZSTD
47da0c48c4Sopenharmony_ci# define __libdw_unzstd(...)	DWFL_E_BADELF
48da0c48c4Sopenharmony_ci#endif
49da0c48c4Sopenharmony_ci
50da0c48c4Sopenharmony_ci/* Consumes and replaces *ELF only on success.  */
51da0c48c4Sopenharmony_cistatic Dwfl_Error
52da0c48c4Sopenharmony_cidecompress (int fd __attribute__ ((unused)), Elf **elf)
53da0c48c4Sopenharmony_ci{
54da0c48c4Sopenharmony_ci  Dwfl_Error error = DWFL_E_BADELF;
55da0c48c4Sopenharmony_ci  /* ELF cannot be decompressed, if there is no file descriptor.  */
56da0c48c4Sopenharmony_ci  if (fd == -1)
57da0c48c4Sopenharmony_ci    return error;
58da0c48c4Sopenharmony_ci  void *buffer = NULL;
59da0c48c4Sopenharmony_ci  size_t size = 0;
60da0c48c4Sopenharmony_ci
61da0c48c4Sopenharmony_ci  const off_t offset = (*elf)->start_offset;
62da0c48c4Sopenharmony_ci  void *const mapped = ((*elf)->map_address == NULL ? NULL
63da0c48c4Sopenharmony_ci			: (*elf)->map_address + offset);
64da0c48c4Sopenharmony_ci  const size_t mapped_size = (*elf)->maximum_size;
65da0c48c4Sopenharmony_ci  if (mapped_size == 0)
66da0c48c4Sopenharmony_ci    return error;
67da0c48c4Sopenharmony_ci
68da0c48c4Sopenharmony_ci  error = __libdw_gunzip (fd, offset, mapped, mapped_size, &buffer, &size);
69da0c48c4Sopenharmony_ci  if (error == DWFL_E_BADELF)
70da0c48c4Sopenharmony_ci    error = __libdw_bunzip2 (fd, offset, mapped, mapped_size, &buffer, &size);
71da0c48c4Sopenharmony_ci  if (error == DWFL_E_BADELF)
72da0c48c4Sopenharmony_ci    error = __libdw_unlzma (fd, offset, mapped, mapped_size, &buffer, &size);
73da0c48c4Sopenharmony_ci  if (error == DWFL_E_BADELF)
74da0c48c4Sopenharmony_ci    error = __libdw_unzstd (fd, offset, mapped, mapped_size, &buffer, &size);
75da0c48c4Sopenharmony_ci
76da0c48c4Sopenharmony_ci  if (error == DWFL_E_NOERROR)
77da0c48c4Sopenharmony_ci    {
78da0c48c4Sopenharmony_ci      if (unlikely (size == 0))
79da0c48c4Sopenharmony_ci	{
80da0c48c4Sopenharmony_ci	  error = DWFL_E_BADELF;
81da0c48c4Sopenharmony_ci	  free (buffer);
82da0c48c4Sopenharmony_ci	}
83da0c48c4Sopenharmony_ci      else
84da0c48c4Sopenharmony_ci	{
85da0c48c4Sopenharmony_ci	  Elf *memelf = elf_memory (buffer, size);
86da0c48c4Sopenharmony_ci	  if (memelf == NULL)
87da0c48c4Sopenharmony_ci	    {
88da0c48c4Sopenharmony_ci	      error = DWFL_E_LIBELF;
89da0c48c4Sopenharmony_ci	      free (buffer);
90da0c48c4Sopenharmony_ci	    }
91da0c48c4Sopenharmony_ci	  else
92da0c48c4Sopenharmony_ci	    {
93da0c48c4Sopenharmony_ci	      memelf->flags |= ELF_F_MALLOCED;
94da0c48c4Sopenharmony_ci	      elf_end (*elf);
95da0c48c4Sopenharmony_ci	      *elf = memelf;
96da0c48c4Sopenharmony_ci	    }
97da0c48c4Sopenharmony_ci	}
98da0c48c4Sopenharmony_ci    }
99da0c48c4Sopenharmony_ci  else
100da0c48c4Sopenharmony_ci    free (buffer);
101da0c48c4Sopenharmony_ci
102da0c48c4Sopenharmony_ci  return error;
103da0c48c4Sopenharmony_ci}
104da0c48c4Sopenharmony_ci
105da0c48c4Sopenharmony_cistatic Dwfl_Error
106da0c48c4Sopenharmony_ciwhat_kind (int fd, Elf **elfp, Elf_Kind *kind, bool *may_close_fd)
107da0c48c4Sopenharmony_ci{
108da0c48c4Sopenharmony_ci  Dwfl_Error error = DWFL_E_NOERROR;
109da0c48c4Sopenharmony_ci  *kind = elf_kind (*elfp);
110da0c48c4Sopenharmony_ci  if (unlikely (*kind == ELF_K_NONE))
111da0c48c4Sopenharmony_ci    {
112da0c48c4Sopenharmony_ci      if (unlikely (*elfp == NULL))
113da0c48c4Sopenharmony_ci	error = DWFL_E_LIBELF;
114da0c48c4Sopenharmony_ci      else
115da0c48c4Sopenharmony_ci	{
116da0c48c4Sopenharmony_ci	  error = decompress (fd, elfp);
117da0c48c4Sopenharmony_ci	  if (error == DWFL_E_NOERROR)
118da0c48c4Sopenharmony_ci	    {
119da0c48c4Sopenharmony_ci	      *may_close_fd = true;
120da0c48c4Sopenharmony_ci	      *kind = elf_kind (*elfp);
121da0c48c4Sopenharmony_ci	    }
122da0c48c4Sopenharmony_ci	}
123da0c48c4Sopenharmony_ci    }
124da0c48c4Sopenharmony_ci  return error;
125da0c48c4Sopenharmony_ci}
126da0c48c4Sopenharmony_ci
127da0c48c4Sopenharmony_cistatic Dwfl_Error
128da0c48c4Sopenharmony_cilibdw_open_elf (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok,
129da0c48c4Sopenharmony_ci		bool never_close_fd, bool bad_elf_ok, bool use_elfp)
130da0c48c4Sopenharmony_ci{
131da0c48c4Sopenharmony_ci  bool may_close_fd = false;
132da0c48c4Sopenharmony_ci
133da0c48c4Sopenharmony_ci  Elf *elf =
134da0c48c4Sopenharmony_ci      use_elfp ? *elfp : elf_begin (*fdp, ELF_C_READ_MMAP_PRIVATE, NULL);
135da0c48c4Sopenharmony_ci
136da0c48c4Sopenharmony_ci  Elf_Kind kind;
137da0c48c4Sopenharmony_ci  Dwfl_Error error = what_kind (*fdp, &elf, &kind, &may_close_fd);
138da0c48c4Sopenharmony_ci  if (error == DWFL_E_BADELF)
139da0c48c4Sopenharmony_ci    {
140da0c48c4Sopenharmony_ci      /* It's not an ELF file or a compressed file.
141da0c48c4Sopenharmony_ci	 See if it's an image with a header preceding the real file.  */
142da0c48c4Sopenharmony_ci
143da0c48c4Sopenharmony_ci      off_t offset = elf->start_offset;
144da0c48c4Sopenharmony_ci      error = __libdw_image_header (*fdp, &offset,
145da0c48c4Sopenharmony_ci				    (elf->map_address == NULL ? NULL
146da0c48c4Sopenharmony_ci				     : elf->map_address + offset),
147da0c48c4Sopenharmony_ci				    elf->maximum_size);
148da0c48c4Sopenharmony_ci      if (error == DWFL_E_NOERROR)
149da0c48c4Sopenharmony_ci	{
150da0c48c4Sopenharmony_ci	  /* Pure evil.  libelf needs some better interfaces.  */
151da0c48c4Sopenharmony_ci	  elf->kind = ELF_K_AR;
152da0c48c4Sopenharmony_ci	  elf->state.ar.elf_ar_hdr.ar_name = "libdwfl is faking you out";
153da0c48c4Sopenharmony_ci	  elf->state.ar.elf_ar_hdr.ar_size = elf->maximum_size - offset;
154da0c48c4Sopenharmony_ci	  elf->state.ar.offset = offset - sizeof (struct ar_hdr);
155da0c48c4Sopenharmony_ci	  Elf *subelf = elf_begin (-1, ELF_C_READ_MMAP_PRIVATE, elf);
156da0c48c4Sopenharmony_ci	  elf->kind = ELF_K_NONE;
157da0c48c4Sopenharmony_ci	  if (unlikely (subelf == NULL))
158da0c48c4Sopenharmony_ci	    error = DWFL_E_LIBELF;
159da0c48c4Sopenharmony_ci	  else
160da0c48c4Sopenharmony_ci	    {
161da0c48c4Sopenharmony_ci	      subelf->parent = NULL;
162da0c48c4Sopenharmony_ci	      subelf->flags |= elf->flags & (ELF_F_MMAPPED | ELF_F_MALLOCED);
163da0c48c4Sopenharmony_ci	      elf->flags &= ~(ELF_F_MMAPPED | ELF_F_MALLOCED);
164da0c48c4Sopenharmony_ci	      elf_end (elf);
165da0c48c4Sopenharmony_ci	      elf = subelf;
166da0c48c4Sopenharmony_ci	      error = what_kind (*fdp, &elf, &kind, &may_close_fd);
167da0c48c4Sopenharmony_ci	    }
168da0c48c4Sopenharmony_ci	}
169da0c48c4Sopenharmony_ci    }
170da0c48c4Sopenharmony_ci
171da0c48c4Sopenharmony_ci  if (error == DWFL_E_NOERROR
172da0c48c4Sopenharmony_ci      && kind != ELF_K_ELF
173da0c48c4Sopenharmony_ci      && !(archive_ok && kind == ELF_K_AR))
174da0c48c4Sopenharmony_ci    error = DWFL_E_BADELF;
175da0c48c4Sopenharmony_ci
176da0c48c4Sopenharmony_ci  /* This basically means, we keep a ELF_K_NONE Elf handle and return it.  */
177da0c48c4Sopenharmony_ci  if (bad_elf_ok && error == DWFL_E_BADELF)
178da0c48c4Sopenharmony_ci    error = DWFL_E_NOERROR;
179da0c48c4Sopenharmony_ci
180da0c48c4Sopenharmony_ci  if (error != DWFL_E_NOERROR)
181da0c48c4Sopenharmony_ci    {
182da0c48c4Sopenharmony_ci      elf_end (elf);
183da0c48c4Sopenharmony_ci      elf = NULL;
184da0c48c4Sopenharmony_ci    }
185da0c48c4Sopenharmony_ci
186da0c48c4Sopenharmony_ci  if (! never_close_fd
187da0c48c4Sopenharmony_ci      && error == DWFL_E_NOERROR ? may_close_fd : close_on_fail)
188da0c48c4Sopenharmony_ci    {
189da0c48c4Sopenharmony_ci      close (*fdp);
190da0c48c4Sopenharmony_ci      *fdp = -1;
191da0c48c4Sopenharmony_ci    }
192da0c48c4Sopenharmony_ci
193da0c48c4Sopenharmony_ci  *elfp = elf;
194da0c48c4Sopenharmony_ci  return error;
195da0c48c4Sopenharmony_ci}
196da0c48c4Sopenharmony_ci
197da0c48c4Sopenharmony_ciDwfl_Error internal_function
198da0c48c4Sopenharmony_ci__libdw_open_file (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok)
199da0c48c4Sopenharmony_ci{
200da0c48c4Sopenharmony_ci  return libdw_open_elf (fdp, elfp, close_on_fail, archive_ok, false, false,
201da0c48c4Sopenharmony_ci			 false);
202da0c48c4Sopenharmony_ci}
203da0c48c4Sopenharmony_ci
204da0c48c4Sopenharmony_ciDwfl_Error internal_function
205da0c48c4Sopenharmony_ci__libdw_open_elf_memory (char *data, size_t size, Elf **elfp, bool archive_ok)
206da0c48c4Sopenharmony_ci{
207da0c48c4Sopenharmony_ci  /* It is ok to use `fd == -1` here, because libelf uses it as a value for
208da0c48c4Sopenharmony_ci     "no file opened" and code supports working with this value, and also
209da0c48c4Sopenharmony_ci     `never_close_fd == false` is passed to prevent closing non-existant file.
210da0c48c4Sopenharmony_ci     The only caveat is in `decompress` method, which doesn't support
211da0c48c4Sopenharmony_ci     decompressing from memory, so reading compressed zImage using this method
212da0c48c4Sopenharmony_ci     won't work.  */
213da0c48c4Sopenharmony_ci  int fd = -1;
214da0c48c4Sopenharmony_ci  *elfp = elf_memory (data, size);
215da0c48c4Sopenharmony_ci  /* Allow using this ELF as reference for subsequent elf_begin calls.  */
216da0c48c4Sopenharmony_ci  (*elfp)->cmd = ELF_C_READ_MMAP_PRIVATE;
217da0c48c4Sopenharmony_ci  return libdw_open_elf (&fd, elfp, false, archive_ok, true, false, true);
218da0c48c4Sopenharmony_ci}
219da0c48c4Sopenharmony_ci
220da0c48c4Sopenharmony_ciDwfl_Error internal_function
221da0c48c4Sopenharmony_ci__libdw_open_elf (int fd, Elf **elfp)
222da0c48c4Sopenharmony_ci{
223da0c48c4Sopenharmony_ci  return libdw_open_elf (&fd, elfp, false, true, true, true, false);
224da0c48c4Sopenharmony_ci}
225