diff --git a/README.md b/README.md index 96c8b0b..0088502 100644 --- a/README.md +++ b/README.md @@ -132,7 +132,7 @@ need to be satisfied: 1) Only starting from Linux 3.8, unprivileged processes ca create the required user and mount namespaces. 2) Moreover, the Linux kernel distro must have the user namespace enabled. Hopefully, in the future the major GNU/Linux distros will start enabling such feature by default. -For instance, Ubuntu (version 14.04+) already has such feature enabled. +For instance, Ubuntu (version 12.04+) already has such feature enabled. In order to run JuNest via Linux namespaces: diff --git a/bin/groot b/bin/groot index fd438b4..cb4952f 100755 --- a/bin/groot +++ b/bin/groot @@ -16,7 +16,6 @@ CHROOTCMD=${CHROOTCMD:-chroot} SHELL="/bin/sh" MOUNT=mount UMOUNT=umount -MOUNTPOINT=mountpoint MKDIR=mkdir TOUCH=touch CUT=cut @@ -35,6 +34,15 @@ source "${JUNEST_BASE}/lib/utils/utils.sh" ################################ MAIN FUNCTIONS ########################### +function is_mountpoint() { + local mountpoint="$1" + for mp in $($CAT $MOUNTS_FILE | $CUT -f2 -d' ' | $SORT -r | $UNIQ) + do + [[ $mp == $mountpoint ]] && return 0 + done + return 1 +} + function chroot_teardown() { # Remove all mounts starting from the most nested ones. # Suffix the CHROOTDIR with / to avoid umounting directories not belonging @@ -43,7 +51,7 @@ function chroot_teardown() { local final_res=0 for mp in $($CAT $MOUNTS_FILE | $CUT -f2 -d' ' | $SORT -r | $UNIQ) do - if [[ $mp =~ ^${normalized_chrootdir}.* ]] && $MOUNTPOINT -q "$mp" + if [[ $mp =~ ^${normalized_chrootdir}.* ]] && is_mountpoint "$mp" then $UMOUNT $mp || final_res=$? fi @@ -66,7 +74,7 @@ function chroot_maybe_add_mount() { function chroot_setup() { $OPT_NO_UMOUNT || check_and_trap 'chroot_teardown' QUIT EXIT ABRT KILL TERM INT - if ! chroot_maybe_add_mount "! $MOUNTPOINT -q '$CHROOTDIR'" --bind "$CHROOTDIR" "$CHROOTDIR" + if ! chroot_maybe_add_mount "! is_mountpoint '$CHROOTDIR'" --bind "$CHROOTDIR" "$CHROOTDIR" then warn "Failed mount of directories. $CHROOTDIR is already a mountpoint. Skipping it..." return 0 diff --git a/tests/unit-tests/test-groot.sh b/tests/unit-tests/test-groot.sh index ca4df91..5fb2580 100755 --- a/tests/unit-tests/test-groot.sh +++ b/tests/unit-tests/test-groot.sh @@ -53,6 +53,10 @@ function init_mocks() { function check_and_trap() { echo "check_and_trap($@)" } + + # As default suppose the mountpoint "chrootdir" does not exist + echo -e "1 /home/mychroot/dev\n" > ./mounts + MOUNTS_FILE=./mounts } function test_help(){ @@ -77,41 +81,42 @@ function test_groot_no_directory(){ assertCommandFailOnStatus $NOT_EXISTING_FILE main no-directory } function test_groot_mountpoint_exist(){ - MOUNTPOINT=mountpoint_mock + echo -e "1 /home/mychroot/dev\n1 chrootdir\n" > ./mounts + MOUNTS_FILE=./mounts assertCommandSuccess main chrootdir - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_mountpoint_does_not_exist(){ assertCommandSuccess main chrootdir - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_bind(){ assertCommandSuccess main -b /tmp chrootdir [[ -d chrootdir/tmp ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_bind_file(){ touch file_src assertCommandSuccess main -b ${PWD}/file_src:/file_src chrootdir [[ -f chrootdir/file_src ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--bind ${PWD}/file_src chrootdir/file_src)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(--bind ${PWD}/file_src chrootdir/file_src)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_bind_not_existing_node(){ assertCommandFailOnStatus $NOT_EXISTING_FILE main -b ${PWD}/file_src:/file_src chrootdir - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_bind_not_absolute_path_node(){ touch file_src assertCommandFailOnStatus $NOT_ABSOLUTE_PATH main -b file_src:/file_src chrootdir - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_bind_guest_host(){ assertCommandSuccess main -b /tmp:/home/tmp chrootdir [[ -d chrootdir/home/tmp ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/home/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/home/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_multiple_bind(){ assertCommandSuccess main -b /tmp:/home/tmp -b /dev chrootdir @@ -119,11 +124,11 @@ function test_groot_with_multiple_bind(){ assertEquals 0 $? [[ -d chrootdir/dev ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/home/tmp)\nmount(--bind /dev chrootdir/dev)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/home/tmp)\nmount(--bind /dev chrootdir/dev)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_command(){ assertCommandSuccess main chrootdir ls -la -h - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)" } function test_groot_with_bind_and_command(){ assertCommandSuccess main -b /tmp:/home/tmp -b /dev chrootdir ls -la -h @@ -131,30 +136,24 @@ function test_groot_with_bind_and_command(){ assertEquals 0 $? [[ -d chrootdir/dev ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/home/tmp)\nmount(--bind /dev chrootdir/dev)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/home/tmp)\nmount(--bind /dev chrootdir/dev)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)" } function test_groot_with_bind_no_umount(){ assertCommandSuccess main -n chrootdir - assertEquals "$(echo -e "mountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "mount(--bind chrootdir chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_chroot_teardown(){ - MOUNTPOINT=mountpoint_mock echo -e "1 /home/mychroot/dev\n1 /home/mychroot/proc/fs1\n1 /home/mychroot\n1 /home/mychroot-no/dev\n1 /home/mychroot/dev/shm\n1 /home/mychroot/proc\n" > ./mounts MOUNTS_FILE=./mounts CHROOTDIR=/home/mychroot assertCommandSuccess chroot_teardown - assertEquals "$(echo -e "mountpoint(-q /home/mychroot/proc/fs1) -umount(/home/mychroot/proc/fs1) -mountpoint(-q /home/mychroot/proc) + assertEquals "$(echo -e "umount(/home/mychroot/proc/fs1) umount(/home/mychroot/proc) -mountpoint(-q /home/mychroot/dev/shm) umount(/home/mychroot/dev/shm) -mountpoint(-q /home/mychroot/dev) umount(/home/mychroot/dev) umount(/home/mychroot)")" "$(cat $STDOUTF)" } function test_groot_with_chroot_teardown_umount_failure(){ - MOUNTPOINT=mountpoint_mock function umount() { echo "umount($@)" [[ "$1" == "/home/mychroot/dev/shm" ]] && return 128 @@ -164,47 +163,32 @@ function test_groot_with_chroot_teardown_umount_failure(){ echo -e "1 /home/mychroot/dev\n1 /home/mychroot/proc/fs1\n1 /home/mychroot\n1 /home/mychroot-no/dev\n1 /home/mychroot/dev/shm\n1 /home/mychroot/proc\n" > ./mounts MOUNTS_FILE=./mounts CHROOTDIR=/home/mychroot assertCommandFailOnStatus 128 chroot_teardown - assertEquals "$(echo -e "mountpoint(-q /home/mychroot/proc/fs1) -umount(/home/mychroot/proc/fs1) -mountpoint(-q /home/mychroot/proc) + assertEquals "$(echo -e "umount(/home/mychroot/proc/fs1) umount(/home/mychroot/proc) -mountpoint(-q /home/mychroot/dev/shm) umount(/home/mychroot/dev/shm) -mountpoint(-q /home/mychroot/dev) umount(/home/mychroot/dev) umount(/home/mychroot)")" "$(cat $STDOUTF)" } function test_groot_with_chroot_teardown_with_trailing_slash(){ - MOUNTPOINT=mountpoint_mock echo -e "1 /home/mychroot/dev\n1 /home/mychroot/proc/fs1\n1 /home/mychroot\n1 /home/mychroot-no/dev\n1 /home/mychroot/dev/shm\n1 /home/mychroot/proc\n" > ./mounts MOUNTS_FILE=./mounts CHROOTDIR=/home/mychroot assertCommandSuccess chroot_teardown - assertEquals "$(echo -e "mountpoint(-q /home/mychroot/proc/fs1) -umount(/home/mychroot/proc/fs1) -mountpoint(-q /home/mychroot/proc) + assertEquals "$(echo -e "umount(/home/mychroot/proc/fs1) umount(/home/mychroot/proc) -mountpoint(-q /home/mychroot/dev/shm) umount(/home/mychroot/dev/shm) -mountpoint(-q /home/mychroot/dev) umount(/home/mychroot/dev) umount(/home/mychroot)")" "$(cat $STDOUTF)" } function test_groot_with_chroot_teardown_mountpoint_failure(){ - mountpoint_mock() { - echo "mountpoint($@)" - [[ $2 == "/home/mychroot/dev/shm" ]] && return 128 + is_mountpoint() { + [[ $1 == "/home/mychroot/dev/shm" ]] && return 128 return 0 } - MOUNTPOINT=mountpoint_mock echo -e "1 /home/mychroot/dev\n1 /home/mychroot/proc/fs1\n1 /home/mychroot\n1 /home/mychroot-no/dev\n1 /home/mychroot/dev/shm\n1 /home/mychroot/proc\n" > ./mounts MOUNTS_FILE=./mounts CHROOTDIR=/home/mychroot assertCommandSuccess chroot_teardown - assertEquals "$(echo -e "mountpoint(-q /home/mychroot/proc/fs1) -umount(/home/mychroot/proc/fs1) -mountpoint(-q /home/mychroot/proc) + assertEquals "$(echo -e "umount(/home/mychroot/proc/fs1) umount(/home/mychroot/proc) -mountpoint(-q /home/mychroot/dev/shm) -mountpoint(-q /home/mychroot/dev) umount(/home/mychroot/dev) umount(/home/mychroot)")" "$(cat $STDOUTF)" } @@ -213,42 +197,42 @@ function test_groot_with_rbind(){ assertCommandSuccess main -r -b /tmp chrootdir [[ -d chrootdir/tmp ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_avoid_bind_proc(){ assertCommandSuccess main -i -b /proc chrootdir [[ -d chrootdir/proc ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(proc chrootdir/proc -t proc)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(proc chrootdir/proc -t proc)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_avoid_bind_dev(){ assertCommandSuccess main -i -b /dev chrootdir [[ -d chrootdir/dev ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(udev chrootdir/dev -t devtmpfs)\nmount(devpts /dev/pts -t devpts)\nmount(shm /dev/shm -t tmpfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(udev chrootdir/dev -t devtmpfs)\nmount(devpts /dev/pts -t devpts)\nmount(shm /dev/shm -t tmpfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_avoid_bind_sys(){ assertCommandSuccess main -i -b /sys chrootdir [[ -d chrootdir/sys ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(sys chrootdir/sys -t sysfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(sys chrootdir/sys -t sysfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_avoid_bind_run(){ assertCommandSuccess main -i -b /run chrootdir [[ -d chrootdir/run ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(run chrootdir/run -t tmpfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(run chrootdir/run -t tmpfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_avoid_bind_tmp(){ assertCommandSuccess main -i -b /tmp chrootdir [[ -d chrootdir/tmp ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(tmp chrootdir/tmp -t tmpfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(tmp chrootdir/tmp -t tmpfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_avoid_bind_combined(){ @@ -258,7 +242,7 @@ function test_groot_with_avoid_bind_combined(){ assertEquals 0 $? [[ -d chrootdir/usr ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(tmp chrootdir/tmp -t tmpfs)\nmount(--bind /usr chrootdir/usr)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(tmp chrootdir/tmp -t tmpfs)\nmount(--bind /usr chrootdir/usr)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } source $(dirname $0)/../utils/shunit2