diff --git a/contrib/initramfs/scripts/zfs b/contrib/initramfs/scripts/zfs index 8d54f16bb16b..55de6be1c4dc 100644 --- a/contrib/initramfs/scripts/zfs +++ b/contrib/initramfs/scripts/zfs @@ -345,7 +345,7 @@ mount_fs() # Need the _original_ datasets mountpoint! mountpoint=$(get_fs_value "$fs" mountpoint) - ZFS_CMD="mount -o zfsutil -t zfs" + ZFS_CMD="mount.zfs -o zfsutil" if [ "$mountpoint" = "legacy" ] || [ "$mountpoint" = "none" ]; then # Can't use the mountpoint property. Might be one of our # clones. Check the 'org.zol:mountpoint' property set in @@ -362,7 +362,7 @@ mount_fs() fi # Don't use mount.zfs -o zfsutils for legacy mountpoint if [ "$mountpoint" = "legacy" ]; then - ZFS_CMD="mount -t zfs" + ZFS_CMD="mount.zfs" fi # Last hail-mary: Hope 'rootmnt' is set! mountpoint="" diff --git a/module/os/linux/zfs/zfs_ctldir.c b/module/os/linux/zfs/zfs_ctldir.c index e042116333fb..811c0b466e77 100644 --- a/module/os/linux/zfs/zfs_ctldir.c +++ b/module/os/linux/zfs/zfs_ctldir.c @@ -1049,6 +1049,61 @@ exportfs_flush(void) (void) call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC); } +static int +get_current_root_path(char *buff, int len) +{ + struct path path; + char *path_buffer, *path_ptr; + int path_len, error = 0; + + get_fs_root(current->fs, &path); + path_get(&path); + + path_buffer = kmem_zalloc(len, KM_SLEEP); + + path_ptr = d_path(&path, path_buffer, len); + if (IS_ERR(path_ptr)) { + error = -PTR_ERR(path_ptr); + goto out; + } + + path_len = path_buffer + len - 1 - path_ptr; + if (path_len > len) { + error = SET_ERROR(EFAULT); + goto out; + } + + memcpy(buff, path_ptr, path_len); + buff[path_len] = '\0'; +out: + kmem_free(path_buffer, len); + path_put(&path); + return (error); +} + +static int +is_current_chrooted(void) +{ + struct task_struct *curr = current, *global = &init_task; + struct path gl_root; + struct path cr_root; + int chrooted; + + get_fs_root(global->fs, &gl_root); + path_get(&gl_root); + while (d_mountpoint(gl_root.dentry) && follow_down_one(&gl_root)) + ; + + get_fs_root(curr->fs, &cr_root); + path_get(&cr_root); + chrooted = !path_equal(&cr_root, &gl_root); + + path_put(&cr_root); + path_put(&gl_root); + + return (chrooted); +} + /* * Attempt to unmount a snapshot by making a call to user space. * There is no assurance that this can or will succeed, is just a @@ -1100,7 +1155,7 @@ zfsctl_snapshot_mount(struct path *path, int flags) zfsvfs_t *zfsvfs; zfsvfs_t *snap_zfsvfs; zfs_snapentry_t *se; - char *full_name, *full_path; + char *full_name, *full_path, *root_path; char *argv[] = { "/usr/bin/env", "mount", "-i", "-t", "zfs", "-n", NULL, NULL, NULL }; char *envp[] = { NULL }; @@ -1116,12 +1171,30 @@ zfsctl_snapshot_mount(struct path *path, int flags) full_name = kmem_zalloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP); full_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); + root_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); error = zfsctl_snapshot_name(zfsvfs, dname(dentry), ZFS_MAX_DATASET_NAME_LEN, full_name); if (error) goto error; + if (get_current_root_path(root_path, MAXPATHLEN) == 0) { + if (is_current_chrooted() == 0) { + zfs_dbgmsg("current process is not chrooted"); + if (zfsvfs->z_vfs->vfs_mntpoint != NULL && + strcmp(zfsvfs->z_vfs->vfs_mntpoint, "/root") == 0 && + strcmp(root_path, "/") == 0) { + zfs_dbgmsg("zfsvfs->z_vfs->vfs_mntpoint is /root"); + zfs_dbgmsg("d_path returns / for current fs root"); + zfs_dbgmsg("this is propbably root filesystem"); + zfs_dbgmsg("setting zfsvfs->z_vfs->vfs_mntpoint to /"); + strcpy(zfsvfs->z_vfs->vfs_mntpoint, ""); + } + } else if (is_current_chrooted()) { + zfs_dbgmsg("Current process is in chroot context"); + } + } + /* * Construct a mount point path from sb of the ctldir inode and dirent * name, instead of from d_path(), so that chroot'd process doesn't fail