From a06bd82cd4dc14b3c2949a421870b6d3067aba34 Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Thu, 28 Sep 2017 18:57:33 +0000 Subject: [PATCH] tests: check for relabeling rather than overlay Instead of checking for overlayfs, let's explicitly check for our ability to relabel files since we now have a `libtest` function to do this. Also port that logic to `libostreetest`. Note that overlayfs *does* allow manipulating user xattrs. So ideally, we should break down `OSTREE_NO_XATTRS` further to distinguish between tests that use bare repos from other modes. We check the current directory instead of `/` so that developers can just point `TEST_TMPDIR` to a non-overlayfs mount point when hacking from a container. Closes: #1170 Approved by: cgwalters --- tests/libostreetest.c | 91 +++++++++++++++++++++++++++++++++++-------- tests/libostreetest.h | 6 +++ tests/libtest.sh | 78 +++++++++++++++++++++++-------------- tests/test-basic-c.c | 14 +++++-- 4 files changed, 140 insertions(+), 49 deletions(-) diff --git a/tests/libostreetest.c b/tests/libostreetest.c index 6186a73a..496ff740 100644 --- a/tests/libostreetest.c +++ b/tests/libostreetest.c @@ -72,6 +72,68 @@ ot_test_setup_repo (GCancellable *cancellable, return g_steal_pointer (&ret_repo); } +/* Determine whether we're able to relabel files. Needed for bare tests. */ +gboolean +ot_check_relabeling (gboolean *can_relabel, + GError **error) +{ + g_auto(GLnxTmpfile) tmpf = { 0, }; + if (!glnx_open_tmpfile_linkable_at (AT_FDCWD, ".", O_RDWR | O_CLOEXEC, &tmpf, error)) + return FALSE; + + g_autoptr(GError) local_error = NULL; + g_autoptr(GBytes) bytes = glnx_fgetxattr_bytes (tmpf.fd, "security.selinux", &local_error); + if (!bytes) + { + /* libglnx preserves errno */ + if (G_IN_SET (errno, ENOTSUP, ENODATA)) + { + *can_relabel = FALSE; + return TRUE; + } + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + + gsize data_len; + const guint8 *data = g_bytes_get_data (bytes, &data_len); + if (fsetxattr (tmpf.fd, "security.selinux", data, data_len, 0) < 0) + { + if (errno == ENOTSUP) + { + *can_relabel = FALSE; + return TRUE; + } + return glnx_throw_errno_prefix (error, "fsetxattr"); + } + + *can_relabel = TRUE; + return TRUE; +} + +/* Determine whether the filesystem supports getting/setting user xattrs. */ +gboolean +ot_check_user_xattrs (gboolean *has_user_xattrs, + GError **error) +{ + g_auto(GLnxTmpfile) tmpf = { 0, }; + if (!glnx_open_tmpfile_linkable_at (AT_FDCWD, ".", O_RDWR | O_CLOEXEC, &tmpf, error)) + return FALSE; + + if (fsetxattr (tmpf.fd, "user.test", "novalue", strlen ("novalue"), 0) < 0) + { + if (errno == ENOTSUP) + { + *has_user_xattrs = FALSE; + return TRUE; + } + return glnx_throw_errno_prefix (error, "fsetxattr"); + } + + *has_user_xattrs = TRUE; + return TRUE; +} + OstreeSysroot * ot_test_setup_sysroot (GCancellable *cancellable, GError **error) @@ -79,22 +141,19 @@ ot_test_setup_sysroot (GCancellable *cancellable, if (!ot_test_run_libtest ("setup_os_repository \"archive\" \"syslinux\"", error)) return FALSE; - struct statfs stbuf; - { g_autoptr(GString) buf = g_string_new ("mutable-deployments"); - if (statfs ("/", &stbuf) < 0) - return glnx_null_throw_errno (error); - /* Keep this in sync with the overlayfs bits in libtest.sh */ -#ifndef OVERLAYFS_SUPER_MAGIC -#define OVERLAYFS_SUPER_MAGIC 0x794c7630 -#endif - if (stbuf.f_type == OVERLAYFS_SUPER_MAGIC) - { - g_print ("libostreetest: detected overlayfs\n"); - g_string_append (buf, ",no-xattrs"); - } - /* Make sure deployments are mutable */ - g_setenv ("OSTREE_SYSROOT_DEBUG", buf->str, TRUE); - } + g_autoptr(GString) buf = g_string_new ("mutable-deployments"); + + gboolean can_relabel; + if (!ot_check_relabeling (&can_relabel, error)) + return FALSE; + if (!can_relabel) + { + g_print ("libostreetest: can't relabel, turning off xattrs\n"); + g_string_append (buf, ",no-xattrs"); + } + + /* Make sure deployments are mutable */ + g_setenv ("OSTREE_SYSROOT_DEBUG", buf->str, TRUE); g_autoptr(GFile) sysroot_path = g_file_new_for_path ("sysroot"); return ostree_sysroot_new (sysroot_path); diff --git a/tests/libostreetest.h b/tests/libostreetest.h index d5512d55..0273334a 100644 --- a/tests/libostreetest.h +++ b/tests/libostreetest.h @@ -31,6 +31,12 @@ gboolean ot_test_run_libtest (const char *cmd, GError **error); OstreeRepo *ot_test_setup_repo (GCancellable *cancellable, GError **error); +gboolean ot_check_relabeling (gboolean *can_relabel, + GError **error); + +gboolean ot_check_user_xattrs (gboolean *has_user_xattrs, + GError **error); + OstreeSysroot *ot_test_setup_sysroot (GCancellable *cancellable, GError **error); diff --git a/tests/libtest.sh b/tests/libtest.sh index 6993629d..a0c0e36f 100755 --- a/tests/libtest.sh +++ b/tests/libtest.sh @@ -70,16 +70,50 @@ chmod -R u+w "${test_tmpdir}" export TEST_GPG_KEYHOME=${test_tmpdir}/gpghome export OSTREE_GPG_HOME=${test_tmpdir}/gpghome/trusted -# See comment in ot-builtin-commit.c and https://github.com/ostreedev/ostree/issues/758 -# Also keep this in sync with the bits in libostreetest.c -echo evaluating for overlayfs... -case $(stat -f --printf '%T' /) in - overlayfs) - echo "overlayfs found; enabling OSTREE_NO_XATTRS" - export OSTREE_SYSROOT_DEBUG="${OSTREE_SYSROOT_DEBUG},no-xattrs" - export OSTREE_NO_XATTRS=1 ;; - *) ;; -esac +assert_has_setfattr() { + if ! which setfattr 2>/dev/null; then + fatal "no setfattr available to determine xattr support" + fi +} + +_have_selinux_relabel='' +have_selinux_relabel() { + assert_has_setfattr + if test "${_have_selinux_relabel}" = ''; then + pushd ${test_tmpdir} + echo testlabel > testlabel.txt + selinux_xattr=security.selinux + if getfattr --encoding=base64 -n ${selinux_xattr} testlabel.txt >label.txt 2>err.txt; then + label=$(grep -E -e "^${selinux_xattr}=" < label.txt |sed -e "s,${selinux_xattr}=,,") + if setfattr -n ${selinux_xattr} -v ${label} testlabel.txt 2>err.txt; then + echo "SELinux enabled in $(pwd), and have privileges to relabel" + _have_selinux_relabel=yes + else + sed -e 's/^/# /' < err.txt >&2 + echo "Found SELinux label, but unable to set (Unprivileged Docker?)" + _have_selinux_relabel=no + fi + else + sed -e 's/^/# /' < err.txt >&2 + echo "Unable to retrieve SELinux label, assuming disabled" + _have_selinux_relabel=no + fi + popd + fi + test ${_have_selinux_relabel} = yes +} + +# just globally turn off xattrs if we can't manipulate security xattrs; this is +# the case for overlayfs -- really, we should only enforce this for tests that +# use bare repos; separate from other tests that should check for user xattrs +# support +# see https://github.com/ostreedev/ostree/issues/758 +# and https://github.com/ostreedev/ostree/pull/1217 +echo -n checking for xattrs... +if ! have_selinux_relabel; then + export OSTREE_SYSROOT_DEBUG="${OSTREE_SYSROOT_DEBUG},no-xattrs" + export OSTREE_NO_XATTRS=1 +fi echo done if test -n "${OT_TESTS_DEBUG:-}"; then @@ -516,12 +550,9 @@ os_repository_new_commit () cd ${test_tmpdir} } -# Usage: if ! skip_one_without_user_xattrs; then ... more tests ...; fi _have_user_xattrs='' have_user_xattrs() { - if ! which setfattr 2>/dev/null; then - fatal "no setfattr available to determine xattr support" - fi + assert_has_setfattr if test "${_have_user_xattrs}" = ''; then touch test-xattrs if setfattr -n user.testvalue -v somevalue test-xattrs 2>/dev/null; then @@ -533,6 +564,8 @@ have_user_xattrs() { fi test ${_have_user_xattrs} = yes } + +# Usage: if ! skip_one_without_user_xattrs; then ... more tests ...; fi skip_one_without_user_xattrs () { if ! have_user_xattrs; then echo "ok # SKIP - this test requires xattr support" @@ -554,21 +587,8 @@ skip_without_user_xattrs () { # https://github.com/ostreedev/ostree/pull/759 # https://github.com/ostreedev/ostree/pull/1217 skip_without_no_selinux_or_relabel () { - cd ${test_tmpdir} - echo testlabel > testlabel.txt - selinux_xattr=security.selinux - if getfattr --encoding=base64 -n ${selinux_xattr} testlabel.txt >label.txt 2>err.txt; then - label=$(grep -E -e "^${selinux_xattr}=" < label.txt |sed -e "s,${selinux_xattr}=,,") - if setfattr -n ${selinux_xattr} -v ${label} testlabel.txt 2>err.txt; then - echo "SELinux enabled in $(pwd), and have privileges to relabel" - return 0 - else - sed -e 's/^/# /' < err.txt >&2 - skip "Found SELinux label, but unable to set (Unprivileged Docker?)" - fi - else - sed -e 's/^/# /' < err.txt >&2 - skip "Unable to retrieve SELinux label, assuming disabled" + if ! have_selinux_relabel; then + skip "this test requires xattr support" fi } diff --git a/tests/test-basic-c.c b/tests/test-basic-c.c index 163774f3..f7e85438 100644 --- a/tests/test-basic-c.c +++ b/tests/test-basic-c.c @@ -262,14 +262,20 @@ test_devino_cache_xattrs (void) g_assert_no_error (error); g_assert (ret); - gboolean on_overlay; - ret = ot_check_for_overlay (&on_overlay, &error); + gboolean can_relabel; + ret = ot_check_relabeling (&can_relabel, &error); g_assert_no_error (error); g_assert (ret); - if (on_overlay) + gboolean has_user_xattrs; + ret = ot_check_user_xattrs (&has_user_xattrs, &error); + g_assert_no_error (error); + g_assert (ret); + + /* we need both because we're bare and our tests target user xattrs */ + if (!can_relabel || !has_user_xattrs) { - g_test_skip ("overlayfs detected"); + g_test_skip ("this test requires full xattr support"); return; }