Coverage Report

Created: 2025-11-24 06:41

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
208
# define __libdw_bunzip2(...) DWFL_E_BADELF
39
#endif
40
41
#if !USE_LZMA
42
208
# define __libdw_unlzma(...)  DWFL_E_BADELF
43
#endif
44
45
#if !USE_ZSTD
46
208
# 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
208
{
53
208
  Dwfl_Error error = DWFL_E_BADELF;
54
  /* ELF cannot be decompressed, if there is no file descriptor.  */
55
208
  if (fd == -1)
56
0
    return error;
57
208
  void *buffer = NULL;
58
208
  size_t size = 0;
59
60
208
  const off_t offset = (*elf)->start_offset;
61
208
  void *const mapped = ((*elf)->map_address == NULL ? NULL
62
208
      : (*elf)->map_address + offset);
63
208
  const size_t mapped_size = (*elf)->maximum_size;
64
208
  if (mapped_size == 0)
65
0
    return error;
66
67
208
  error = __libdw_gunzip (fd, offset, mapped, mapped_size, &buffer, &size);
68
208
  if (error == DWFL_E_BADELF)
69
208
    error = __libdw_bunzip2 (fd, offset, mapped, mapped_size, &buffer, &size);
70
208
  if (error == DWFL_E_BADELF)
71
208
    error = __libdw_unlzma (fd, offset, mapped, mapped_size, &buffer, &size);
72
208
  if (error == DWFL_E_BADELF)
73
208
    error = __libdw_unzstd (fd, offset, mapped, mapped_size, &buffer, &size);
74
75
208
  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
208
  else
99
208
    free (buffer);
100
101
208
  return error;
102
208
}
103
104
static Dwfl_Error
105
what_kind (int fd, Elf **elfp, Elf_Kind *kind, bool *may_close_fd)
106
5.82k
{
107
5.82k
  Dwfl_Error error = DWFL_E_NOERROR;
108
5.82k
  *kind = elf_kind (*elfp);
109
5.82k
  if (unlikely (*kind == ELF_K_NONE))
110
685
    {
111
685
      if (unlikely (*elfp == NULL))
112
477
  error = DWFL_E_LIBELF;
113
208
      else
114
208
  {
115
208
    error = decompress (fd, elfp);
116
208
    if (error == DWFL_E_NOERROR)
117
0
      {
118
0
        *may_close_fd = true;
119
0
        *kind = elf_kind (*elfp);
120
0
      }
121
208
  }
122
685
    }
123
5.82k
  return error;
124
5.82k
}
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
5.82k
{
130
5.82k
  bool may_close_fd = false;
131
132
5.82k
  Elf *elf =
133
5.82k
      use_elfp ? *elfp : elf_begin (*fdp, ELF_C_READ_MMAP_PRIVATE, NULL);
134
135
5.82k
  Elf_Kind kind;
136
5.82k
  Dwfl_Error error = what_kind (*fdp, &elf, &kind, &may_close_fd);
137
5.82k
  if (error == DWFL_E_BADELF)
138
208
    {
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
208
      off_t offset = elf->start_offset;
143
208
      error = __libdw_image_header (*fdp, &offset,
144
208
            (elf->map_address == NULL ? NULL
145
208
             : elf->map_address + offset),
146
208
            elf->maximum_size);
147
208
      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.cur_ar_hdr.ar_name = "libdwfl is faking you out";
152
0
    elf->state.ar.cur_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->cmd, elf);
155
0
    elf->kind = ELF_K_NONE;
156
0
    elf->state.ar.cur_ar_hdr.ar_name = NULL;
157
0
    if (unlikely (subelf == NULL))
158
0
      error = DWFL_E_LIBELF;
159
0
    else
160
0
      {
161
0
        subelf->parent = NULL;
162
0
        subelf->flags |= elf->flags & (ELF_F_MMAPPED | ELF_F_MALLOCED);
163
0
        elf->flags &= ~(ELF_F_MMAPPED | ELF_F_MALLOCED);
164
0
        elf_end (elf);
165
0
        elf = subelf;
166
0
        error = what_kind (*fdp, &elf, &kind, &may_close_fd);
167
0
      }
168
0
  }
169
208
    }
170
171
5.82k
  if (error == DWFL_E_NOERROR
172
5.13k
      && kind != ELF_K_ELF
173
1
      && !(archive_ok && kind == ELF_K_AR))
174
1
    error = DWFL_E_BADELF;
175
176
  /* This basically means, we keep a ELF_K_NONE Elf handle and return it.  */
177
5.82k
  if (bad_elf_ok && error == DWFL_E_BADELF)
178
0
    error = DWFL_E_NOERROR;
179
180
5.82k
  if (error != DWFL_E_NOERROR)
181
686
    {
182
686
      elf_end (elf);
183
686
      elf = NULL;
184
686
    }
185
186
5.82k
  if (! never_close_fd
187
5.82k
      && error == DWFL_E_NOERROR ? may_close_fd : close_on_fail)
188
686
    {
189
686
      close (*fdp);
190
686
      *fdp = -1;
191
686
    }
192
193
5.82k
  *elfp = elf;
194
5.82k
  return error;
195
5.82k
}
196
197
Dwfl_Error internal_function
198
__libdw_open_file (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok)
199
5.82k
{
200
5.82k
  return libdw_open_elf (fdp, elfp, close_on_fail, archive_ok, false, false,
201
5.82k
       false);
202
5.82k
}
203
204
Dwfl_Error internal_function
205
__libdw_open_elf_memory (char *data, size_t size, Elf **elfp, bool archive_ok)
206
0
{
207
  /* It is ok to use `fd == -1` here, because libelf uses it as a value for
208
     "no file opened" and code supports working with this value, and also
209
     `never_close_fd == false` is passed to prevent closing non-existent file.
210
     The only caveat is in `decompress` method, which doesn't support
211
     decompressing from memory, so reading compressed zImage using this method
212
     won't work.  */
213
0
  int fd = -1;
214
0
  *elfp = elf_memory (data, size);
215
0
  if (unlikely(*elfp == NULL))
216
0
    {
217
0
      return DWFL_E_LIBELF;
218
0
    }
219
0
  return libdw_open_elf (&fd, elfp, false, archive_ok, true, false, true);
220
0
}
221
222
Dwfl_Error internal_function
223
__libdw_open_elf (int fd, Elf **elfp)
224
0
{
225
0
  return libdw_open_elf (&fd, elfp, false, true, true, true, false);
226
0
}