diff options
| -rw-r--r-- | stand/efi/boot1/zfs_module.c | 5 | ||||
| -rw-r--r-- | stand/libsa/zfs/zfs.c | 8 | ||||
| -rw-r--r-- | 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); |
