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