Coverage Report

Created: 2024-06-18 06:30

/src/elfutils/libdwfl/open.c
Line
Count
Source (jump to first uncovered line)
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
371
# define __libdw_bunzip2(...) DWFL_E_BADELF
39
#endif
40
41
#if !USE_LZMA
42
371
# define __libdw_unlzma(...)  DWFL_E_BADELF
43
#endif
44
45
#if !USE_ZSTD
46
371
# 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.63k
{
53
4.63k
  Dwfl_Error error = DWFL_E_BADELF;
54
  /* ELF cannot be decompressed, if there is no file descriptor.  */
55
4.63k
  if (fd == -1)
56
0
    return error;
57
4.63k
  void *buffer = NULL;
58
4.63k
  size_t size = 0;
59
60
4.63k
  const off_t offset = (*elf)->start_offset;
61
4.63k
  void *const mapped = ((*elf)->map_address == NULL ? NULL
62
4.63k
      : (*elf)->map_address + offset);
63
4.63k
  const size_t mapped_size = (*elf)->maximum_size;
64
4.63k
  if (mapped_size == 0)
65
0
    return error;
66
67
4.63k
  error = __libdw_gunzip (fd, offset, mapped, mapped_size, &buffer, &size);
68
4.63k
  if (error == DWFL_E_BADELF)
69
371
    error = __libdw_bunzip2 (fd, offset, mapped, mapped_size, &buffer, &size);
70
4.63k
  if (error == DWFL_E_BADELF)
71
371
    error = __libdw_unlzma (fd, offset, mapped, mapped_size, &buffer, &size);
72
4.63k
  if (error == DWFL_E_BADELF)
73
371
    error = __libdw_unzstd (fd, offset, mapped, mapped_size, &buffer, &size);
74
75
4.63k
  if (error == DWFL_E_NOERROR)
76
3.69k
    {
77
3.69k
      if (unlikely (size == 0))
78
836
  {
79
836
    error = DWFL_E_BADELF;
80
836
    free (buffer);
81
836
  }
82
2.85k
      else
83
2.85k
  {
84
2.85k
    Elf *memelf = elf_memory (buffer, size);
85
2.85k
    if (memelf == NULL)
86
13
      {
87
13
        error = DWFL_E_LIBELF;
88
13
        free (buffer);
89
13
      }
90
2.84k
    else
91
2.84k
      {
92
2.84k
        memelf->flags |= ELF_F_MALLOCED;
93
2.84k
        elf_end (*elf);
94
2.84k
        *elf = memelf;
95
2.84k
      }
96
2.85k
  }
97
3.69k
    }
98
941
  else
99
941
    free (buffer);
100
101
4.63k
  return error;
102
4.63k
}
103
104
static Dwfl_Error
105
what_kind (int fd, Elf **elfp, Elf_Kind *kind, bool *may_close_fd)
106
21.7k
{
107
21.7k
  Dwfl_Error error = DWFL_E_NOERROR;
108
21.7k
  *kind = elf_kind (*elfp);
109
21.7k
  if (unlikely (*kind == ELF_K_NONE))
110
5.22k
    {
111
5.22k
      if (unlikely (*elfp == NULL))
112
592
  error = DWFL_E_LIBELF;
113
4.63k
      else
114
4.63k
  {
115
4.63k
    error = decompress (fd, elfp);
116
4.63k
    if (error == DWFL_E_NOERROR)
117
2.84k
      {
118
2.84k
        *may_close_fd = true;
119
2.84k
        *kind = elf_kind (*elfp);
120
2.84k
      }
121
4.63k
  }
122
5.22k
    }
123
21.7k
  return error;
124
21.7k
}
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
21.6k
{
130
21.6k
  bool may_close_fd = false;
131
132
21.6k
  Elf *elf =
133
21.6k
      use_elfp ? *elfp : elf_begin (*fdp, ELF_C_READ_MMAP_PRIVATE, NULL);
134
135
21.6k
  Elf_Kind kind;
136
21.6k
  Dwfl_Error error = what_kind (*fdp, &elf, &kind, &may_close_fd);
137
21.6k
  if (error == DWFL_E_BADELF)
138
1.06k
    {
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.06k
      off_t offset = elf->start_offset;
143
1.06k
      error = __libdw_image_header (*fdp, &offset,
144
1.06k
            (elf->map_address == NULL ? NULL
145
1.06k
             : elf->map_address + offset),
146
1.06k
            elf->maximum_size);
147
1.06k
      if (error == DWFL_E_NOERROR)
148
196
  {
149
    /* Pure evil.  libelf needs some better interfaces.  */
150
196
    elf->kind = ELF_K_AR;
151
196
    elf->state.ar.elf_ar_hdr.ar_name = "libdwfl is faking you out";
152
196
    elf->state.ar.elf_ar_hdr.ar_size = elf->maximum_size - offset;
153
196
    elf->state.ar.offset = offset - sizeof (struct ar_hdr);
154
196
    Elf *subelf = elf_begin (-1, ELF_C_READ_MMAP_PRIVATE, elf);
155
196
    elf->kind = ELF_K_NONE;
156
196
    if (unlikely (subelf == NULL))
157
1
      error = DWFL_E_LIBELF;
158
195
    else
159
195
      {
160
195
        subelf->parent = NULL;
161
195
        subelf->flags |= elf->flags & (ELF_F_MMAPPED | ELF_F_MALLOCED);
162
195
        elf->flags &= ~(ELF_F_MMAPPED | ELF_F_MALLOCED);
163
195
        elf_end (elf);
164
195
        elf = subelf;
165
195
        error = what_kind (*fdp, &elf, &kind, &may_close_fd);
166
195
      }
167
196
  }
168
1.06k
    }
169
170
21.6k
  if (error == DWFL_E_NOERROR
171
21.6k
      && kind != ELF_K_ELF
172
21.6k
      && !(archive_ok && kind == ELF_K_AR))
173
799
    error = DWFL_E_BADELF;
174
175
  /* This basically means, we keep a ELF_K_NONE Elf handle and return it.  */
176
21.6k
  if (bad_elf_ok && error == DWFL_E_BADELF)
177
0
    error = DWFL_E_NOERROR;
178
179
21.6k
  if (error != DWFL_E_NOERROR)
180
2.98k
    {
181
2.98k
      elf_end (elf);
182
2.98k
      elf = NULL;
183
2.98k
    }
184
185
21.6k
  if (! never_close_fd
186
21.6k
      && error == DWFL_E_NOERROR ? may_close_fd : close_on_fail)
187
5.07k
    {
188
5.07k
      close (*fdp);
189
5.07k
      *fdp = -1;
190
5.07k
    }
191
192
21.6k
  *elfp = elf;
193
21.6k
  return error;
194
21.6k
}
195
196
Dwfl_Error internal_function
197
__libdw_open_file (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok)
198
21.6k
{
199
21.6k
  return libdw_open_elf (fdp, elfp, close_on_fail, archive_ok, false, false,
200
21.6k
       false);
201
21.6k
}
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
}