• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 13147270439

04 Feb 2025 05:43PM UTC coverage: 71.817% (+0.08%) from 71.734%
13147270439

push

github

web-flow
machine: introduce io.systemd.MachineImage.CleanPool (#35928)

This PR introduces io.systemd.MachineImage.CleanPool method which is
alternative to DBus's CleanPool.

154 of 202 new or added lines in 6 files covered. (76.24%)

176 existing lines in 37 files now uncovered.

293028 of 408020 relevant lines covered (71.82%)

713624.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.64
/src/shared/pe-binary.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <sys/stat.h>
4
#include <unistd.h>
5

6
#include "alloc-util.h"
7
#include "hexdecoct.h"
8
#include "log.h"
9
#include "pe-binary.h"
10
#include "sort-util.h"
11
#include "stat-util.h"
12
#include "string-table.h"
13
#include "string-util.h"
14

15
bool pe_header_is_64bit(const PeHeader *h) {
232✔
16
        assert(h);
232✔
17

18
        if (le16toh(h->optional.Magic) == UINT16_C(0x010B)) /* PE32 */
232✔
19
                return false;
20

21
        if (le16toh(h->optional.Magic) == UINT16_C(0x020B)) /* PE32+ */
232✔
22
                return true;
23

24
        assert_not_reached();
×
25
}
26

27
static size_t pe_header_size(const PeHeader *pe_header) {
254✔
28
        assert(pe_header);
254✔
29

30
        return offsetof(PeHeader, optional) + le16toh(pe_header->pe.SizeOfOptionalHeader);
254✔
31
}
32

33
const IMAGE_DATA_DIRECTORY *pe_header_get_data_directory(
20✔
34
                const PeHeader *h,
35
                size_t i) {
36

37
        assert(h);
20✔
38

39
        if (i >= le32toh(PE_HEADER_OPTIONAL_FIELD(h, NumberOfRvaAndSizes)))
20✔
40
                return NULL;
41

42
        return PE_HEADER_OPTIONAL_FIELD(h, DataDirectory) + i;
20✔
43
}
44

45
const IMAGE_SECTION_HEADER *pe_section_table_find(
518✔
46
                const IMAGE_SECTION_HEADER *sections,
47
                size_t n_sections,
48
                const char *name) {
49

50
        size_t n;
518✔
51

52
        assert(name);
518✔
53
        assert(sections || n_sections == 0);
518✔
54

55
        n = strlen(name);
518✔
56
        if (n > sizeof(sections[0].Name)) /* Too long? */
518✔
57
                return NULL;
58

59
        FOREACH_ARRAY(section, sections, n_sections)
3,304✔
60
                if (memcmp(section->Name, name, n) == 0 &&
3,654✔
61
                    memeqzero(section->Name + n, sizeof(section->Name) - n))
434✔
62
                        return section;
63

64
        return NULL;
65
}
66

67
const IMAGE_SECTION_HEADER* pe_header_find_section(
112✔
68
                const PeHeader *pe_header,
69
                const IMAGE_SECTION_HEADER *sections,
70
                const char *name) {
71

72
        assert(pe_header);
112✔
73

74
        return pe_section_table_find(sections, le16toh(pe_header->pe.NumberOfSections), name);
112✔
75
}
76

77
int pe_load_headers(
88✔
78
                int fd,
79
                IMAGE_DOS_HEADER **ret_dos_header,
80
                PeHeader **ret_pe_header) {
81

82
        _cleanup_free_ IMAGE_DOS_HEADER *dos_header = NULL;
176✔
83
        _cleanup_free_ PeHeader *pe_header = NULL;
88✔
84
        ssize_t n;
88✔
85

86
        assert(fd >= 0);
88✔
87

88
        dos_header = new(IMAGE_DOS_HEADER, 1);
88✔
89
        if (!dos_header)
88✔
90
                return log_oom_debug();
×
91

92
        n = pread(fd,
88✔
93
                  dos_header,
94
                  sizeof(IMAGE_DOS_HEADER),
95
                  0);
96
        if (n < 0)
88✔
97
                return log_debug_errno(errno, "Failed to read DOS header: %m");
×
98
        if ((size_t) n != sizeof(IMAGE_DOS_HEADER))
88✔
UNCOV
99
                return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Short read while reading MZ executable header.");
×
100

101
        if (le16toh(dos_header->e_magic) != UINT16_C(0x5A4D))
88✔
102
                return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "File lacks MZ executable header.");
2✔
103

104
        pe_header = new(PeHeader, 1);
86✔
105
        if (!pe_header)
86✔
106
                return log_oom_debug();
×
107

108
        n = pread(fd,
172✔
109
                  pe_header,
110
                  offsetof(PeHeader, optional),
111
                  le32toh(dos_header->e_lfanew));
86✔
112
        if (n < 0)
86✔
113
                return log_debug_errno(errno, "Failed to read PE executable header: %m");
×
114
        if ((size_t) n != offsetof(PeHeader, optional))
86✔
115
                return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Short read while reading PE executable header.");
×
116

117
        if (le32toh(pe_header->signature) != UINT32_C(0x00004550))
86✔
118
                return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "File lacks PE executable header.");
×
119

120
        if (le16toh(pe_header->pe.SizeOfOptionalHeader) < sizeof_field(PeHeader, optional.Magic))
86✔
121
                return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Optional header size too short for magic.");
×
122

123
        PeHeader *pe_header_tmp = realloc(pe_header, MAX(sizeof(PeHeader), pe_header_size(pe_header)));
86✔
124
        if (!pe_header_tmp)
86✔
125
                return log_oom_debug();
×
126
        pe_header = pe_header_tmp;
86✔
127

128
        n = pread(fd,
172✔
129
                  &pe_header->optional,
86✔
130
                  le16toh(pe_header->pe.SizeOfOptionalHeader),
86✔
131
                  le32toh(dos_header->e_lfanew) + offsetof(PeHeader, optional));
86✔
132
        if (n < 0)
86✔
133
                return log_debug_errno(errno, "Failed to read PE executable optional header: %m");
×
134
        if ((size_t) n != le16toh(pe_header->pe.SizeOfOptionalHeader))
86✔
135
                return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Short read while reading PE executable optional header.");
×
136

137
        if (!IN_SET(le16toh(pe_header->optional.Magic), UINT16_C(0x010B), UINT16_C(0x020B)))
86✔
138
                return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Optional header magic invalid.");
×
139

140
        if (pe_header_size(pe_header) !=
86✔
141
            PE_HEADER_OPTIONAL_FIELD_OFFSET(pe_header, DataDirectory) +
86✔
142
            sizeof(IMAGE_DATA_DIRECTORY) * (uint64_t) le32toh(PE_HEADER_OPTIONAL_FIELD(pe_header, NumberOfRvaAndSizes)))
86✔
143
                return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Optional header size mismatch.");
×
144

145
        if (ret_dos_header)
86✔
146
                *ret_dos_header = TAKE_PTR(dos_header);
86✔
147
        if (ret_pe_header)
86✔
148
                *ret_pe_header = TAKE_PTR(pe_header);
86✔
149

150
        return 0;
151
}
152

153
int pe_load_sections(
82✔
154
                int fd,
155
                const IMAGE_DOS_HEADER *dos_header,
156
                const PeHeader *pe_header,
157
                IMAGE_SECTION_HEADER **ret_sections) {
158

159
        _cleanup_free_ IMAGE_SECTION_HEADER *sections = NULL;
82✔
160
        size_t nos;
82✔
161
        ssize_t n;
82✔
162

163
        assert(fd >= 0);
82✔
164
        assert(dos_header);
82✔
165
        assert(pe_header);
82✔
166

167
        nos = le16toh(pe_header->pe.NumberOfSections);
82✔
168

169
        sections = new(IMAGE_SECTION_HEADER, nos);
82✔
170
        if (!sections)
82✔
171
                return log_oom_debug();
×
172

173
        n = pread(fd,
246✔
174
                  sections,
175
                  sizeof(IMAGE_SECTION_HEADER) * nos,
176
                  le32toh(dos_header->e_lfanew) + pe_header_size(pe_header));
82✔
177
        if (n < 0)
82✔
178
                return log_debug_errno(errno, "Failed to read section table: %m");
×
179
        if ((size_t) n != sizeof(IMAGE_SECTION_HEADER) * nos)
82✔
180
                return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Short read while reading section table.");
×
181

182
        if (ret_sections)
82✔
183
                *ret_sections = TAKE_PTR(sections);
82✔
184

185
        return 0;
186
}
187

188
int pe_read_section_data(
126✔
189
                int fd,
190
                const IMAGE_SECTION_HEADER *section,
191
                size_t max_size,
192
                void **ret,
193
                size_t *ret_size) {
194

195
        assert(fd >= 0);
126✔
196
        assert(section);
126✔
197

198
        size_t n = le32toh(section->VirtualSize);
126✔
199
        if (n > MIN(max_size, (size_t) SSIZE_MAX))
126✔
200
                return -E2BIG;
126✔
201

202
        _cleanup_free_ void *data = malloc(n+1);
126✔
203
        if (!data)
126✔
204
                return -ENOMEM;
205

206
        ssize_t ss = pread(fd, data, n, le32toh(section->PointerToRawData));
126✔
207
        if (ss < 0)
126✔
208
                return -errno;
×
209
        if ((size_t) ss != n)
126✔
210
                return -EIO;
211

212
        if (ret_size)
126✔
213
                *ret_size = n;
×
214
        else {
215
                /* Check that there are no embedded NUL bytes if the caller doesn't want to know the size
216
                 * (i.e. treats the blob as a string) */
217
                const char *nul;
126✔
218

219
                nul = memchr(data, 0, n);
126✔
220
                if (nul && !memeqzero(nul, n - (nul - (const char*) data))) /* If there's a NUL it must only be NULs from there on */
126✔
221
                        return -EBADMSG;
222
        }
223
        if (ret) {
126✔
224
                ((uint8_t*) data)[n] = 0; /* NUL terminate, no matter what */
126✔
225
                *ret = TAKE_PTR(data);
126✔
226
        }
227

228
        return 0;
229
}
230

231
int pe_read_section_data_by_name(
×
232
                int fd,
233
                const PeHeader *pe_header,
234
                const IMAGE_SECTION_HEADER *sections,
235
                const char *name,
236
                size_t max_size,
237
                void **ret,
238
                size_t *ret_size) {
239

240
        const IMAGE_SECTION_HEADER *section;
×
241

242
        assert(fd >= 0);
×
243
        assert(pe_header);
×
244
        assert(sections || pe_header->pe.NumberOfSections == 0);
×
245
        assert(name);
×
246

247
        section = pe_header_find_section(pe_header, sections, name);
×
248
        if (!section)
×
249
                return -ENXIO;
250

251
        return pe_read_section_data(fd, section, max_size, ret, ret_size);
×
252
}
253

254
bool pe_is_uki(const PeHeader *pe_header, const IMAGE_SECTION_HEADER *sections) {
56✔
255
        assert(pe_header);
56✔
256
        assert(sections || le16toh(pe_header->pe.NumberOfSections) == 0);
56✔
257

258
        if (le16toh(pe_header->optional.Subsystem) != IMAGE_SUBSYSTEM_EFI_APPLICATION)
56✔
259
                return false;
260

261
        /* Note that the UKI spec only requires .linux, but we are stricter here, and require .osrel too,
262
         * since for sd-boot it just doesn't make sense to not have that. */
263
        return
56✔
264
                pe_header_find_section(pe_header, sections, ".osrel") &&
112✔
265
                pe_header_find_section(pe_header, sections, ".linux");
56✔
266
}
267

268
bool pe_is_addon(const PeHeader *pe_header, const IMAGE_SECTION_HEADER *sections) {
×
269
        assert(pe_header);
×
270
        assert(sections || le16toh(pe_header->pe.NumberOfSections) == 0);
×
271

272
        if (le16toh(pe_header->optional.Subsystem) != IMAGE_SUBSYSTEM_EFI_APPLICATION)
×
273
                return false;
274

275
        /* Add-ons do not have a Linux kernel, but do have one of .cmdline, .dtb, .initrd or .ucode (currently) */
276
        return !pe_header_find_section(pe_header, sections, ".linux") &&
×
277
                (pe_header_find_section(pe_header, sections, ".cmdline") ||
×
278
                 pe_header_find_section(pe_header, sections, ".dtb") ||
×
279
                 pe_header_find_section(pe_header, sections, ".initrd") ||
×
280
                 pe_header_find_section(pe_header, sections, ".ucode"));
×
281
}
282

283
bool pe_is_native(const PeHeader *pe_header) {
56✔
284
        assert(pe_header);
56✔
285

286
#ifdef _IMAGE_FILE_MACHINE_NATIVE
287
        return le16toh(pe_header->pe.Machine) == _IMAGE_FILE_MACHINE_NATIVE;
56✔
288
#else
289
        return false;
290
#endif
291
}
292

293
/* Implements:
294
 *
295
 * https://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/authenticode_pe.docx
296
 * → Section "Calculating the PE Image Hash"
297
 */
298

299
#if HAVE_OPENSSL
300
static int hash_file(int fd, EVP_MD_CTX *md_ctx, uint64_t offset, uint64_t size) {
197✔
301
        uint8_t buffer[64*1024];
197✔
302

303
        log_debug("Hashing %" PRIu64 " @ %" PRIu64 " → %" PRIu64, size, offset, offset + size);
197✔
304

305
        while (size > 0) {
411✔
306
                size_t m = MIN(size, sizeof(buffer));
214✔
307
                ssize_t n;
214✔
308

309
                n = pread(fd, buffer, m, offset);
214✔
310
                if (n < 0)
214✔
311
                        return log_debug_errno(errno, "Failed to read file for hashing: %m");
×
312
                if ((size_t) n != m)
214✔
313
                        return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Short read while hashing.");
×
314

315
                if (EVP_DigestUpdate(md_ctx, buffer, m) != 1)
214✔
316
                        return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Unable to hash data.");
×
317

318
                offset += m;
214✔
319
                size -= m;
214✔
320
        }
321

322
        return 0;
323
}
324

325
static int section_offset_cmp(const IMAGE_SECTION_HEADER *a, const IMAGE_SECTION_HEADER *b) {
162✔
326
        return CMP(ASSERT_PTR(a)->PointerToRawData, ASSERT_PTR(b)->PointerToRawData);
162✔
327
}
328
#endif
329

330
int pe_hash(int fd,
22✔
331
            const EVP_MD *md,
332
            void **ret_hash,
333
            size_t *ret_hash_size) {
334
#if HAVE_OPENSSL
335
        _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX *mdctx = NULL;
22✔
336
        _cleanup_free_ IMAGE_SECTION_HEADER *sections = NULL;
×
337
        _cleanup_free_ IMAGE_DOS_HEADER *dos_header = NULL;
×
338
        _cleanup_free_ PeHeader *pe_header = NULL;
22✔
339
        const IMAGE_DATA_DIRECTORY *certificate_table;
22✔
340
        struct stat st;
22✔
341
        uint64_t p, q;
22✔
342
        int r;
22✔
343

344
        assert(fd >= 0);
22✔
345
        assert(md);
22✔
346
        assert(ret_hash_size);
22✔
347
        assert(ret_hash);
22✔
348

349
        if (fstat(fd, &st) < 0)
22✔
350
                return log_debug_errno(errno, "Failed to stat file: %m");
×
351
        r = stat_verify_regular(&st);
22✔
352
        if (r < 0)
22✔
353
                return log_debug_errno(r, "Not a regular file: %m");
2✔
354

355
        r = pe_load_headers(fd, &dos_header, &pe_header);
20✔
356
        if (r < 0)
20✔
357
                return r;
358

359
        r = pe_load_sections(fd, dos_header, pe_header, &sections);
18✔
360
        if (r < 0)
18✔
361
                return r;
362

363
        certificate_table = pe_header_get_data_directory(pe_header, IMAGE_DATA_DIRECTORY_INDEX_CERTIFICATION_TABLE);
18✔
364
        if (!certificate_table)
18✔
365
                return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "File lacks certificate table.");
×
366

367
        mdctx = EVP_MD_CTX_new();
18✔
368
        if (!mdctx)
18✔
369
                return log_oom_debug();
×
370

371
        if (EVP_DigestInit_ex(mdctx, md, NULL) != 1)
18✔
372
                return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to allocate message digest.");
×
373

374
        /* Everything from beginning of file to CheckSum field in PE header */
375
        p = (uint64_t) dos_header->e_lfanew +
18✔
376
                offsetof(PeHeader, optional.CheckSum);
377
        r = hash_file(fd, mdctx, 0, p);
18✔
378
        if (r < 0)
18✔
379
                return r;
380
        p += sizeof(le32_t);
18✔
381

382
        /* Everything between the CheckSum field and the Image Data Directory Entry for the Certification Table */
383
        q = (uint64_t) dos_header->e_lfanew +
36✔
384
                PE_HEADER_OPTIONAL_FIELD_OFFSET(pe_header, DataDirectory[IMAGE_DATA_DIRECTORY_INDEX_CERTIFICATION_TABLE]);
18✔
385
        r = hash_file(fd, mdctx, p, q - p);
18✔
386
        if (r < 0)
18✔
387
                return r;
388
        q += sizeof(IMAGE_DATA_DIRECTORY);
18✔
389

390
        /* The rest of the header + the section table */
391
        p = pe_header->optional.SizeOfHeaders;
18✔
392
        if (p < q)
18✔
393
                return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "SizeOfHeaders too short.");
×
394
        r = hash_file(fd, mdctx, q, p - q);
18✔
395
        if (r < 0)
18✔
396
                return r;
397

398
        /* Sort by location in file */
399
        typesafe_qsort(sections, pe_header->pe.NumberOfSections, section_offset_cmp);
18✔
400

401
        FOREACH_ARRAY(section, sections, pe_header->pe.NumberOfSections) {
144✔
402
                r = hash_file(fd, mdctx, section->PointerToRawData, section->SizeOfRawData);
126✔
403
                if (r < 0)
126✔
404
                        return r;
405

406
                p += section->SizeOfRawData;
126✔
407
        }
408

409
        if ((uint64_t) st.st_size > p) {
18✔
410

411
                if (st.st_size - p < certificate_table->Size)
1✔
412
                        return log_debug_errno(errno, "No space for certificate table, refusing.");
×
413

414
                r = hash_file(fd, mdctx, p, st.st_size - p - certificate_table->Size);
1✔
415
                if (r < 0)
1✔
416
                        return r;
417

418
                /* If the file size is not a multiple of 8 bytes, pad the hash with zero bytes. */
419
                if (st.st_size % 8 != 0 && EVP_DigestUpdate(mdctx, (const uint8_t[8]) {}, 8 - (st.st_size % 8)) != 1)
1✔
420
                        return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Unable to hash data.");
×
421
        }
422

423
        int hsz = EVP_MD_CTX_size(mdctx);
18✔
424
        if (hsz < 0)
18✔
425
                return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to get hash size.");
×
426

427
        unsigned hash_size = (unsigned) hsz;
18✔
428
        _cleanup_free_ void *hash = malloc(hsz);
18✔
429
        if (!hash)
18✔
430
                return log_oom_debug();
×
431

432
        if (EVP_DigestFinal_ex(mdctx, hash, &hash_size) != 1)
18✔
433
                return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to finalize hash function.");
×
434

435
        assert(hash_size == (unsigned) hsz);
18✔
436

437
        *ret_hash = TAKE_PTR(hash);
18✔
438
        *ret_hash_size = hash_size;
18✔
439

440
        return 0;
18✔
441
#else
442
        return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL is not supported, cannot calculate PE hash.");
443
#endif
444
}
445

446
int pe_checksum(int fd, uint32_t *ret) {
2✔
447
        _cleanup_free_ IMAGE_DOS_HEADER *dos_header = NULL;
4✔
448
        _cleanup_free_ PeHeader *pe_header = NULL;
2✔
449
        struct stat st;
2✔
450
        int r;
2✔
451

452
        assert(fd >= 0);
2✔
453
        assert(ret);
2✔
454

455
        if (fstat(fd, &st) < 0)
2✔
456
                return log_debug_errno(errno, "Failed to stat file: %m");
×
457

458
        r = pe_load_headers(fd, &dos_header, &pe_header);
2✔
459
        if (r < 0)
2✔
460
                return r;
461

462
        uint32_t checksum = 0, checksum_offset = le32toh(dos_header->e_lfanew) + offsetof(PeHeader, optional.CheckSum);
2✔
463
        size_t off = 0;
2✔
464
        for (;;) {
14✔
465
                uint16_t buf[32*1024];
8✔
466

467
                ssize_t n = pread(fd, buf, sizeof(buf), off);
8✔
468
                if (n == 0)
8✔
469
                        break;
470
                if (n < 0)
6✔
471
                        return log_debug_errno(errno, "Failed to read from PE file: %m");
×
472
                if (n % sizeof(uint16_t) != 0)
6✔
473
                        return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Short read from PE file");
×
474

475
                for (size_t i = 0; i < (size_t) n / 2; i++) {
139,570✔
476
                        if (off + i >= checksum_offset && off + i < checksum_offset + sizeof(pe_header->optional.CheckSum))
139,564✔
477
                                continue;
8✔
478

479
                        uint16_t val = le16toh(buf[i]);
139,556✔
480

481
                        checksum += val;
139,556✔
482
                        checksum = (checksum >> 16) + (checksum & 0xffff);
139,556✔
483
                }
484

485
                off += n;
6✔
486
        }
487

488
        checksum = (checksum >> 16) + (checksum & 0xffff);
2✔
489
        checksum += off;
2✔
490

491
        *ret = checksum;
2✔
492
        return 0;
2✔
493
}
494

495
#if HAVE_OPENSSL
496
typedef void* SectionHashArray[_UNIFIED_SECTION_MAX];
497

498
static void section_hash_array_done(SectionHashArray *array) {
8✔
499
        assert(array);
8✔
500

501
        for (size_t i = 0; i < _UNIFIED_SECTION_MAX; i++)
128✔
502
                free((*array)[i]);
120✔
503
}
8✔
504
#endif
505

506
int uki_hash(int fd,
8✔
507
             const EVP_MD *md,
508
             void* ret_hashes[static _UNIFIED_SECTION_MAX],
509
             size_t *ret_hash_size) {
510
#if HAVE_OPENSSL
511
        _cleanup_(section_hash_array_done) SectionHashArray hashes = {};
×
512
        _cleanup_free_ IMAGE_SECTION_HEADER *sections = NULL;
×
513
        _cleanup_free_ IMAGE_DOS_HEADER *dos_header = NULL;
×
514
        _cleanup_free_ PeHeader *pe_header = NULL;
8✔
515
        int r;
8✔
516

517
        assert(fd >= 0);
8✔
518
        assert(ret_hashes);
8✔
519
        assert(ret_hash_size);
8✔
520

521
        r = pe_load_headers(fd, &dos_header, &pe_header);
8✔
522
        if (r < 0)
8✔
523
                return r;
524

525
        r = pe_load_sections(fd, dos_header, pe_header, &sections);
8✔
526
        if (r < 0)
8✔
527
                return r;
528

529
        int hsz = EVP_MD_size(md);
8✔
530
        if (hsz < 0)
8✔
531
                return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to get hash size.");
×
532

533
        FOREACH_ARRAY(section, sections, pe_header->pe.NumberOfSections) {
64✔
534
                _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX *mdctx = NULL;
16✔
535
                _cleanup_free_ char *n = NULL;
56✔
536
                ssize_t i;
56✔
537

538
                n = memdup_suffix0(section->Name, sizeof(section->Name));
56✔
539
                if (!n)
56✔
540
                        return log_oom_debug();
×
541

542
                i = string_table_lookup(unified_sections, _UNIFIED_SECTION_MAX, n);
56✔
543
                if (i < 0)
56✔
544
                        continue;
40✔
545

546
                if (hashes[i])
16✔
547
                        return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Duplicate section");
×
548

549
                mdctx = EVP_MD_CTX_new();
16✔
550
                if (!mdctx)
16✔
551
                        return log_oom_debug();
×
552

553
                if (EVP_DigestInit_ex(mdctx, md, NULL) != 1)
16✔
554
                        return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to allocate message digest.");
×
555

556
                r = hash_file(fd, mdctx, section->PointerToRawData, MIN(section->VirtualSize, section->SizeOfRawData));
16✔
557
                if (r < 0)
16✔
558
                        return r;
559

560
                if (section->SizeOfRawData < section->VirtualSize) {
16✔
561
                        uint8_t zeroes[1024] = {};
×
562
                        size_t remaining = section->VirtualSize - section->SizeOfRawData;
×
563

564
                        while (remaining > 0) {
×
565
                                size_t sz = MIN(sizeof(zeroes), remaining);
×
566

567
                                if (EVP_DigestUpdate(mdctx, zeroes, sz) != 1)
×
568
                                        return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Unable to hash data.");
×
569

570
                                remaining -= sz;
×
571
                        }
572
                }
573

574
                hashes[i] = malloc(hsz);
16✔
575
                if (!hashes[i])
16✔
576
                        return log_oom_debug();
×
577

578
                unsigned hash_size = (unsigned) hsz;
16✔
579
                if (EVP_DigestFinal_ex(mdctx, hashes[i], &hash_size) != 1)
16✔
580
                        return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to finalize hash function.");
×
581

582
                assert(hash_size == (unsigned) hsz);
16✔
583

584
                if (DEBUG_LOGGING) {
16✔
585
                        _cleanup_free_ char *hs = NULL;
16✔
586

587
                        hs = hexmem(hashes[i], hsz);
16✔
588
                        log_debug("Section %s with %s is %s.", n, EVP_MD_name(md), strna(hs));
16✔
589
                }
590
        }
591

592
        memcpy(ret_hashes, hashes, sizeof(hashes));
8✔
593
        zero(hashes);
8✔
594
        *ret_hash_size = (unsigned) hsz;
8✔
595

596
        return 0;
8✔
597
#else
598
        return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL is not supported, cannot calculate UKI hash.");
599
#endif
600
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc