aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--stand/efi/boot1/zfs_module.c5
-rw-r--r--stand/libsa/zfs/zfs.c8
-rw-r--r--stand/libsa/zfs/zfsimpl.c54
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);