Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package pcr-oracle for openSUSE:Factory checked in at 2025-06-01 21:36:11 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/pcr-oracle (Old) and /work/SRC/openSUSE:Factory/.pcr-oracle.new.16005 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "pcr-oracle" Sun Jun 1 21:36:11 2025 rev:21 rq:1281086 version:0.5.7 Changes: -------- --- /work/SRC/openSUSE:Factory/pcr-oracle/pcr-oracle.changes 2025-05-20 09:31:00.979518421 +0200 +++ /work/SRC/openSUSE:Factory/.pcr-oracle.new.16005/pcr-oracle.changes 2025-06-01 21:36:21.620808105 +0200 @@ -1,0 +2,9 @@ +Thu May 29 07:31:13 UTC 2025 - Gary Ching-Pang Lin <g...@suse.com> + +- Update to 0.5.7 + + Support ppc64 events + + Fix the string comparison for the alternative event + (bsc#1241957) +- Add the new BuildRequires: libelf-devel and libfdisk-devel + +------------------------------------------------------------------- Old: ---- pcr-oracle-0.5.6.tar.xz New: ---- pcr-oracle-0.5.7.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ pcr-oracle.spec ++++++ --- /var/tmp/diff_new_pack.EmBGID/_old 2025-06-01 21:36:22.136829479 +0200 +++ /var/tmp/diff_new_pack.EmBGID/_new 2025-06-01 21:36:22.140829644 +0200 @@ -18,13 +18,15 @@ Name: pcr-oracle -Version: 0.5.6 +Version: 0.5.7 Release: 0 Summary: Predict TPM PCR values License: GPL-2.0-or-later Group: System/Boot URL: https://github.com/openSUSE/pcr-oracle Source: %{name}-%{version}.tar.xz +BuildRequires: libelf-devel +BuildRequires: libfdisk-devel BuildRequires: libopenssl-devel >= 3.0.0 BuildRequires: tpm2-0-tss-devel >= 2.4.0 Requires: libtss2-tcti-device0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.EmBGID/_old 2025-06-01 21:36:22.168830805 +0200 +++ /var/tmp/diff_new_pack.EmBGID/_new 2025-06-01 21:36:22.172830970 +0200 @@ -7,7 +7,7 @@ <param name="url">https://github.com/openSUSE/pcr-oracle.git</param> <param name="filename">pcr-oracle</param> <param name="versionformat">@PARENT_TAG@</param> - <param name="revision">refs/tags/0.5.6</param> + <param name="revision">refs/tags/0.5.7</param> </service> <service name="recompress" mode="disabled"> <param name="file">pcr-oracle*.tar</param> ++++++ pcr-oracle-0.5.6.tar.xz -> pcr-oracle-0.5.7.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pcr-oracle-0.5.6/Makefile.in new/pcr-oracle-0.5.7/Makefile.in --- old/pcr-oracle-0.5.6/Makefile.in 2025-05-13 08:48:20.000000000 +0200 +++ new/pcr-oracle-0.5.7/Makefile.in 2025-05-29 09:26:41.000000000 +0200 @@ -3,9 +3,11 @@ CCOPT = -O0 -g FIRSTBOOTDIR = /usr/share/jeos-firstboot -CFLAGS = -Wall @TSS2_ESYS_CFLAGS@ @JSON_CFLAGS@ $(CCOPT) +CFLAGS = -Wall @TSS2_ESYS_CFLAGS@ @JSON_CFLAGS@ @FDISK_CFLAGS@ @LIBELF_CFLAGS@ $(CCOPT) TSS2_LINK = -ltss2-esys -ltss2-tctildr -ltss2-rc -ltss2-mu -lcrypto JSON_LINK = -L@JSON_LIBDIR@ @JSON_LIBS@ +FDISK_LINK = @FDISK_LIBS@ +LIBELF_LINK = @LIBELF_LIBS@ TOOLS = pcr-oracle MANDIR = @MANDIR@ @@ -35,7 +37,8 @@ util.c \ sd-boot.c \ uapi.c \ - secure_boot.c + secure_boot.c \ + ieee1275-events.c ORACLE_OBJS = $(addprefix build/,$(patsubst %.c,%.o,$(ORACLE_SRCS))) all: $(TOOLS) $(MANPAGES) @@ -54,7 +57,7 @@ rm -rf build pcr-oracle: $(ORACLE_OBJS) - $(CC) -o $@ $(ORACLE_OBJS) $(TSS2_LINK) $(JSON_LINK) + $(CC) -o $@ $(ORACLE_OBJS) $(TSS2_LINK) $(JSON_LINK) $(FDISK_LINK) $(LIBELF_LINK) build/%.o: src/%.c @mkdir -p build diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pcr-oracle-0.5.6/configure new/pcr-oracle-0.5.7/configure --- old/pcr-oracle-0.5.6/configure 2025-05-13 08:48:20.000000000 +0200 +++ new/pcr-oracle-0.5.7/configure 2025-05-29 09:26:41.000000000 +0200 @@ -12,9 +12,11 @@ # Invoke with --help for a description of options # # microconf:begin -# version 0.5.6 +# version 0.5.7 # require libtss2 # require json +# require libfdisk +# require libelf # disable debug-authenticode # microconf:end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pcr-oracle-0.5.6/microconf/stage1/04-fdisk new/pcr-oracle-0.5.7/microconf/stage1/04-fdisk --- old/pcr-oracle-0.5.6/microconf/stage1/04-fdisk 1970-01-01 01:00:00.000000000 +0100 +++ new/pcr-oracle-0.5.7/microconf/stage1/04-fdisk 2025-05-29 09:26:41.000000000 +0200 @@ -0,0 +1,11 @@ +uc_add_option_with libfdisk +uc_with_libfdisk=detect + +uc_add_help <<EOH + + + Override libfdisk detection + --with-libfdisk=VERSION + --without-libfdisk + +EOH diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pcr-oracle-0.5.6/microconf/stage1/05-libelf new/pcr-oracle-0.5.7/microconf/stage1/05-libelf --- old/pcr-oracle-0.5.6/microconf/stage1/05-libelf 1970-01-01 01:00:00.000000000 +0100 +++ new/pcr-oracle-0.5.7/microconf/stage1/05-libelf 2025-05-29 09:26:41.000000000 +0200 @@ -0,0 +1,11 @@ +uc_add_option_with libelf +uc_with_libelf=detect + +uc_add_help <<EOH + + + Override libelf detection + --with-libelf=VERSION + --without-libelf + +EOH diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pcr-oracle-0.5.6/microconf/stage3/06-fdisk new/pcr-oracle-0.5.7/microconf/stage3/06-fdisk --- old/pcr-oracle-0.5.6/microconf/stage3/06-fdisk 1970-01-01 01:00:00.000000000 +0100 +++ new/pcr-oracle-0.5.7/microconf/stage3/06-fdisk 2025-05-29 09:26:41.000000000 +0200 @@ -0,0 +1,6 @@ +################################################################## +# libfdisk version +################################################################## +if [ -z "$uc_with_libfdisk" -o "$uc_with_libfdisk" = "detect" ]; then + uc_pkg_config_check_package fdisk +fi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pcr-oracle-0.5.6/microconf/stage3/07-libelf new/pcr-oracle-0.5.7/microconf/stage3/07-libelf --- old/pcr-oracle-0.5.6/microconf/stage3/07-libelf 1970-01-01 01:00:00.000000000 +0100 +++ new/pcr-oracle-0.5.7/microconf/stage3/07-libelf 2025-05-29 09:26:41.000000000 +0200 @@ -0,0 +1,6 @@ +################################################################## +# libelf version +################################################################## +if [ -z "$uc_with_libelf" -o "$uc_with_libelf" = "detect" ]; then + uc_pkg_config_check_package libelf +fi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pcr-oracle-0.5.6/microconf/version new/pcr-oracle-0.5.7/microconf/version --- old/pcr-oracle-0.5.6/microconf/version 2025-05-13 08:48:20.000000000 +0200 +++ new/pcr-oracle-0.5.7/microconf/version 2025-05-29 09:26:41.000000000 +0200 @@ -1 +1 @@ -uc_version=0.5.6 +uc_version=0.5.7 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pcr-oracle-0.5.6/src/efi-gpt.c new/pcr-oracle-0.5.7/src/efi-gpt.c --- old/pcr-oracle-0.5.6/src/efi-gpt.c 2025-05-13 08:48:20.000000000 +0200 +++ new/pcr-oracle-0.5.7/src/efi-gpt.c 2025-05-29 09:26:41.000000000 +0200 @@ -39,6 +39,7 @@ static void __tpm_event_efi_gpt_destroy(tpm_parsed_event_t *parsed) { + drop_string(&parsed->efi_gpt_event.sys_partition); drop_string(&parsed->efi_gpt_event.disk_device); } @@ -166,14 +167,14 @@ buffer_t *buffer = NULL; char *device; - if (evspec->efi_partition == NULL) { - error("Cannot determine EFI partition from event log\n"); + if (evspec->sys_partition == NULL) { + error("Cannot determine system partition from event log\n"); /* FIXME: just use the device that holds /boot/efi? */ return NULL; } - if (!(device = runtime_disk_for_partition(evspec->efi_partition))) { - error("Unable to determine disk for partition %s\n", evspec->efi_partition); + if (!(device = runtime_disk_for_partition(evspec->sys_partition))) { + error("Unable to determine disk for partition %s\n", evspec->sys_partition); return NULL; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pcr-oracle-0.5.6/src/efi-variable.c new/pcr-oracle-0.5.7/src/efi-variable.c --- old/pcr-oracle-0.5.6/src/efi-variable.c 2025-05-13 08:48:20.000000000 +0200 +++ new/pcr-oracle-0.5.7/src/efi-variable.c 2025-05-29 09:26:41.000000000 +0200 @@ -371,7 +371,7 @@ var_short_name = parsed->efi_variable_event.variable_name; - if (!strcmp(var_short_name, "db") || !strcmp(var_short_name, "MokListRT")) + if (strcmp(var_short_name, "db") != 0 && strcmp(var_short_name, "MokListRT") != 0) return NULL; parsed_alt = malloc(sizeof(tpm_parsed_event_t)); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pcr-oracle-0.5.6/src/eventlog.c new/pcr-oracle-0.5.7/src/eventlog.c --- old/pcr-oracle-0.5.6/src/eventlog.c 2025-05-13 08:48:20.000000000 +0200 +++ new/pcr-oracle-0.5.7/src/eventlog.c 2025-05-29 09:26:41.000000000 +0200 @@ -1089,6 +1089,8 @@ return true; } +#define GRUB_PREP_ENVBLK "PReP ENV Block" + static bool __tpm_event_parse_ipl(tpm_event_t *ev, tpm_parsed_event_t *parsed, buffer_t *bp) { @@ -1109,8 +1111,12 @@ if (ev->pcr_index == 8) return __tpm_event_grub_command_event_parse(ev, parsed, value); - if (ev->pcr_index == 9) - return __tpm_event_grub_file_event_parse(ev, parsed, value); + if (ev->pcr_index == 9) { + if (strncmp(value, GRUB_PREP_ENVBLK, strlen(GRUB_PREP_ENVBLK)) == 0) + return __tpm_event_grub_envblk_event_parse(ev, parsed, value); + else + return __tpm_event_grub_file_event_parse(ev, parsed, value); + } if (ev->pcr_index == 12) return __tpm_event_systemd_event_parse(ev, parsed, value, len); @@ -1146,6 +1152,9 @@ case TPM2_EFI_GPT_EVENT: return __tpm_event_parse_efi_gpt(ev, parsed, &buf); + + case TPM2_EVENT_COMPACT_HASH: + return __tpm_event_parse_compact_hash(ev, parsed, &buf); } return false; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pcr-oracle-0.5.6/src/eventlog.h new/pcr-oracle-0.5.7/src/eventlog.h --- old/pcr-oracle-0.5.6/src/eventlog.h 2025-05-13 08:48:20.000000000 +0200 +++ new/pcr-oracle-0.5.7/src/eventlog.h 2025-05-29 09:26:41.000000000 +0200 @@ -277,7 +277,7 @@ } shim_event; struct efi_gpt_event { - char * efi_partition; + char * sys_partition; char * disk_device; } efi_gpt_event; @@ -291,6 +291,14 @@ uint32_t event_data_len; char event_data[52]; } tag_event; + + struct compact_hash_event { + char * prep_partition; + } compact_hash_event; + + struct grub_envblk_event { + char * prep_partition; + } grub_envblk_event; }; } tpm_parsed_event_t; @@ -344,4 +352,6 @@ extern bool secure_boot_enabled(); +extern bool __tpm_event_parse_compact_hash(tpm_event_t *, tpm_parsed_event_t *, buffer_t *); +extern bool __tpm_event_grub_envblk_event_parse(tpm_event_t *, tpm_parsed_event_t *, const char *); #endif /* EVENTLOG_H */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pcr-oracle-0.5.6/src/ieee1275-events.c new/pcr-oracle-0.5.7/src/ieee1275-events.c --- old/pcr-oracle-0.5.6/src/ieee1275-events.c 1970-01-01 01:00:00.000000000 +0100 +++ new/pcr-oracle-0.5.7/src/ieee1275-events.c 2025-05-29 09:26:41.000000000 +0200 @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2025 SUSE LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Written by Gary Lin <g...@suse.com> + */ + +#include <stdbool.h> + +#include "bufparser.h" +#include "eventlog.h" +#include "runtime.h" + +/* Process Compact Hash Events */ + +static void +__tpm_event_compact_hash_destroy(tpm_parsed_event_t *parsed) +{ + drop_string(&parsed->compact_hash_event.prep_partition); +} + +static const char * +__tpm_event_compact_hash_describe(const tpm_parsed_event_t *parsed) +{ + return "Compact Hash"; +} + +static const tpm_evdigest_t * +__prep_bootloader_rehash (const struct compact_hash_event *evspec, tpm_event_log_rehash_ctx_t *ctx) +{ + const tpm_evdigest_t *md; + + debug("Computing digest of the bootloader in PReP partition\n"); + if (evspec->prep_partition == NULL) + return NULL; + + md = runtime_digest_prep_booloader(ctx->algo, evspec->prep_partition); + + return md; +} + +static const tpm_evdigest_t * +__tpm_event_compact_hash_rehash(const tpm_event_t *ev, const tpm_parsed_event_t *parsed, tpm_event_log_rehash_ctx_t *ctx) +{ + const struct compact_hash_event *evspec = &parsed->compact_hash_event; + + /* Copy the digest for the normal Compact Hash events */ + if (evspec->prep_partition == NULL) + return tpm_event_get_digest(ev, ctx->algo); + + /* Rehash the bootloader in the PReP partition */ + return __prep_bootloader_rehash(evspec, ctx); +} + +bool +__tpm_event_parse_compact_hash(tpm_event_t *ev, tpm_parsed_event_t *parsed, buffer_t *bp) +{ + struct compact_hash_event *evspec = &parsed->compact_hash_event; + + parsed->destroy = __tpm_event_compact_hash_destroy; + parsed->describe = __tpm_event_compact_hash_describe; + parsed->rehash = __tpm_event_compact_hash_rehash; + + /* Only handle the Compact Hash event with "BOOTLOADER" in the event data */ + if (bp->size != 10 || memcmp(bp->data, "BOOTLOADER", 10) != 0) + return true; + + /* Locate the PReP partition */ + if (!(evspec->prep_partition = runtime_locate_prep_partition())) + return false; + + return true; +} + +/* Process PReP ENV Block */ +static void +__tpm_event_grub_envblk_destroy(tpm_parsed_event_t *parsed) +{ + drop_string(&parsed->grub_envblk_event.prep_partition); +} + +static const char * +__tpm_event_grub_envblk_describe(const tpm_parsed_event_t *parsed) +{ + return "GRUB ENV Block"; +} + +static const tpm_evdigest_t * +__tpm_event_grub_envblk_rehash(const tpm_event_t *ev, const tpm_parsed_event_t *parsed, tpm_event_log_rehash_ctx_t *ctx) +{ + const struct grub_envblk_event *evspec = &parsed->grub_envblk_event; + + if (evspec->prep_partition == NULL) + return NULL; + + return runtime_digest_prep_envblk(ctx->algo, evspec->prep_partition);; +} + +bool +__tpm_event_grub_envblk_event_parse(tpm_event_t *ev, tpm_parsed_event_t *parsed, const char *value) +{ + struct grub_envblk_event *evspec = &parsed->grub_envblk_event; + + parsed->destroy = __tpm_event_grub_envblk_destroy; + parsed->describe = __tpm_event_grub_envblk_describe; + parsed->rehash = __tpm_event_grub_envblk_rehash; + + /* Locate the PReP partition */ + if (!(evspec->prep_partition = runtime_locate_prep_partition())) + return false; + + return true; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pcr-oracle-0.5.6/src/oracle.c new/pcr-oracle-0.5.7/src/oracle.c --- old/pcr-oracle-0.5.6/src/oracle.c 2025-05-13 08:48:20.000000000 +0200 +++ new/pcr-oracle-0.5.7/src/oracle.c 2025-05-29 09:26:41.000000000 +0200 @@ -487,7 +487,7 @@ * Lookahead: when processing the GPT event, we need to know which hard disk * we're talking about. */ -static void +static bool __predictor_lookahead_efi_partition(tpm_event_t *ev, tpm_event_log_rehash_ctx_t *ctx) { struct efi_gpt_event *gpt = &ev->__parsed->efi_gpt_event; @@ -502,7 +502,31 @@ if (!(parsed = ev->__parsed)) continue; - assign_string(&gpt->efi_partition, parsed->efi_bsa_event.efi_partition); + assign_string(&gpt->sys_partition, parsed->efi_bsa_event.efi_partition); + return true; + } + return false; +} + +static void +__predictor_lookahead_prep_partition(tpm_event_t *ev, tpm_event_log_rehash_ctx_t *ctx) +{ + struct efi_gpt_event *gpt = &ev->__parsed->efi_gpt_event; + + while ((ev = ev->next) != NULL) { + tpm_parsed_event_t *parsed; + + if (ev->event_type != TPM2_EVENT_COMPACT_HASH) + continue; + + /* Compact hash events have already been parsed during the pre-scan */ + if (!(parsed = ev->__parsed)) + continue; + + if (!parsed->compact_hash_event.prep_partition) + continue; + + assign_string(&gpt->sys_partition, parsed->compact_hash_event.prep_partition); return; } } @@ -585,6 +609,12 @@ */ TPM2_EFI_GPT_EVENT, + /* + * EVENT_COMPACT_HASH: used by SLOF for PCR4, to measure the bootloader with + * 'BOOTLOADER' in the event data. + */ + TPM2_EVENT_COMPACT_HASH, + -1, }; static int copy_types[] = { @@ -721,9 +751,16 @@ * BOOT_SERVICES event that would tell us which partition we're booting * from. * Scan ahead to the first BSA event to extract the EFI partition. + * + * For PowerPC 64, the firmware measures the bootloader in a Compact + * Hash event instead of a BSA event. If there is no BSA event, we + * go further to look for the Compact Hash event to set the PReP + * partition. */ - if (ev->event_type == TPM2_EFI_GPT_EVENT) - __predictor_lookahead_efi_partition(ev, &rehash_ctx); + if (ev->event_type == TPM2_EFI_GPT_EVENT) { + if (!__predictor_lookahead_efi_partition(ev, &rehash_ctx)) + __predictor_lookahead_prep_partition(ev, &rehash_ctx); + } /* The shim loader emits an event that tells us which certificate it * used to verify the second stage loader. We try to predict that diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pcr-oracle-0.5.6/src/runtime.c new/pcr-oracle-0.5.7/src/runtime.c --- old/pcr-oracle-0.5.6/src/runtime.c 2025-05-13 08:48:20.000000000 +0200 +++ new/pcr-oracle-0.5.7/src/runtime.c 2025-05-29 09:26:41.000000000 +0200 @@ -20,6 +20,9 @@ #include <sys/stat.h> #include <sys/mount.h> +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <string.h> @@ -27,12 +30,23 @@ #include <errno.h> #include <ctype.h> +#include <libelf.h> +#include <libfdisk.h> +#include <linux/cdrom.h> + #include "runtime.h" #include "bufparser.h" #include "digest.h" #include "testcase.h" #include "util.h" +#define PROC_PARTITIONS_PATH "/proc/partitions" +#define SYSFS_BLOCK_PATH "/sys/block" + +#define GPT_PREP_UUID "9E1A2D38-C612-4316-AA26-8B49521E5A8B" +#define DOS_PREP_TYPE 0x41 + + struct file_locator { char * partition; char * relative_path; @@ -290,6 +304,432 @@ return result; } +static bool +is_parent_block(char *blkname) +{ + char buf[PATH_MAX]; + struct stat f_stat; + + /* Check /sys/block/<blkname>/dev */ + snprintf(buf, PATH_MAX, "%s/%s/dev", SYSFS_BLOCK_PATH, blkname); + + return (stat(buf, &f_stat) == 0); +} + +#ifdef CDROM_GET_CAPABILITY +static bool +blkdev_is_cdrom(int fd) +{ + int ret; + + if ((ret = ioctl(fd, CDROM_GET_CAPABILITY, NULL)) < 0) + return false; + + return !!ret; +} +#else +static bool +blkdev_is_cdrom(int fd __attribute__((__unused__))) +{ + return false; +} +#endif + +static bool +is_cdrom_or_tape(char *device) +{ + int fd; + bool ret; + + if ((fd = open(device, O_RDONLY|O_NONBLOCK)) < 0) + return 0; + ret = blkdev_is_cdrom(fd); + + close(fd); + return ret; +} + +static char * +next_proc_partition (FILE **f) +{ + char line[128 + 1]; + char buf[PATH_MAX]; + char devpath[PATH_MAX]; + + if (!*f) { + *f = fopen(PROC_PARTITIONS_PATH, "r"); + if (!*f) { + fprintf(stderr, "cannot open %s", PROC_PARTITIONS_PATH); + return NULL; + } + } + + /* + * Example of /proc/partitions + * + * major minor #blocks name + * + * 8 0 41943040 sda + * 8 1 8192 sda1 + * 8 2 41933807 sda2 + * 254 0 41917423 dm-0 + */ + while (fgets(line, sizeof(line), *f)) { + if (sscanf(line, " %*d %*d %*d %128[^\n ]", buf) != 1) + continue; + + /* The partition table is only available to the parent block device */ + if (!is_parent_block(buf)) + continue; + + if (snprintf(devpath, PATH_MAX, "/dev/%s", buf) < 0) + return NULL; + + if (!is_cdrom_or_tape(devpath)) + return strdup(devpath); + } + fclose(*f); + *f = NULL; + + return NULL; +} + +static int +is_prep_partition(struct fdisk_parttype *ptype, int is_gpt) +{ + const char *typestr; + + if (is_gpt) { + typestr = fdisk_parttype_get_string(ptype); + return !!(strcmp(typestr, GPT_PREP_UUID) == 0); + } else { + return !!(fdisk_parttype_get_code(ptype) == DOS_PREP_TYPE); + } + return 0; +} + +static char * +locate_prep_partition_real(char *devname) +{ + struct fdisk_context *cxt = NULL; + struct fdisk_table *tb = NULL; + struct fdisk_iter *itr = NULL; + struct fdisk_partition *part = NULL; + struct fdisk_parttype *ptype = NULL; + int is_gpt = 0; + char *prep_dev = NULL; + + cxt = fdisk_new_context(); + + if (fdisk_assign_device(cxt, devname, 1) < 0) + goto done; + + /* PReP partition only in GPT or MBR */ + if (fdisk_is_labeltype(cxt, FDISK_DISKLABEL_GPT) == 1) + is_gpt = 1; + else if (fdisk_is_labeltype(cxt, FDISK_DISKLABEL_DOS) == 1) + is_gpt = 0; + else + goto done; + + if (fdisk_get_partitions(cxt, &tb) || fdisk_table_get_nents(tb) <= 0) + goto done; + + itr = fdisk_new_iter(FDISK_ITER_FORWARD); + if (itr == NULL) { + error("failed to allocate fdisk iterator\n"); + goto done; + } + + /* Go through the partitions to find PReP partition */ + while (fdisk_table_next_partition(tb, itr, &part) == 0) { + ptype = fdisk_partition_get_type(part); + if (ptype == NULL) + continue; + + if (!is_prep_partition(ptype, is_gpt)) + continue; + + fdisk_partition_to_string(part, cxt, + FDISK_FIELD_DEVICE, + &prep_dev); + break; + } +done: + if (itr) + fdisk_free_iter(itr); + if (tb) + fdisk_unref_table(tb); + fdisk_unref_context(cxt); + + return prep_dev; +} + +char * +runtime_locate_prep_partition(void) +{ + static char prep_dev[PATH_MAX]; + FILE *f = NULL; + char *devname = NULL; + char *prep_tmp = NULL; + + if (testcase_playback) + return testcase_playback_prep_partition(testcase_playback); + + if (prep_dev[0] != '\0') + return strdup(prep_dev); + + while ((devname = next_proc_partition(&f))) { + prep_tmp = locate_prep_partition_real(devname); + free(devname); + + if (prep_tmp != NULL) { + snprintf(prep_dev, PATH_MAX, "%s", prep_tmp); + break; + } + } + + if (testcase_recording) + testcase_record_prep_partition(testcase_recording, prep_tmp); + return prep_tmp; +} + +static int +calculate_elf32_size(Elf *elf, size_t max_size, size_t *result) +{ + Elf32_Ehdr *ehdr = NULL; + Elf32_Phdr *phdrs = NULL, *phdr = NULL; + Elf_Scn *scn = NULL; + Elf32_Shdr *shdr = NULL; + size_t elf_size = 0; + int i; + + if (result == NULL) + return -1; + + if ((ehdr = elf32_getehdr(elf)) == NULL) + return -1; + + elf_size = ehdr->e_phoff; + phdrs = elf32_getphdr(elf); + if (phdrs == NULL) + return -1; + + for (i = 0; i < ehdr->e_phnum; i++) { + phdr = phdrs + i; + + elf_size = MAX(phdr->p_offset + phdr->p_filesz, elf_size); + if (elf_size > max_size) + return -1; + } + + for (i = 0; i < ehdr->e_shnum; i++) { + if ((scn = elf_getscn(elf, i)) == NULL) + return -1; + if ((shdr = elf32_getshdr(scn)) == NULL) + return -1; + + elf_size = MAX(shdr->sh_offset + shdr->sh_size, elf_size); + if (elf_size > max_size) + return -1; + } + + *result = elf_size; + + return 0; +} + +static int +calculate_elf64_size(Elf *elf, size_t max_size, size_t *result) +{ + Elf64_Ehdr *ehdr = NULL; + Elf64_Phdr *phdrs = NULL, *phdr = NULL; + Elf_Scn *scn = NULL; + Elf64_Shdr *shdr = NULL; + size_t elf_size = 0; + int i; + + if (result == NULL) + return -1; + + if ((ehdr = elf64_getehdr(elf)) == NULL) + return -1; + + elf_size = ehdr->e_phoff; + phdrs = elf64_getphdr(elf); + if (phdrs == NULL) + return -1; + + for (i = 0; i < ehdr->e_phnum; i++) { + phdr = phdrs + i; + + elf_size = MAX(phdr->p_offset + phdr->p_filesz, elf_size); + if (elf_size > max_size) + return -1; + } + + for (i = 0; i < ehdr->e_shnum; i++) { + if ((scn = elf_getscn(elf, i)) == NULL) + return -1; + if ((shdr = elf64_getshdr(scn)) == NULL) + return -1; + + elf_size = MAX(shdr->sh_offset + shdr->sh_size, elf_size); + if (elf_size > max_size) + return -1; + } + + *result = elf_size; + + return 0; +} + +static int +prep_bootloader_size (block_dev_io_t *prep_io, size_t *result) +{ + buffer_t *buffer = NULL; + Elf *elf = NULL; + size_t part_size = 0; + size_t elf_size; + int ret = -1; + + if (result == NULL) + return -1; + + part_size = lseek(prep_io->fd, 0, SEEK_END); + + /* The first two blocks (1KB) should be enough to cover all the ELF + * headers (ELF headers, program headers, and section headers). */ + if ((buffer = runtime_blockdev_read_lba(prep_io, 0, 2)) == NULL) { + error("Unable to read the first two blocks\n"); + goto failed; + } + + /* Read the ELF structure */ + if ((elf = elf_memory((char *)buffer->data, buffer->size)) == NULL) { + error("Failed to initialize Elf\n"); + goto failed; + } + + if (elf32_getehdr(elf) != NULL) { + ret = calculate_elf32_size(elf, part_size, &elf_size); + } else if (elf64_getehdr(elf) != NULL) { + ret = calculate_elf64_size(elf, part_size, &elf_size); + } else { + error("invalid ELF header\n"); + goto failed; + } + + if (ret < 0) { + error("Failed get ELF size\n"); + goto failed; + } + + /* Follow SLOF to round up the size */ + elf_size = roundup(elf_size, 4); + + *result = elf_size; + + ret = 0; +failed: + if (buffer) + buffer_free(buffer); + if (elf) + elf_end(elf); + + return ret; +} + +const tpm_evdigest_t * +runtime_digest_prep_booloader(const tpm_algo_info_t *algo, const char *prep_partition) +{ + buffer_t *buffer = NULL; + block_dev_io_t *prep_io; + size_t bootloader_size = 0; + unsigned int nsector; + const tpm_evdigest_t *md = NULL; + + if ((prep_io = runtime_blockdev_open(prep_partition)) == NULL) { + error("Unable to open disk device %s: %m\n", prep_partition); + goto failed; + } + + if (prep_bootloader_size(prep_io, &bootloader_size) < 0) { + error("%s: unable to get bootloader size\n", prep_partition); + goto failed; + } + + nsector = runtime_blockdev_bytes_to_sectors(prep_io, bootloader_size); + + if ((buffer = runtime_blockdev_read_lba(prep_io, 0, nsector)) == NULL) { + error("%s: unable to read the full bootloader\n", prep_partition); + goto failed; + } + + md = digest_compute(algo, buffer->data, bootloader_size); + +failed: + if (prep_io >= 0) + runtime_blockdev_close(prep_io); + if (buffer) + buffer_free(buffer); + + return md; +} + + +#define GRUB_ENVBLK_SIGNATURE "# GRUB Environment Block\n" +#define GRUB_ENVBLK_SIZE 4096 + +const tpm_evdigest_t * +runtime_digest_prep_envblk(const tpm_algo_info_t *algo, const char *prep_partition) +{ + buffer_t *buffer = NULL; + block_dev_io_t *io; + size_t nsector, start; + off_t part_size; + const tpm_evdigest_t *md = NULL; + + if ((io = runtime_blockdev_open(prep_partition)) == NULL) { + error("Unable to open disk device %s: %m\n", prep_partition); + goto failed; + } + + if ((part_size = lseek(io->fd, 0, SEEK_END)) < 0) { + error("block dev seek: %m\n"); + goto failed; + } + + /* read the last 4096 bytes */ + if (part_size < GRUB_ENVBLK_SIZE) { + error("insufficient partition size\n"); + goto failed; + } + + start = runtime_blockdev_bytes_to_sectors(io, part_size - GRUB_ENVBLK_SIZE); + nsector = runtime_blockdev_bytes_to_sectors(io, GRUB_ENVBLK_SIZE); + + if ((buffer = runtime_blockdev_read_lba(io, start, nsector)) == NULL) { + error("%s: unable to read envblk\n", prep_partition); + goto failed; + } + + if (memcmp(buffer->data, GRUB_ENVBLK_SIGNATURE, strlen(GRUB_ENVBLK_SIGNATURE)) != 0) { + error("%s: invalid envblk signature\n", prep_partition); + goto failed; + } + + md = digest_compute(algo, buffer->data, GRUB_ENVBLK_SIZE); + +failed: + if (io >= 0) + runtime_blockdev_close(io); + if (buffer) + buffer_free(buffer); + + return md; +} + char * runtime_disk_for_partition(const char *part_dev) { @@ -398,14 +838,14 @@ free(io); } -unsigned int -runtime_blockdev_bytes_to_sectors(const block_dev_io_t *io, unsigned int size) +size_t +runtime_blockdev_bytes_to_sectors(const block_dev_io_t *io, size_t size) { return (size + io->sector_size - 1) / io->sector_size; } buffer_t * -runtime_blockdev_read_lba(block_dev_io_t *io, unsigned int block, unsigned int count) +runtime_blockdev_read_lba(block_dev_io_t *io, size_t block, size_t count) { unsigned long offset = block * io->sector_size; unsigned int bytes; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pcr-oracle-0.5.6/src/runtime.h new/pcr-oracle-0.5.7/src/runtime.h --- old/pcr-oracle-0.5.6/src/runtime.h 2025-05-13 08:48:20.000000000 +0200 +++ new/pcr-oracle-0.5.7/src/runtime.h 2025-05-29 09:26:41.000000000 +0200 @@ -40,13 +40,16 @@ extern buffer_t * runtime_read_efi_application(const char *partition, const char *application); extern const tpm_evdigest_t *runtime_digest_efi_file(const tpm_algo_info_t *algo, const char *path); extern const tpm_evdigest_t *runtime_digest_rootfs_file(const tpm_algo_info_t *algo, const char *path); +extern char * runtime_locate_prep_partition(void); +extern const tpm_evdigest_t *runtime_digest_prep_booloader(const tpm_algo_info_t *algo, const char *prep_partition); +extern const tpm_evdigest_t *runtime_digest_prep_envblk(const tpm_algo_info_t *algo, const char *prep_partition); extern char * runtime_disk_for_partition(const char *part_dev); extern char * runtime_blockdev_by_partuuid(const char *uuid); extern block_dev_io_t * runtime_blockdev_open(const char *dev); -extern buffer_t * runtime_blockdev_read_lba(block_dev_io_t *, unsigned int block, unsigned int count); +extern buffer_t * runtime_blockdev_read_lba(block_dev_io_t *, size_t block, size_t count); extern void runtime_blockdev_close(block_dev_io_t *); -extern unsigned int runtime_blockdev_bytes_to_sectors(const block_dev_io_t *, unsigned int size); +extern size_t runtime_blockdev_bytes_to_sectors(const block_dev_io_t *, size_t size); extern void runtime_record_testcase(testcase_t *); extern void runtime_replay_testcase(testcase_t *); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pcr-oracle-0.5.6/src/testcase.c new/pcr-oracle-0.5.7/src/testcase.c --- old/pcr-oracle-0.5.6/src/testcase.c 2025-05-13 08:48:20.000000000 +0200 +++ new/pcr-oracle-0.5.7/src/testcase.c 2025-05-29 09:26:41.000000000 +0200 @@ -42,6 +42,7 @@ char * partition_directory; char * disk_directory; char * hash_log; + char * prep_partition; FILE * hash_log_fp; }; @@ -189,7 +190,8 @@ fatal("Cannot read symlink %s: %m\n", path); if (target[0] != '/' && default_dir) { - snprintf(result, sizeof(result), "%s/%s", default_dir, target); + if (snprintf(result, sizeof(result), "%s/%s", default_dir, target) < 0) + return NULL; return strdup(result); } @@ -599,3 +601,38 @@ { return testcase_playback_digest(tc, "efi", path, algo); } + +void +testcase_record_prep_partition(testcase_t *tc, const char *path) +{ + int fd; + + if ((fd = testcase_create_file(tc->base_directory, "prep_partition")) < 0) + fatal("Failed to create PReP partition recording file: %m\n"); + + if (write(fd, path, strlen(path) + 1) < 0) + fatal("Failed to record PReP partition: %m\n"); + + close(fd); +} + +char * +testcase_playback_prep_partition(testcase_t *tc) +{ + int fd; + char buf[PATH_MAX]; + ssize_t count; + + if ((fd = testcase_open_file(tc->base_directory, "prep_partition")) < 0) + return NULL; + + count = read(fd, buf, PATH_MAX - 1); + if (count < 0) + fatal("failed to read prep_partition: %m\n"); + + buf[count+1] = '\0'; + + close(fd); + + return strdup(buf); +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pcr-oracle-0.5.6/src/testcase.h new/pcr-oracle-0.5.7/src/testcase.h --- old/pcr-oracle-0.5.6/src/testcase.h 2025-05-13 08:48:20.000000000 +0200 +++ new/pcr-oracle-0.5.7/src/testcase.h 2025-05-29 09:26:41.000000000 +0200 @@ -47,6 +47,8 @@ extern const tpm_evdigest_t * testcase_playback_rootfs_digest(testcase_t *, const char *path, const tpm_algo_info_t *algo); extern void testcase_record_efi_digest(testcase_t *, const char *path, const tpm_evdigest_t *md); extern const tpm_evdigest_t * testcase_playback_efi_digest(testcase_t *, const char *path, const tpm_algo_info_t *algo); +extern void testcase_record_prep_partition(testcase_t *, const char *path); +extern char * testcase_playback_prep_partition(testcase_t *); #include <stdio.h>