Allow to opt-out from the have-real-root check via NFT_TEST_ROOTLESS=1 ./run-tests.sh For that to be useful, we must also unshare the PID and user namespace and map the root user inside that namespace. With that, inside the namespace we look like root. Including having CAP_NET_ADMIN for the new net namespace. This allows to run the tests as rootless and most tests will pass. Note that some tests will fail as rootless. For example, the socket buffers are limited by /proc/sys/net/core/{wmem_max,rmem_max}, which is not namespaced. When running as real-root, nftables can raise them beyond those limits and the tests will pass. Rootless cannot do that and the test may fail. Test that don't work without real root should check for [ "$NFT_TEST_HAVE_REALROOT" != 1 ] and skip gracefully. Signed-off-by: Thomas Haller <thaller@xxxxxxxxxx> --- tests/shell/run-tests.sh | 57 +++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/tests/shell/run-tests.sh b/tests/shell/run-tests.sh index b66ef4fa4d1f..96dd0b0c2fd6 100755 --- a/tests/shell/run-tests.sh +++ b/tests/shell/run-tests.sh @@ -1,9 +1,18 @@ #!/bin/bash -# Configuration -TESTDIR="./$(dirname $0)/testcases" -SRC_NFT="$(dirname $0)/../../src/nft" -DIFF=$(which diff) +# Environment variables for the user: +# NFT=<path> Path to the nft executable. +# NFT_TEST_ROOTLESS=0|1: Whether the test allows to run as rootless. Usually the test +# will require real root permissions. You can set NFT_TEST_ROOTLESS=1 +# to run rootless in a separate namespace. +# NFT_TEST_HAVE_REALROOT=0|1: To indicate whether the test has real root permissions. +# Usually, you don't need this and it gets autodetected. +# Note that without real root, certain tests may not work. +# For example, due to limited /proc/sys/net/core/{wmem_max,rmem_max}. +# Such test should check for [ "$NFT_TEST_HAVE_REALROOT" != 1 ] and +# skip (not fail) in such an environment. +# NFT_TEST_NO_UNSHARE=0|1: Usually, the test will run in a separate namespace. +# You can opt-out from that by setting NFT_TEST_NO_UNSHARE=1. msg_error() { echo "E: $1 ..." >&2 @@ -18,18 +27,42 @@ msg_info() { echo "I: $1" } -if [ "$(id -u)" != "0" ] ; then +if [ "$NFT_TEST_HAVE_REALROOT" = "" ] ; then + # The caller can set NFT_TEST_HAVE_REALROOT to indicate us whether we + # have real root. They usually don't need, and we detect it now based + # on `id -u`. Note that we may unshare below, so the check inside the + # new namespace won't be conclusive. We thus only detect once and export + # the result. + export NFT_TEST_HAVE_REALROOT="$(test "$(id -u)" = "0" && echo 1 || echo 0)" +fi + +if [ "$NFT_TEST_HAVE_REALROOT" != 1 -a "$NFT_TEST_ROOTLESS" != 1 ] ; then + # By default, we require real-root, unless the user explicitly opts-in + # to proceed via NFT_TEST_ROOTLESS=1. msg_error "this requires root!" fi -if [ "${1}" != "run" ]; then - if unshare -f -n true; then - unshare -n "${0}" run $@ - exit $? - fi - msg_warn "cannot run in own namespace, connectivity might break" +if [ "$NFT_TEST_NO_UNSHARE" = 1 ]; then + # The user opts-out from unshare. Proceed without. + : +elif [ "$_NFT_TEST_IS_UNSHARED" = 1 ]; then + # We are inside the unshared environment. Don't unshare again. + # Continue. + : +else + # Unshare. This works both as rootless and with real root. Inside + # the user namespace we will map the root user, so we appear to have + # root. Check for [ "$NFT_TEST_HAVE_REALROOT" != 1 ] to know when + # not having real root. + export _NFT_TEST_IS_UNSHARED=1 + unshare -f --map-root-user -U -p -n "$0" "$@" + exit $? fi -shift + +# Configuration +TESTDIR="./$(dirname $0)/testcases" +SRC_NFT="$(dirname $0)/../../src/nft" +DIFF=$(which diff) [ -z "$NFT" ] && NFT=$SRC_NFT ${NFT} > /dev/null 2>&1 -- 2.41.0