From nobody Fri Sep 04 18:49:14 2026 X-Original-To: dev-commits-src-branches@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4hc59656GSz6r5l7 for ; Fri, 04 Sep 2026 18:49:14 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR2" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4hc5961WMqz3C1M for ; Fri, 04 Sep 2026 18:49:14 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1788547754; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=qO+1R9+tq8BPyuOCVB9ndCqFyKrhUwP6pMAEVLKopnY=; b=EvXnsTz7+/KG4um7H2I9/Ll+HIl1tXnld9KybHzI11YrSXcZFC5GVwRwfZwydbIWPv40lT 5lqS6miXeoM9ctnteCG66FZ6tpNKClupjcaTkcx32iy2eT6HwlufEk+/fRpK4nl5XDTKRr OcG/z39jiqxA70RmJsfJ9xlort9o/LwatXHdMN2FkYUkwH81b4eI0PbZsysPxB+ALHOJFo DqOfynjSNaQvRimNEfV+bSxvJkPrpvTWIr7+ACS3nEWU3S4kRUnfpBBb1x2xLa4+6Uj4jY RALdpTdP4rgas8vKaQ62j43Ikutt9gwog89d1fS0dnrDe8NkH1B/pUYFurqVig== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1788547754; a=rsa-sha256; cv=none; b=IlI5rzwEIXlWAPBMJjzUFkoUU6c1o82KoAEiGjUw9QlBGkCtOGWbhibSijqIuE0WU6eRNK B9oQe9P3EvnSt1g1cTaAK7DC9W6j/WoggkLTG84mE41pGJkA0vd307+FUECHKUaBT/PEFP VlHLMrFoi2dQmtHG7GDa4mZnjBwluSzdS8LItOfpTvB5J+/KLxKg1NgftBl6QN/KYJGlDL LxOG9ubM9mEJGGl4pv+LXJVtxz/6fWyg8n2vvv9hOe6IUD2PLsaFet1nRI35EGzU9Ggq3a 0JHukQisYvvITp1jl5Zc9/UlkMQCMYKq/S0uARSlV6dKLki9/SKeskgoYzK6bg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1788547754; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=qO+1R9+tq8BPyuOCVB9ndCqFyKrhUwP6pMAEVLKopnY=; b=aGSc3BstgtusUmQMLmwfgWwBhOWJd6y1n7qfzVwzerUgjrLfFeJQMDXA8UxCjLxy2fEzbf i3z/1BArhHIj/9wWdwoxNgPOX173rpNsbdUD+BdlgCEdD6S7yZlyFOiPYN5vxO3L+CxxX/ 7P+DB83OIdxF3Vl9BjDTBLz7s81K8D6JUbR/5jpGtqsePTlJXWGXP9qtbiQCqXsg0EKvXw I84Y7r9SEtVejSZjucC9S1sM/Wn621oRkxfhw7Zf9kpdUbqCNGIdGt5TvKDUZCwEIIYr70 2ImYbSBWIUvcoSamYCY5UJa4cYRZdxIFV5LQXzZfmiXmlMEOzMjpe4oRQjMaYA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hc5960Qf9z1B9l for ; Fri, 04 Sep 2026 18:49:14 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 21941 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Fri, 04 Sep 2026 18:49:14 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org Cc: Etienne Bonnand From: Kyle Evans Subject: git: 6b1371fca772 - stable/15 - stand: set st_dev/st_ino in the loader's ZFS stat for veriexec List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-branches@freebsd.org Sender: owner-dev-commits-src-branches@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kevans X-Git-Repository: src X-Git-Refname: refs/heads/stable/15 X-Git-Reftype: branch X-Git-Commit: 6b1371fca772dd4583e2ba257b3237bad8c57cab Auto-Submitted: auto-generated Date: Fri, 04 Sep 2026 18:49:14 +0000 Message-Id: <6a9b12aa.21941.73b664e4@gitrepo.freebsd.org> The branch stable/15 has been updated by kevans: URL: https://cgit.FreeBSD.org/src/commit/?id=6b1371fca772dd4583e2ba257b3237bad8c57cab commit 6b1371fca772dd4583e2ba257b3237bad8c57cab Author: Etienne Bonnand AuthorDate: 2026-06-18 16:37:31 +0000 Commit: Kyle Evans CommitDate: 2026-09-04 15:33:04 +0000 stand: set st_dev/st_ino in the loader's ZFS stat for veriexec The loader's ZFS implementation never set st_dev or st_ino in zfs_dnode_stat(). With an uninitialized struct stat, veriexec's device comparison in lib/libsecureboot/veopen.c read stack garbage and skipped the matching manifest entry, failing with a spurious "no entry" on ZFS root under UEFI Secure Boot. Rather than zeroing the device (which would break veriexec's ability to tell apart the same path on different datasets), populate st_dev and st_ino with the same intrinsic identifiers the kernel uses: - st_dev = the dataset's ds_fsid_guid (as the kernel does via dmu_objset_fsid_guid()/dsl_dataset_fsid_guid()), already read in zfs_mount_dataset() and now propagated through struct zfsmount. - st_ino = the object number resolved in zfs_lookup(), propagated through struct file (the loader's equivalent of the kernel's z_id). dev_t and ino_t are 64-bit on FreeBSD, so both are assigned directly with no hashing. A memset() at the top of zfs_dnode_stat() zeroes the remaining fields so they no longer hold stack garbage. Tested on 16.0-CURRENT (amd64), ZFS-on-GELI root: rebuilt and re-signed the EFI loader; the system boots under UEFI Secure Boot with mac_veriexec active. (boot1 segment was modified by kevans) PR: 295935 Sponsored by: Defenso Reviewed-by: kevans Pull-Request: https://github.com/freebsd/freebsd-src/pull/2271 (cherry picked from commit b567434a592e1a35b20c5a39c4ccc2ea9e00601d) --- stand/efi/boot1/zfs_module.c | 5 ++-- stand/libsa/zfs/zfs.c | 8 ++++--- stand/libsa/zfs/zfsimpl.c | 54 +++++++++++++++++++++++++++++++++++++++----- 3 files changed, 56 insertions(+), 11 deletions(-) diff --git a/stand/efi/boot1/zfs_module.c b/stand/efi/boot1/zfs_module.c index 16722b33f0b9..261753a7acfe 100644 --- a/stand/efi/boot1/zfs_module.c +++ b/stand/efi/boot1/zfs_module.c @@ -205,7 +205,7 @@ load(const char *filepath, dev_info_t *devinfo, void **bufp, size_t *bufsize) return (EFI_NOT_FOUND); } - if ((err = zfs_lookup(&zmount, filepath, &dn)) != 0) { + if ((err = zfs_lookup(&zmount, filepath, &dn, NULL)) != 0) { if (err == ENOENT) { DPRINTF("Failed to find '%s' on pool '%s' (%d)\n", filepath, spa->spa_name, err); @@ -216,7 +216,8 @@ load(const char *filepath, dev_info_t *devinfo, void **bufp, size_t *bufsize) return (EFI_INVALID_PARAMETER); } - if ((err = zfs_dnode_stat(spa, &dn, &st)) != 0) { + /* Only st_size is inspected here, so identity is irrelevant. */ + if ((err = zfs_dnode_stat(spa, &dn, &st, 0, 0)) != 0) { printf("Failed to stat '%s' on pool '%s' (%d)\n", filepath, spa->spa_name, err); return (EFI_INVALID_PARAMETER); diff --git a/stand/libsa/zfs/zfs.c b/stand/libsa/zfs/zfs.c index 70a102f6425d..2784c0afd412 100644 --- a/stand/libsa/zfs/zfs.c +++ b/stand/libsa/zfs/zfs.c @@ -85,6 +85,7 @@ struct fs_ops zfs_fsops = { struct file { off_t f_seekp; /* seek pointer */ dnode_phys_t f_dnode; + uint64_t f_objnum; /* object number (st_ino) */ uint64_t f_zap_type; /* zap type for readdir */ uint64_t f_num_leafs; /* number of fzap leaf blocks */ zap_leaf_phys_t *f_zap_leaf; /* zap leaf buffer */ @@ -120,7 +121,7 @@ zfs_open(const char *upath, struct open_file *f) return (ENOMEM); f->f_fsdata = fp; - rc = zfs_lookup(mount, upath, &fp->f_dnode); + rc = zfs_lookup(mount, upath, &fp->f_dnode, &fp->f_objnum); fp->f_seekp = 0; if (rc) { f->f_fsdata = NULL; @@ -214,10 +215,11 @@ static int zfs_stat(struct open_file *f, struct stat *sb) { struct devdesc *dev = f->f_devdata; - const spa_t *spa = ((struct zfsmount *)dev->d_opendata)->spa; + struct zfsmount *zm = dev->d_opendata; struct file *fp = (struct file *)f->f_fsdata; - return (zfs_dnode_stat(spa, &fp->f_dnode, sb)); + return (zfs_dnode_stat(zm->spa, &fp->f_dnode, sb, zm->fsid_guid, + fp->f_objnum)); } static int diff --git a/stand/libsa/zfs/zfsimpl.c b/stand/libsa/zfs/zfsimpl.c index e5920004bd9d..b6d14090fc76 100644 --- a/stand/libsa/zfs/zfsimpl.c +++ b/stand/libsa/zfs/zfsimpl.c @@ -48,6 +48,7 @@ struct zfsmount { const spa_t *spa; objset_phys_t objset; uint64_t rootobj; + uint64_t fsid_guid; /* mount's ds_fsid_guid */ STAILQ_ENTRY(zfsmount) next; }; @@ -3433,7 +3434,8 @@ done: * and return its details in *objset */ static int -zfs_mount_dataset(const spa_t *spa, uint64_t objnum, objset_phys_t *objset) +zfs_mount_dataset(const spa_t *spa, uint64_t objnum, objset_phys_t *objset, + uint64_t *fsid_guid) { dnode_phys_t dataset; dsl_dataset_phys_t *ds; @@ -3450,6 +3452,17 @@ zfs_mount_dataset(const spa_t *spa, uint64_t objnum, objset_phys_t *objset) return (EIO); } + /* + * Capture the dataset's intrinsic on-disk identifier so callers can + * expose it as st_dev (matches the kernel, which derives the fsid from + * dmu_objset_fsid_guid()/ds_fsid_guid). ds_fsid_guid is a 56-bit ID + * that may change to avoid collisions; ds_guid is a never-changing + * 64-bit ID and would be the alternative if absolute stability over + * time were required -- to be decided in review. + */ + if (fsid_guid != NULL) + *fsid_guid = ds->ds_fsid_guid; + return (0); } @@ -3518,7 +3531,8 @@ zfs_mount_impl(const spa_t *spa, uint64_t rootobj, struct zfsmount *mount) return (EIO); } - if (zfs_mount_dataset(spa, rootobj, &mount->objset)) { + if (zfs_mount_dataset(spa, rootobj, &mount->objset, + &mount->fsid_guid)) { printf("ZFS: can't open root filesystem\n"); return (EIO); } @@ -3703,9 +3717,17 @@ zfs_spa_init(spa_t *spa) } static int -zfs_dnode_stat(const spa_t *spa, dnode_phys_t *dn, struct stat *sb) +zfs_dnode_stat(const spa_t *spa, dnode_phys_t *dn, struct stat *sb, + uint64_t fsid_guid, uint64_t objnum) { + /* + * Zero the whole struct first so fields this function does not fill + * (st_nlink, timestamps, st_blocks, ...) hold 0 rather than stack + * garbage. st_dev/st_ino are then overwritten with real values below. + */ + memset(sb, 0, sizeof(*sb)); + if (dn->dn_bonustype != DMU_OT_SA) { znode_phys_t *zp = (znode_phys_t *)dn->dn_bonus; @@ -3754,6 +3776,15 @@ zfs_dnode_stat(const spa_t *spa, dnode_phys_t *dn, struct stat *sb) free(buf); } + /* + * Populate the identity fields used by veriexec to tell apart the same + * path on different datasets/filesystems. dev_t and ino_t are 64-bit + * on FreeBSD, so the dataset GUID and object number fit directly with + * no hashing or truncation. + */ + sb->st_dev = (dev_t)fsid_guid; + sb->st_ino = (ino_t)objnum; + return (0); } @@ -3818,7 +3849,8 @@ struct obj_list { * Lookup a file and return its dnode. */ static int -zfs_lookup(const struct zfsmount *mount, const char *upath, dnode_phys_t *dnode) +zfs_lookup(const struct zfsmount *mount, const char *upath, + dnode_phys_t *dnode, uint64_t *objnum_out) { int rc; uint64_t objnum; @@ -3904,7 +3936,8 @@ zfs_lookup(const struct zfsmount *mount, const char *upath, dnode_phys_t *dnode) element[q - p] = 0; p = q; - if ((rc = zfs_dnode_stat(spa, &dn, &sb)) != 0) + /* Only st_mode is inspected here, so identity is irrelevant. */ + if ((rc = zfs_dnode_stat(spa, &dn, &sb, 0, 0)) != 0) goto done; if (!S_ISDIR(sb.st_mode)) { rc = ENOTDIR; @@ -3929,7 +3962,8 @@ zfs_lookup(const struct zfsmount *mount, const char *upath, dnode_phys_t *dnode) /* * Check for symlink. */ - rc = zfs_dnode_stat(spa, &dn, &sb); + /* Only st_mode is inspected here, so identity is irrelevant. */ + rc = zfs_dnode_stat(spa, &dn, &sb, 0, 0); if (rc) goto done; if (S_ISLNK(sb.st_mode)) { @@ -3976,6 +4010,14 @@ zfs_lookup(const struct zfsmount *mount, const char *upath, dnode_phys_t *dnode) } *dnode = dn; + /* + * objnum tracks the object number of the dnode we just resolved (the + * loader's equivalent of the kernel's z_id/db_object); hand it back so + * the file can expose it as st_ino. Callers that do not need it pass + * NULL. + */ + if (objnum_out != NULL) + *objnum_out = objnum; done: STAILQ_FOREACH_SAFE(entry, &on_cache, entry, tentry) free(entry);