Coverage Report

Created: 2026-09-01 06:25

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