From e862b7ecfc6049df19cf0d439510f385a7707b8b Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Sun, 19 Jul 2020 09:56:21 -0700 Subject: [PATCH] Linux 4.10 compat: has_capability() Stock kernels older than 4.10 do not export the has_capability() function which is required by commit e59a377. To avoid breaking the build on older kernels revert to the safe legacy behavior and return EACCES when privileges cannot be checked. Reviewed-by: Ryan Moeller Reviewed-by: Matt Ahrens Signed-off-by: Brian Behlendorf Closes #10565 Closes #10573 --- config/kernel-userns-capabilities.m4 | 29 +++++++++++++++++++ module/os/linux/zfs/policy.c | 9 ++++++ tests/test-runner/bin/zts-report.py.in | 2 ++ .../functional/limits/filesystem_limit.ksh | 12 ++++++++ .../functional/limits/snapshot_limit.ksh | 12 ++++++++ 5 files changed, 64 insertions(+) diff --git a/config/kernel-userns-capabilities.m4 b/config/kernel-userns-capabilities.m4 index 68a7bd62c..026503623 100644 --- a/config/kernel-userns-capabilities.m4 +++ b/config/kernel-userns-capabilities.m4 @@ -19,6 +19,33 @@ AC_DEFUN([ZFS_AC_KERNEL_NS_CAPABLE], [ ]) ]) +dnl # +dnl # 4.10 API change +dnl # has_capability() was exported. +dnl # +AC_DEFUN([ZFS_AC_KERNEL_SRC_HAS_CAPABILITY], [ + ZFS_LINUX_TEST_SRC([has_capability], [ + #include + ],[ + struct task_struct *task = NULL; + int cap = 0; + bool result __attribute__ ((unused)); + + result = has_capability(task, cap); + ]) +]) + +AC_DEFUN([ZFS_AC_KERNEL_HAS_CAPABILITY], [ + AC_MSG_CHECKING([whether has_capability() is available]) + ZFS_LINUX_TEST_RESULT_SYMBOL([has_capability], + [has_capability], [kernel/capability.c], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_HAS_CAPABILITY, 1, [has_capability() is available]) + ],[ + AC_MSG_RESULT(no) + ]) +]) + dnl # dnl # 2.6.39 API change dnl # struct user_namespace was added to struct cred_t as cred->user_ns member @@ -66,12 +93,14 @@ AC_DEFUN([ZFS_AC_KERNEL_KUID_HAS_MAPPING], [ AC_DEFUN([ZFS_AC_KERNEL_SRC_USERNS_CAPABILITIES], [ ZFS_AC_KERNEL_SRC_NS_CAPABLE + ZFS_AC_KERNEL_SRC_HAS_CAPABILITY ZFS_AC_KERNEL_SRC_CRED_USER_NS ZFS_AC_KERNEL_SRC_KUID_HAS_MAPPING ]) AC_DEFUN([ZFS_AC_KERNEL_USERNS_CAPABILITIES], [ ZFS_AC_KERNEL_NS_CAPABLE + ZFS_AC_KERNEL_HAS_CAPABILITY ZFS_AC_KERNEL_CRED_USER_NS ZFS_AC_KERNEL_KUID_HAS_MAPPING ]) diff --git a/module/os/linux/zfs/policy.c b/module/os/linux/zfs/policy.c index eaa5372f2..5267d67ee 100644 --- a/module/os/linux/zfs/policy.c +++ b/module/os/linux/zfs/policy.c @@ -249,13 +249,22 @@ secpolicy_zfs(const cred_t *cr) * Equivalent to secpolicy_zfs(), but works even if the cred_t is not that of * the current process. Takes both cred_t and proc_t so that this can work * easily on all platforms. + * + * The has_capability() function was first exported in the 4.10 Linux kernel + * then backported to some LTS kernels. Prior to this change there was no + * mechanism to perform this check therefore EACCES is returned when the + * functionality is not present in the kernel. */ int secpolicy_zfs_proc(const cred_t *cr, proc_t *proc) { +#if defined(HAVE_HAS_CAPABILITY) if (!has_capability(proc, CAP_SYS_ADMIN)) return (EACCES); return (0); +#else + return (EACCES); +#endif } void diff --git a/tests/test-runner/bin/zts-report.py.in b/tests/test-runner/bin/zts-report.py.in index a2d81ceda..51e6e52db 100755 --- a/tests/test-runner/bin/zts-report.py.in +++ b/tests/test-runner/bin/zts-report.py.in @@ -263,6 +263,8 @@ elif sys.platform.startswith('linux'): 'cli_root/zpool_expand/zpool_expand_001_pos': ['FAIL', known_reason], 'cli_root/zpool_expand/zpool_expand_005_pos': ['FAIL', known_reason], 'cli_root/zpool_reopen/zpool_reopen_003_pos': ['FAIL', known_reason], + 'limits/filesystem_limit': ['SKIP', known_reason], + 'limits/snapshot_limit': ['SKIP', known_reason], 'refreserv/refreserv_raidz': ['FAIL', known_reason], 'rsend/rsend_007_pos': ['FAIL', known_reason], 'rsend/rsend_010_pos': ['FAIL', known_reason], diff --git a/tests/zfs-tests/tests/functional/limits/filesystem_limit.ksh b/tests/zfs-tests/tests/functional/limits/filesystem_limit.ksh index cd1e054bf..fbfc141be 100755 --- a/tests/zfs-tests/tests/functional/limits/filesystem_limit.ksh +++ b/tests/zfs-tests/tests/functional/limits/filesystem_limit.ksh @@ -30,6 +30,18 @@ verify_runnable "both" +# +# The has_capability() function was first exported in the 4.10 Linux kernel +# then backported to some LTS kernels. Prior to this change there was no +# mechanism to perform the needed permission check. Therefore, this test +# is expected to fail on older kernels and is skipped. +# +if is_linux; then + if [[ $(linux_version) -lt $(linux_version "4.10") ]]; then + log_unsupported "Requires has_capability() kernel function" + fi +fi + function setup { # We can't delegate 'mount' privs under Linux: to avoid issues with diff --git a/tests/zfs-tests/tests/functional/limits/snapshot_limit.ksh b/tests/zfs-tests/tests/functional/limits/snapshot_limit.ksh index 860a0da92..62f14466e 100755 --- a/tests/zfs-tests/tests/functional/limits/snapshot_limit.ksh +++ b/tests/zfs-tests/tests/functional/limits/snapshot_limit.ksh @@ -31,6 +31,18 @@ verify_runnable "both" +# +# The has_capability() function was first exported in the 4.10 Linux kernel +# then backported to some LTS kernels. Prior to this change there was no +# mechanism to perform the needed permission check. Therefore, this test +# is expected to fail on older kernels and is skipped. +# +if is_linux; then + if [[ $(linux_version) -lt $(linux_version "4.10") ]]; then + log_unsupported "Requires has_capability() kernel function" + fi +fi + function setup { # We can't delegate 'mount' privs under Linux: to avoid issues with