From cc351f419dd7455991efd1bf33c3a34b90e34130 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 28 Oct 2018 17:34:45 +1100 Subject: [PATCH 1/2] Add check for disabled unprivileged user namespace --- README.md | 22 ++++++++++++++++++---- lib/core/common.sh | 1 + lib/core/namespace.sh | 16 +++++++++++++++- tests/unit-tests/test-namespace.sh | 21 +++++++++++++++++++++ 4 files changed, 55 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 713d194..f2c45f2 100644 --- a/README.md +++ b/README.md @@ -425,17 +425,31 @@ Troubleshooting > since JuNest will try to preserve the JuNest environment by assigning ownership > of the files to the real user. -## Not enabled User namespace or kernel too old ## +## Unprivileged user namespace disable at kernel compile time or kernel too old ## -> **Q**: Why do I get warning when I run JuNest via Linux namespaces? +> **Q**: Why do I get this warning when I run JuNest via Linux namespaces? $> junest -u - User namespace is not enabled or Kernel too old (<3.8). Proceeding anyway... + Unprivileged user namespace is disabled at kernel compile time or kernel too old (<3.8). Proceeding anyway... + +> **A**: This means that JuNest detected that the host OS either +> does not have a newer kernel version or the unprivileged user namespace +> is not enabled at kernel compile time. +> JuNest does not stop the execution of the program but it attempts to run it +> anyway. Try to use Proot as backend program in case is not possible to invoke namespaces. + +## Unprivileged user namespace disabled + +> **Q**: Why do I get this warning when I run JuNest via Linux namespaces? + + $> junest -u + Unprivileged user namespace disabled. Root permissions are required to enable it: sudo sysctl kernel.unprivileged_userns_clone=1 > **A**: This means that JuNest detected that the host OS either > does not have a newer Linux version or the user namespace is not enabled. > JuNest does not stop the execution of the program but it attempts to run it -> anyway. Try to use Proot as backend program in case is not possible to invoke namespaces. +> anyway. If you have root permissions try to enable it, otherwise try to use +> Proot as backend program. More documentation ================== diff --git a/lib/core/common.sh b/lib/core/common.sh index 8b15d57..a43df83 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -18,6 +18,7 @@ ROOT_ACCESS_ERROR=105 NESTED_ENVIRONMENT=106 VARIABLE_NOT_SET=107 NO_CONFIG_FOUND=108 +UNPRIVILEGED_USERNS_DISABLED=109 JUNEST_HOME=${JUNEST_HOME:-~/.${CMD}} JUNEST_BASE=${JUNEST_BASE:-${JUNEST_HOME}/opt/junest} diff --git a/lib/core/namespace.sh b/lib/core/namespace.sh index 6acd21d..686fabe 100644 --- a/lib/core/namespace.sh +++ b/lib/core/namespace.sh @@ -13,6 +13,7 @@ CONFIG_PROC_FILE="/proc/config.gz" CONFIG_BOOT_FILE="/boot/config-$($UNAME -r)" +PROC_USERNS_CLONE_FILE="/proc/sys/kernel/unprivileged_userns_clone" function _is_user_namespace_enabled() { local config_file="" @@ -30,6 +31,18 @@ function _is_user_namespace_enabled() { then return $NO_CONFIG_FOUND fi + + if [[ ! -e $PROC_USERNS_CLONE_FILE ]] + then + return 0 + fi + + if ! zgrep_cmd -q "1" $PROC_USERNS_CLONE_FILE + then + return $UNPRIVILEGED_USERNS_DISABLED + fi + + return 0 } function _check_user_namespace() { @@ -37,7 +50,8 @@ function _check_user_namespace() { _is_user_namespace_enabled case $? in $NOT_EXISTING_FILE) warn "Could not understand if user namespace is enabled. No config.gz file found. Proceeding anyway..." ;; - $NO_CONFIG_FOUND) warn "User namespace is not enabled or Kernel too old (<3.8). Proceeding anyway..." ;; + $NO_CONFIG_FOUND) warn "Unprivileged user namespace is disabled at kernel compile time or kernel too old (<3.8). Proceeding anyway..." ;; + $UNPRIVILEGED_USERNS_DISABLED) warn "Unprivileged user namespace disabled. Root permissions are required to enable it: sudo sysctl kernel.unprivileged_userns_clone=1" ;; esac set -e } diff --git a/tests/unit-tests/test-namespace.sh b/tests/unit-tests/test-namespace.sh index c4e0f8d..005ab0d 100755 --- a/tests/unit-tests/test-namespace.sh +++ b/tests/unit-tests/test-namespace.sh @@ -75,6 +75,27 @@ function test_is_user_namespace_enabled_with_config(){ gzip config CONFIG_PROC_FILE="config.gz" CONFIG_BOOT_FILE="blah" + PROC_USERNS_CLONE_FILE="not-existing-file" + assertCommandSuccess _is_user_namespace_enabled +} + +function test_is_user_namespace_enabled_with_userns_clone_file_disabled(){ + echo "CONFIG_USER_NS=y" > config + gzip config + CONFIG_PROC_FILE="config.gz" + CONFIG_BOOT_FILE="blah" + PROC_USERNS_CLONE_FILE="unprivileged_userns_clone" + echo "0" > $PROC_USERNS_CLONE_FILE + assertCommandFailOnStatus $UNPRIVILEGED_USERNS_DISABLED _is_user_namespace_enabled +} + +function test_is_user_namespace_enabled_with_userns_clone_file_enabled(){ + echo "CONFIG_USER_NS=y" > config + gzip config + CONFIG_PROC_FILE="config.gz" + CONFIG_BOOT_FILE="blah" + PROC_USERNS_CLONE_FILE="unprivileged_userns_clone" + echo "1" > $PROC_USERNS_CLONE_FILE assertCommandSuccess _is_user_namespace_enabled } From 6361522e408684b668ae8bd553e7fcea00c4b7c4 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 29 Oct 2018 22:01:09 +1100 Subject: [PATCH 2/2] Fix aur validation tests and include sudo-fake in codebase --- .gitignore | 3 +++ .travis.yml | 11 +++++----- README.md | 4 ++-- lib/checks/check.sh | 11 +++++++--- lib/core/build.sh | 18 ++++++++++++----- pkgs/sudo-fake/PKGBUILD | 45 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 76 insertions(+), 16 deletions(-) create mode 100644 pkgs/sudo-fake/PKGBUILD diff --git a/.gitignore b/.gitignore index 1377554..2d39c41 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ *.swp +*pkg.tar.xz +*.tar.gz +*.SRCINFO diff --git a/.travis.yml b/.travis.yml index 94afa57..f31c2ea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,8 +12,6 @@ install: - PATH=$PWD/bin:$PATH - junest -- echo "Installing JuNest (\$(uname -m))" - JUNEST_HOME=~/.junest-arm junest -a arm -- echo "Installing JuNest (\$(uname -m))" - # TODO: Remember to enable x86 tests when fixed - #- JUNEST_HOME=~/.junest-x86 junest -a x86 -- echo "Installing JuNest (\$(uname -m))" script: - bash --version @@ -21,10 +19,11 @@ script: - bash ./tests/unit-tests/unit-tests.sh # Multiple tests against different execution modes: - - junest -f -- ${PWD}/lib/checks/check.sh - - junest -u -- ${PWD}/lib/checks/check.sh - - sudo -E ${PWD}/bin/junest -g -- ${PWD}/lib/checks/check.sh --run-root-tests + # TODO AUR installation check is currently disabled + - junest -f -- ${PWD}/lib/checks/check.sh --skip-aur-tests + - junest -u -- ${PWD}/lib/checks/check.sh --skip-aur-tests + - sudo -E ${PWD}/bin/junest -g -- ${PWD}/lib/checks/check.sh --skip-aur-tests - yes | junest --delete - - JUNEST_HOME=~/.junest-arm junest -f -- ./lib/checks/check.sh + - JUNEST_HOME=~/.junest-arm junest -f -- ./lib/checks/check.sh --skip-aur-tests - yes | JUNEST_HOME=~/.junest-arm junest --delete diff --git a/README.md b/README.md index f2c45f2..aa6a4e8 100644 --- a/README.md +++ b/README.md @@ -265,8 +265,8 @@ As a fallback it tries to run the same executable if it is available in the JuNe image. ## Automatic building of the JuNest images ## -The JuNest images are built every week so that you can always get the most -updated package versions. +There is not periodic automation build of the JuNest images yet. +This was due to the difficulty to automate builds for arm architecture. ## Static QEMU binaries ## There are static QEMU binaries included in JuNest image that allows to run JuNest diff --git a/lib/checks/check.sh b/lib/checks/check.sh index e361913..9bf99ea 100755 --- a/lib/checks/check.sh +++ b/lib/checks/check.sh @@ -31,6 +31,10 @@ source "${JUNEST_BASE}/lib/core/common.sh" info "Validating JuNest located in ${JUNEST_HOME}..." info "Initial JuNest setup..." +# The following ensures that the gpg agent gets killed (if exists) +# otherwise it is not possible to exit from the session +trap "[[ -e /etc/pacman.d/gnupg/S.gpg-agent ]] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye" QUIT EXIT ABRT KILL TERM INT + echo "Server = ${DEFAULT_MIRROR}" >> /etc/pacman.d/mirrorlist pacman --noconfirm -Syy pacman --noconfirm -S archlinux-keyring @@ -59,14 +63,15 @@ pacman --noconfirm -Rsn ${repo_package2} if ! $SKIP_AUR_TESTS then - aur_package=tcptraceroute + aur_package=cower info "Checking ${aur_package} package from AUR repo..." + gpg --recv-key --keyserver hkp://pgp.mit.edu 1EB2638FF56C0C53 yogurt -A --noconfirm -S ${aur_package} - $RUN_ROOT_TESTS && tcptraceroute localhost + ${aur_package} --help pacman --noconfirm -Rsn ${aur_package} fi -# The following ensure that the gpg agent gets killed (if exists) +# The following ensures that the gpg agent gets killed (if exists) # otherwise it is not possible to exit from the session [[ -e /etc/pacman.d/gnupg/S.gpg-agent ]] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye diff --git a/lib/core/build.sh b/lib/core/build.sh index adcca80..fe12df3 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -15,7 +15,7 @@ function _check_package(){ fi } -function _install_from_aur(){ +function _install_pkg_from_aur(){ local maindir=$1 local pkgname=$2 local installname=$3 @@ -27,6 +27,14 @@ function _install_from_aur(){ sudo pacman --noconfirm --root ${maindir}/root -U ${pkgname}*.pkg.tar.xz } +function _install_pkg(){ + local maindir=$1 + local pkgbuilddir=$2 + builtin cd ${pkgbuilddir} + makepkg -sfcd + sudo pacman --noconfirm --root ${maindir}/root -U *.pkg.tar.xz +} + function build_image_env(){ umask 022 @@ -55,13 +63,13 @@ function build_image_env(){ # AUR packages requires non-root user to be compiled. proot fakes the user to 10 info "Compiling and installing yaourt..." - _install_from_aur ${maindir} "package-query" - _install_from_aur ${maindir} "yaourt" - _install_from_aur ${maindir} "sudo-fake" + _install_pkg_from_aur ${maindir} "package-query" + _install_pkg_from_aur ${maindir} "yaourt" + _install_pkg ${maindir} "$JUNEST_BASE/pkgs/sudo-fake" info "Install ${NAME} script..." sudo pacman --noconfirm --root ${maindir}/root -S git - _install_from_aur ${maindir} "${CMD}-git" "${CMD}.install" + _install_pkg_from_aur ${maindir} "${CMD}-git" "${CMD}.install" sudo pacman --noconfirm --root ${maindir}/root -Rsn git info "Generating the locales..." diff --git a/pkgs/sudo-fake/PKGBUILD b/pkgs/sudo-fake/PKGBUILD new file mode 100644 index 0000000..99fa18b --- /dev/null +++ b/pkgs/sudo-fake/PKGBUILD @@ -0,0 +1,45 @@ +# Maintainer: Filippo Squillace +# More details on how to change this file: +# https://wiki.archlinux.org/index.php/PKGBUILD +# https://wiki.archlinux.org/index.php/Creating_packages +# https://wiki.archlinux.org/index.php/Arch_User_Repository#Submitting_packages + +pkgname=sudo-fake +pkgver=0.1.0 +pkgrel=1 +pkgdesc="Simple script that bypasses sudo and execute the actual command. Useful for fakeroot environments." +arch=('any') +url="" +license=('GPL') +groups=() +depends=() +makedepends=() +provides=('sudo') +conflicts=('sudo') +backup=() +options=() +#install= +source=() +md5sums=() +noextract=() + +package() { + install -d -m 755 "${pkgdir}/usr/bin/" + cat < "${pkgdir}/usr/bin/sudo" +#!/bin/bash +for opt in "\$@" +do + case "\$1" in + --) shift ; break ;; + -*) shift ;; + *) break ;; + esac +done + +[[ -z "\${@}" ]] || "\${@}" +EOF + + chmod 755 "${pkgdir}/usr/bin/sudo" +} + +# vim:set ts=2 sw=2 et: