Coverage Report

Created: 2026-08-13 06:55

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