VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/ldr/ldrELF.cpp

Last change on this file was 98103, checked in by vboxsync, 17 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 12.9 KB
Line 
1/* $Id: ldrELF.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - Binary Image Loader, Executable and Linker Format (ELF).
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define LOG_GROUP RTLOGGROUP_LDR
42#include <iprt/ldr.h>
43#include "internal/iprt.h"
44
45#include <iprt/alloca.h>
46#include <iprt/asm.h>
47#include <iprt/assert.h>
48#include <iprt/dbg.h>
49#include <iprt/string.h>
50#include <iprt/log.h>
51#include <iprt/mem.h>
52#include <iprt/err.h>
53#include <iprt/crypto/digest.h>
54#include <iprt/formats/elf32.h>
55#include <iprt/formats/elf64.h>
56#include <iprt/formats/elf-i386.h>
57#include <iprt/formats/elf-amd64.h>
58#include "internal/ldr.h"
59#include "internal/dbgmod.h"
60
61
62
63/*********************************************************************************************************************************
64* Defined Constants And Macros *
65*********************************************************************************************************************************/
66/** Finds an ELF symbol table string. */
67#define ELF_STR(pHdrs, iStr) ((pHdrs)->Rel.pStr + (iStr))
68/** Finds an ELF symbol table string. */
69#define ELF_DYN_STR(pHdrs, iStr) ((pHdrs)->Dyn.pStr + (iStr))
70/** Finds an ELF section header string. */
71#define ELF_SH_STR(pHdrs, iStr) ((pHdrs)->pShStr + (iStr))
72
73
74/*********************************************************************************************************************************
75* Structures and Typedefs *
76*********************************************************************************************************************************/
77/** Magic string for RTLDRLNXMODSIG::achMagic */
78#define RTLDRLNXMODSIG_MAGIC "~Module signature appended~\n"
79AssertCompile(sizeof(RTLDRLNXMODSIG_MAGIC) == 29);
80
81/**
82 * Linux kernel module signature footer - found at the end of the file.
83 */
84typedef struct RTLDRLNXMODSIG
85{
86 /** Zero. */
87 uint8_t bAlgo;
88 /** Zero. */
89 uint8_t bHash;
90 /** Signature type (RTLDRLNXMODSIG_TYPE_PKCS7). */
91 uint8_t bType;
92 /** Zero. */
93 uint8_t cbSignerName;
94 /** Zero. */
95 uint8_t cbKeyId;
96 /** Zero padding. */
97 uint8_t abReserved[3];
98 /** The length of the signature preceeding this footer structure. */
99 uint32_t cbSignature;
100 /** Magic value identifying this structure. */
101 char achMagic[sizeof(RTLDRLNXMODSIG_MAGIC) - 1];
102} RTLDRLNXMODSIG;
103typedef RTLDRLNXMODSIG *PRTLDRLNXMODSIG;
104typedef RTLDRLNXMODSIG const *PCRTLDRLNXMODSIG;
105/** Signature type. */
106#define RTLDRLNXMODSIG_TYPE_PKCS7 2
107
108
109
110/*********************************************************************************************************************************
111* Internal Functions *
112*********************************************************************************************************************************/
113static int rtLdrELFLnxKModQueryPropIsSigned(PRTLDRREADER pReader, bool *pfRet);
114static int rtLdrELFLnxKModQueryPropPkcs7SignedData(PRTLDRREADER pReader, void *pvBuf, size_t cbBuf, size_t *pcbRet);
115static DECLCALLBACK(int) rtldrELFLnxKModHashImage(PRTLDRMODINTERNAL pMod, RTDIGESTTYPE enmDigest, uint8_t *pabHash, size_t cbHash);
116#ifdef LOG_ENABLED
117static const char *rtldrElfGetShdrType(uint32_t iType);
118static const char *rtldrElfGetPhdrType(uint32_t iType);
119#endif
120
121
122/* Select ELF mode and include the template. */
123#define ELF_MODE 32
124#define Elf_Reloc Elf_Rel
125#include "ldrELFRelocatable.cpp.h"
126#undef ELF_MODE
127#undef Elf_Reloc
128
129
130#define ELF_MODE 64
131#define Elf_Reloc Elf_Rela
132#include "ldrELFRelocatable.cpp.h"
133#undef ELF_MODE
134#undef Elf_Reloc
135
136
137#ifdef LOG_ENABLED
138
139/**
140 * Gets the section type.
141 *
142 * @returns Pointer to read only string.
143 * @param iType The section type index.
144 */
145static const char *rtldrElfGetShdrType(uint32_t iType)
146{
147 switch (iType)
148 {
149 RT_CASE_RET_STR(SHT_NULL);
150 RT_CASE_RET_STR(SHT_PROGBITS);
151 RT_CASE_RET_STR(SHT_SYMTAB);
152 RT_CASE_RET_STR(SHT_STRTAB);
153 RT_CASE_RET_STR(SHT_RELA);
154 RT_CASE_RET_STR(SHT_HASH);
155 RT_CASE_RET_STR(SHT_DYNAMIC);
156 RT_CASE_RET_STR(SHT_NOTE);
157 RT_CASE_RET_STR(SHT_NOBITS);
158 RT_CASE_RET_STR(SHT_REL);
159 RT_CASE_RET_STR(SHT_SHLIB);
160 RT_CASE_RET_STR(SHT_DYNSYM);
161 default:
162 return "";
163 }
164}
165
166/**
167 * Gets the program header type.
168 *
169 * @returns Pointer to read only string.
170 * @param iType The section type index.
171 */
172static const char *rtldrElfGetPhdrType(uint32_t iType)
173{
174 switch (iType)
175 {
176 RT_CASE_RET_STR(PT_NULL);
177 RT_CASE_RET_STR(PT_LOAD);
178 RT_CASE_RET_STR(PT_DYNAMIC);
179 RT_CASE_RET_STR(PT_INTERP);
180 RT_CASE_RET_STR(PT_NOTE);
181 RT_CASE_RET_STR(PT_SHLIB);
182 RT_CASE_RET_STR(PT_PHDR);
183 RT_CASE_RET_STR(PT_TLS);
184 RT_CASE_RET_STR(PT_GNU_EH_FRAME);
185 RT_CASE_RET_STR(PT_GNU_STACK);
186 RT_CASE_RET_STR(PT_GNU_RELRO);
187 RT_CASE_RET_STR(PT_GNU_PROPERTY);
188 default:
189 return "";
190 }
191}
192
193#endif /* LOG_ENABLED*/
194
195/**
196 * Reads in what migt be a linux kernel module signature footer.
197 */
198static int rtLdrELFLnxKModReadFooter(PRTLDRREADER pReader, PRTLDRLNXMODSIG pSigFooter, uint64_t *pcbFile)
199{
200 /*
201 * Look for the linux module signature at the end of the file.
202 * This should be safe to read w/o any size checking as it is smaller than the elf header.
203 */
204 uint64_t cbFile = pReader->pfnSize(pReader);
205 *pcbFile = cbFile;
206
207 AssertCompile(sizeof(*pSigFooter) <= sizeof(Elf32_Ehdr));
208 return pReader->pfnRead(pReader, pSigFooter, sizeof(*pSigFooter), cbFile - sizeof(*pSigFooter));
209}
210
211
212/**
213 * Check that a linux kernel module signature footer is valid.
214 */
215static bool rtLdrELFLnxKModIsFooterValid(PCRTLDRLNXMODSIG pSigFooter, uint64_t cbFile)
216{
217 if (memcmp(pSigFooter->achMagic, RTLDRLNXMODSIG_MAGIC, sizeof(pSigFooter->achMagic)) == 0)
218 {
219 uint32_t const cbSignature = RT_N2H_U32(pSigFooter->cbSignature);
220 if (cbSignature > 32 && cbSignature + sizeof(*pSigFooter) < cbFile)
221 return pSigFooter->bAlgo == 0
222 && pSigFooter->bHash == 0
223 && pSigFooter->cbSignerName == 0
224 && pSigFooter->cbKeyId == 0;
225 }
226 return false;
227}
228
229
230/**
231 * Handles the linux kernel module signature part of RTLDRPROP_IS_SIGNED
232 * queries.
233 */
234static int rtLdrELFLnxKModQueryPropIsSigned(PRTLDRREADER pReader, bool *pfRet)
235{
236 *pfRet = false;
237 AssertReturn(pReader, VERR_INVALID_STATE);
238
239 uint64_t cbFile;
240 RTLDRLNXMODSIG SigFooter;
241 int rc = rtLdrELFLnxKModReadFooter(pReader, &SigFooter, &cbFile);
242 if (RT_SUCCESS(rc))
243 *pfRet = rtLdrELFLnxKModIsFooterValid(&SigFooter, cbFile);
244 return rc;
245}
246
247
248/**
249 * Handles the linux kernel module signature part of RTLDRPROP_IS_SIGNED
250 * queries.
251 */
252static int rtLdrELFLnxKModQueryPropPkcs7SignedData(PRTLDRREADER pReader, void *pvBuf, size_t cbBuf, size_t *pcbRet)
253{
254 AssertReturn(pReader, VERR_INVALID_STATE);
255
256 uint64_t cbFile;
257 RTLDRLNXMODSIG SigFooter;
258 int rc = rtLdrELFLnxKModReadFooter(pReader, &SigFooter, &cbFile);
259 if (RT_SUCCESS(rc))
260 {
261 if ( rtLdrELFLnxKModIsFooterValid(&SigFooter, cbFile)
262 && SigFooter.bType == RTLDRLNXMODSIG_TYPE_PKCS7)
263 {
264 uint32_t const cbSignature = RT_N2H_U32(SigFooter.cbSignature);
265 *pcbRet = cbSignature;
266 if (cbSignature <= cbBuf)
267 rc = pReader->pfnRead(pReader, pvBuf, cbSignature, cbFile - sizeof(SigFooter) - cbSignature);
268 else
269 rc = VERR_BUFFER_OVERFLOW;
270 }
271 else
272 rc = VERR_NOT_FOUND;
273 }
274 return rc;
275}
276
277
278/**
279 * @interface_method_impl{RTLDROPS,pfnHashImage,
280 * Handles the linux kernel module signatures.}
281 */
282static DECLCALLBACK(int) rtldrELFLnxKModHashImage(PRTLDRMODINTERNAL pMod, RTDIGESTTYPE enmDigest, uint8_t *pabHash, size_t cbHash)
283{
284 PRTLDRREADER pReader = pMod->pReader;
285 AssertReturn(pReader, VERR_INVALID_STATE);
286
287 /*
288 * Get the file size and subtract any linux kernel module signature from it
289 * since it's not part of the hash.
290 */
291 uint64_t cbFile;
292 RTLDRLNXMODSIG SigFooter;
293 int rc = rtLdrELFLnxKModReadFooter(pReader, &SigFooter, &cbFile);
294 if (RT_SUCCESS(rc))
295 {
296 if (rtLdrELFLnxKModIsFooterValid(&SigFooter, cbFile))
297 cbFile -= sizeof(SigFooter) + RT_N2H_U32(SigFooter.cbSignature);
298
299 /*
300 * Now hash the file.
301 */
302 RTCRDIGEST hDigest;
303 rc = RTCrDigestCreateByType(&hDigest, enmDigest);
304 if (RT_SUCCESS(rc))
305 {
306 uint32_t cbBuf = _64K;
307 void *pvBuf = RTMemTmpAlloc(_64K);
308 void *pvBufFree = pvBuf;
309 if (!pvBuf)
310 {
311 cbBuf = _4K;
312 pvBuf = alloca(_4K);
313 }
314
315 for (uint64_t offFile = 0; offFile < cbFile; )
316 {
317 uint64_t cbLeft = cbFile - offFile;
318 uint32_t cbToRead = cbLeft >= cbBuf ? cbBuf : (uint32_t)cbLeft;
319 rc = pReader->pfnRead(pReader, pvBuf, cbToRead, offFile);
320 AssertRCBreak(rc);
321
322 rc = RTCrDigestUpdate(hDigest, pvBuf, cbToRead);
323 offFile += cbToRead;
324 AssertRCBreak(rc);
325 }
326
327 RTMemTmpFree(pvBufFree);
328
329 if (RT_SUCCESS(rc))
330 rc = RTCrDigestFinal(hDigest, pabHash, cbHash);
331 RTCrDigestRelease(hDigest);
332 }
333 }
334 return rc;
335}
336
337
338/**
339 * Open an ELF image.
340 *
341 * @returns iprt status code.
342 * @param pReader The loader reader instance which will provide the raw image bits.
343 * @param fFlags Reserved, MBZ.
344 * @param enmArch Architecture specifier.
345 * @param phLdrMod Where to store the handle.
346 * @param pErrInfo Where to return extended error information. Optional.
347 */
348DECLHIDDEN(int) rtldrELFOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTLDRMOD phLdrMod, PRTERRINFO pErrInfo)
349{
350 const char *pszLogName = pReader->pfnLogName(pReader); NOREF(pszLogName);
351
352 /*
353 * Read the ident to decide if this is 32-bit or 64-bit
354 * and worth dealing with.
355 */
356 uint8_t e_ident[EI_NIDENT];
357 int rc = pReader->pfnRead(pReader, &e_ident, sizeof(e_ident), 0);
358 if (RT_FAILURE(rc))
359 return rc;
360
361 if ( e_ident[EI_MAG0] != ELFMAG0
362 || e_ident[EI_MAG1] != ELFMAG1
363 || e_ident[EI_MAG2] != ELFMAG2
364 || e_ident[EI_MAG3] != ELFMAG3
365 || ( e_ident[EI_CLASS] != ELFCLASS32
366 && e_ident[EI_CLASS] != ELFCLASS64)
367 )
368 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
369 "%s: Unsupported/invalid ident %.*Rhxs", pszLogName, sizeof(e_ident), e_ident);
370
371 if (e_ident[EI_DATA] != ELFDATA2LSB)
372 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_LDRELF_ODD_ENDIAN,
373 "%s: ELF endian %x is unsupported", pszLogName, e_ident[EI_DATA]);
374
375 if (e_ident[EI_CLASS] == ELFCLASS32)
376 rc = rtldrELF32Open(pReader, fFlags, enmArch, phLdrMod, pErrInfo);
377 else
378 rc = rtldrELF64Open(pReader, fFlags, enmArch, phLdrMod, pErrInfo);
379 return rc;
380}
381
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use