Support idmapped mount

Adds support for idmapped mounts.  Supported as of Linux 5.12 this 
functionality allows user and group IDs to be remapped without changing 
their state on disk.  This can be useful for portable home directories
and a variety of container related use cases.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Ryan Moeller <ryan@iXsystems.com>
Signed-off-by: Youzhong Yang <yyang@mathworks.com>
Closes #12923
Closes #13671
This commit is contained in:
youzhongyang
2022-10-19 14:17:09 -04:00
committed by GitHub
parent eaaed26ffb
commit 2a068a1394
41 changed files with 1636 additions and 166 deletions
+10 -2
View File
@@ -378,7 +378,9 @@ nobase_dist_datadir_zfs_tests_tests_DATA += \
functional/zvol/zvol_common.shlib \
functional/zvol/zvol_ENOSPC/zvol_ENOSPC.cfg \
functional/zvol/zvol_misc/zvol_misc_common.kshlib \
functional/zvol/zvol_swap/zvol_swap.cfg
functional/zvol/zvol_swap/zvol_swap.cfg \
functional/idmap_mount/idmap_mount.cfg \
functional/idmap_mount/idmap_mount_common.kshlib
nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/acl/off/cleanup.ksh \
@@ -1998,4 +2000,10 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/zvol/zvol_swap/zvol_swap_003_pos.ksh \
functional/zvol/zvol_swap/zvol_swap_004_pos.ksh \
functional/zvol/zvol_swap/zvol_swap_005_pos.ksh \
functional/zvol/zvol_swap/zvol_swap_006_pos.ksh
functional/zvol/zvol_swap/zvol_swap_006_pos.ksh \
functional/idmap_mount/cleanup.ksh \
functional/idmap_mount/setup.ksh \
functional/idmap_mount/idmap_mount_001.ksh \
functional/idmap_mount/idmap_mount_002.ksh \
functional/idmap_mount/idmap_mount_003.ksh \
functional/idmap_mount/idmap_mount_004.ksh
+25
View File
@@ -0,0 +1,25 @@
#!/bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
. $STF_SUITE/include/libtest.shlib
default_cleanup
@@ -0,0 +1,25 @@
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
export UID1=1000000
export GID1=1000000
export UID2=2000000
export GID2=2000000
@@ -0,0 +1,76 @@
#!/bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
. $STF_SUITE/tests/functional/idmap_mount/idmap_mount_common.kshlib
#
#
# DESCRIPTION:
# Test uid and gid of files in idmapped folder are mapped correctly
#
#
# STRATEGY:
# 1. Create files/folder owned by $UID1 and $GID1 under "idmap_test"
# 2. Idmap the folder to "idmap_dest"
# 3. Verify the owner of files/folder under "idmap_dest"
#
verify_runnable "global"
export WORKDIR=$TESTDIR/idmap_test
export IDMAPDIR=$TESTDIR/idmap_dest
function cleanup
{
log_must rm -rf $WORKDIR
if mountpoint $IDMAPDIR; then
log_must umount $IDMAPDIR
fi
log_must rm -rf $IDMAPDIR
}
log_onexit cleanup
if ! idmap_util -c $TESTDIR; then
log_unsupported "Idmap mount not supported."
fi
log_must mkdir -p $WORKDIR
log_must mkdir -p $IDMAPDIR
log_must touch $WORKDIR/file1
log_must mkdir $WORKDIR/subdir
log_must ln -s $WORKDIR/file1 $WORKDIR/file1_sym
log_must ln $WORKDIR/file1 $WORKDIR/subdir/file1_hard
log_must touch $WORKDIR/subdir/file2
log_must chown -R $UID1:$GID1 $WORKDIR
log_must chown $UID2:$GID2 $WORKDIR/subdir/file2
log_must idmap_util -m "u:${UID1}:${UID2}:1" -m "g:${GID1}:${GID2}:1" $WORKDIR $IDMAPDIR
log_must test "$UID2 $GID2" = "$(stat -c '%u %g' $IDMAPDIR/file1)"
log_must test "$UID2 $GID2" = "$(stat -c '%u %g' $IDMAPDIR/file1_sym)"
log_must test "$UID2 $GID2" = "$(stat -c '%u %g' $IDMAPDIR/subdir)"
log_must test "$UID2 $GID2" = "$(stat -c '%u %g' $IDMAPDIR/subdir/file1_hard)"
log_mustnot test "$UID2 $GID2" = "$(stat -c '%u %g' $IDMAPDIR/subdir/file2)"
log_pass "Owner verification of entries under idmapped folder is successful."
@@ -0,0 +1,97 @@
#!/bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
. $STF_SUITE/tests/functional/idmap_mount/idmap_mount_common.kshlib
#
#
# DESCRIPTION:
# Perform file operations in idmapped folder, check owner in its base.
#
#
# STRATEGY:
# 1. Create folder "idmap_test"
# 2. Idmap the folder to "idmap_dest"
# 3. Do basic file operations in "idmap_dest" folder, verify the owner in
# the base folder "idmap_test"
#
verify_runnable "global"
export WORKDIR=$TESTDIR/idmap_test
export IDMAPDIR=$TESTDIR/idmap_dest
function cleanup
{
log_must rm -rf $IDMAPDIR/*
if mountpoint $IDMAPDIR; then
log_must umount $IDMAPDIR
fi
log_must rm -rf $IDMAPDIR $WORKDIR
}
log_onexit cleanup
if ! idmap_util -c $TESTDIR; then
log_unsupported "Idmap mount not supported."
fi
log_must mkdir -p $WORKDIR
log_must mkdir -p $IDMAPDIR
log_must chown $UID1:$GID1 $WORKDIR
log_must idmap_util -m "u:${UID1}:${UID2}:1" -m "g:${GID1}:${GID2}:1" $WORKDIR $IDMAPDIR
SETPRIV="setpriv --reuid $UID2 --regid $GID2 --clear-groups"
log_must $SETPRIV touch $IDMAPDIR/file1
log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/file1)"
log_must $SETPRIV mv $IDMAPDIR/file1 $IDMAPDIR/file1_renamed
log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/file1_renamed)"
log_must $SETPRIV mv $IDMAPDIR/file1_renamed $IDMAPDIR/file1
log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/file1)"
log_must $SETPRIV mkdir $IDMAPDIR/subdir
log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/subdir)"
log_must $SETPRIV ln -s $IDMAPDIR/file1 $IDMAPDIR/file1_sym
log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/file1_sym)"
log_must $SETPRIV ln $IDMAPDIR/file1 $IDMAPDIR/subdir/file1_hard
log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/subdir/file1_hard)"
log_must $SETPRIV touch $IDMAPDIR/subdir/file2
log_must $SETPRIV chown $UID2:$GID2 $IDMAPDIR/subdir/file2
log_mustnot $SETPRIV chown $UID1 $IDMAPDIR/subdir/file2
log_must $SETPRIV cp -r $IDMAPDIR/subdir $IDMAPDIR/subdir1
log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/subdir1/file2)"
log_must $SETPRIV rm -rf $IDMAPDIR/subdir1
log_must $SETPRIV cp -rp $IDMAPDIR/subdir $IDMAPDIR/subdir1
log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/subdir1/file1_hard)"
log_must $SETPRIV rm -rf $IDMAPDIR/subdir1
log_pass "Owner verification of entries under base folder is successful."
@@ -0,0 +1,121 @@
#!/bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
. $STF_SUITE/tests/functional/idmap_mount/idmap_mount_common.kshlib
#
#
# DESCRIPTION:
# Perform file operations in idmapped folder in user namespace,
# then check the owner in its base.
#
#
# STRATEGY:
# 1. Create folder "idmap_test"
# 2. Idmap the folder to "idmap_dest"
# 3. Perform file operations in the idmapped folder in the user
# namespace having the same idmap info as the idmapped mount
# 4. Verify the owner of entries under the base folder "idmap_test"
#
verify_runnable "global"
export WORKDIR=$TESTDIR/idmap_test
export IDMAPDIR=$TESTDIR/idmap_dest
function cleanup
{
kill -TERM ${unshared_pid}
log_must rm -rf $IDMAPDIR/*
if mountpoint $IDMAPDIR; then
log_must umount $IDMAPDIR
fi
log_must rm -rf $IDMAPDIR $WORKDIR
}
log_onexit cleanup
if ! idmap_util -c $TESTDIR; then
log_unsupported "Idmap mount not supported."
fi
log_must mkdir -p $WORKDIR
log_must mkdir -p $IDMAPDIR
log_must chown $UID1:$GID1 $WORKDIR
log_must idmap_util -m "u:${UID1}:${UID2}:1" -m "g:${GID1}:${GID2}:1" $WORKDIR $IDMAPDIR
# Create a user namespace with the same idmapping
unshare -Urm echo test
if [ "$?" -ne "0" ]; then
log_unsupported "Failed to create user namespace"
fi
unshare -Um /usr/bin/sleep 2h &
unshared_pid=$!
if [ "$?" -ne "0" ]; then
log_unsupported "Failed to create user namespace"
fi
# wait for userns to be ready
sleep 1
echo "${UID1} ${UID2} 1" > /proc/$unshared_pid/uid_map
if [ "$?" -ne "0" ]; then
log_unsupported "Failed to write to uid_map"
fi
echo "${GID1} ${GID2} 1" > /proc/$unshared_pid/gid_map
if [ "$?" -ne "0" ]; then
log_unsupported "Failed to write to gid_map"
fi
NSENTER="nsenter -t $unshared_pid --all -S ${UID1} -G ${GID1}"
log_must $NSENTER touch $IDMAPDIR/file1
log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/file1)"
log_must $NSENTER mv $IDMAPDIR/file1 $IDMAPDIR/file1_renamed
log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/file1_renamed)"
log_must $NSENTER mv $IDMAPDIR/file1_renamed $IDMAPDIR/file1
log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/file1)"
log_must $NSENTER mkdir $IDMAPDIR/subdir
log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/subdir)"
log_must $NSENTER ln -s $IDMAPDIR/file1 $IDMAPDIR/file1_sym
log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/file1_sym)"
log_must $NSENTER ln $IDMAPDIR/file1 $IDMAPDIR/subdir/file1_hard
log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/subdir/file1_hard)"
log_must $NSENTER touch $IDMAPDIR/subdir/file2
log_must $NSENTER chown $UID1:$GID1 $IDMAPDIR/subdir/file2
log_mustnot $NSENTER chown $UID2 $IDMAPDIR/subdir/file2
log_must $NSENTER cp -r $IDMAPDIR/subdir $IDMAPDIR/subdir1
log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/subdir1/file2)"
log_must $NSENTER rm -rf $IDMAPDIR/subdir1
log_must $NSENTER cp -rp $IDMAPDIR/subdir $IDMAPDIR/subdir1
log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/subdir1/file1_hard)"
log_must $NSENTER rm -rf $IDMAPDIR/subdir1
log_pass "Owner verification of entries under the base folder is successful."
@@ -0,0 +1,106 @@
#!/bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
. $STF_SUITE/tests/functional/idmap_mount/idmap_mount_common.kshlib
#
#
# DESCRIPTION:
# Test setgid bit is set properly on the idmapped mount
# in a user namespace.
#
# STRATEGY:
# 1. Create folder "idmap_test", set gid bit on it
# 2. Idmap the folder to "idmap_dest"
# 3. Create file and folder in the idmapped folder in the user
# namespace having the same idmap info
# 4. Verify the gid bit of the file and folder is set
#
verify_runnable "global"
export WORKDIR=$TESTDIR/idmap_test
export IDMAPDIR=$TESTDIR/idmap_dest
function cleanup
{
kill -TERM ${unshared_pid}
log_must rm -rf $IDMAPDIR/*
if mountpoint $IDMAPDIR; then
log_must umount $IDMAPDIR
fi
log_must rm -rf $IDMAPDIR $WORKDIR
}
log_onexit cleanup
if ! idmap_util -c $TESTDIR; then
log_unsupported "Idmap mount not supported."
fi
log_must mkdir -p $WORKDIR
log_must mkdir -p $IDMAPDIR
log_must chown $UID1:$GID1 $WORKDIR
# set gid bit
log_must chmod 2755 $WORKDIR
log_must idmap_util -m "u:${UID1}:${UID2}:1" -m "g:${GID1}:${GID2}:1" $WORKDIR $IDMAPDIR
log_must test -g $IDMAPDIR
# Create a user namespace with the same idmapping
unshare -Urm echo test
if [ "$?" -ne "0" ]; then
log_unsupported "Failed to create user namespace"
fi
unshare -Um /usr/bin/sleep 2h &
unshared_pid=$!
if [ "$?" -ne "0" ]; then
log_unsupported "Failed to create user namespace"
fi
# wait for userns to be ready
sleep 1
echo "${UID1} ${UID2} 1" > /proc/$unshared_pid/uid_map
if [ "$?" -ne "0" ]; then
log_unsupported "Failed to write to uid_map"
fi
echo "${GID1} ${GID2} 1" > /proc/$unshared_pid/gid_map
if [ "$?" -ne "0" ]; then
log_unsupported "Failed to write to gid_map"
fi
NSENTER="nsenter -t $unshared_pid --all -S ${UID1} -G ${GID1}"
# gid bit can be set on the file
log_must $NSENTER touch $IDMAPDIR/file1
log_must $NSENTER chmod 2654 $IDMAPDIR/file1
log_must test -g $WORKDIR/file1
log_must test -g $IDMAPDIR/file1
log_must test "$UID1 $GID1" = "$($NSENTER stat -c '%u %g' $IDMAPDIR/file1)"
# gid bit is carried over to new folder
log_must $NSENTER mkdir $IDMAPDIR/subdir
log_must test -g $WORKDIR/subdir
log_must test -g $IDMAPDIR/subdir
log_must test "$UID1 $GID1" = "$($NSENTER stat -c '%u %g' $IDMAPDIR/subdir)"
log_pass "Verification of setting gid bit in userns is successful."
@@ -0,0 +1,23 @@
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
. $STF_SUITE/include/libtest.shlib
. $STF_SUITE/tests/functional/idmap_mount/idmap_mount.cfg
+30
View File
@@ -0,0 +1,30 @@
#!/bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
. $STF_SUITE/include/libtest.shlib
# unable to do idmapped mount in a local zone
verify_runnable "global"
DISK=${DISKS%% *}
default_setup $DISK