]> granicus.if.org Git - zfs/commitdiff
Implement secpolicy_vnode_setid_retain()
authorTomohiro Kusumi <kusumi.tomohiro@gmail.com>
Fri, 26 Jul 2019 20:52:30 +0000 (05:52 +0900)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Fri, 26 Jul 2019 20:52:30 +0000 (13:52 -0700)
Don't unconditionally return 0 (i.e. retain SUID/SGID).
Test CAP_FSETID capability.

https://github.com/pjd/pjdfstest/blob/master/tests/chmod/12.t
which expects SUID/SGID to be dropped on write(2) by non-owner fails
without this. Most filesystems make this decision within VFS by using
a generic file write for fops.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Tomohiro Kusumi <kusumi.tomohiro@gmail.com>
Closes #9035
Closes #9043

13 files changed:
configure.ac
module/zfs/policy.c
tests/runfiles/linux.run
tests/zfs-tests/tests/functional/Makefile.am
tests/zfs-tests/tests/functional/suid/.gitignore [new file with mode: 0644]
tests/zfs-tests/tests/functional/suid/Makefile.am [new file with mode: 0644]
tests/zfs-tests/tests/functional/suid/cleanup.ksh [new file with mode: 0755]
tests/zfs-tests/tests/functional/suid/setup.ksh [new file with mode: 0755]
tests/zfs-tests/tests/functional/suid/suid_write_to_file.c [new file with mode: 0644]
tests/zfs-tests/tests/functional/suid/suid_write_to_none.ksh [new file with mode: 0755]
tests/zfs-tests/tests/functional/suid/suid_write_to_sgid.ksh [new file with mode: 0755]
tests/zfs-tests/tests/functional/suid/suid_write_to_suid.ksh [new file with mode: 0755]
tests/zfs-tests/tests/functional/suid/suid_write_to_suid_sgid.ksh [new file with mode: 0755]

index 01043422565f151ec1faf0d92582ccb87ff1728e..0522185e4dd9650c2b6fdbb7b838fe5ab6110744 100644 (file)
@@ -332,6 +332,7 @@ AC_CONFIG_FILES([
        tests/zfs-tests/tests/functional/snapshot/Makefile
        tests/zfs-tests/tests/functional/snapused/Makefile
        tests/zfs-tests/tests/functional/sparse/Makefile
+       tests/zfs-tests/tests/functional/suid/Makefile
        tests/zfs-tests/tests/functional/alloc_class/Makefile
        tests/zfs-tests/tests/functional/threadsappend/Makefile
        tests/zfs-tests/tests/functional/tmpfile/Makefile
index 55c9327479153d1668d77b39d20d7b51557cb5e6..a723235d3015520bc2db8482cc3133818da6aec5 100644 (file)
@@ -209,7 +209,7 @@ secpolicy_vnode_setdac(const cred_t *cr, uid_t owner)
 int
 secpolicy_vnode_setid_retain(const cred_t *cr, boolean_t issuidroot)
 {
-       return (0);
+       return (priv_policy_user(cr, CAP_FSETID, B_FALSE, EPERM));
 }
 
 /*
index e9db661308ba2572b61c5ca98f3a2c54e32eac23..c554e578d53aad4a300c0225ea5badcb2ddc6de4 100644 (file)
@@ -856,6 +856,11 @@ tags = ['functional', 'snapused']
 tests = ['sparse_001_pos']
 tags = ['functional', 'sparse']
 
+[tests/functional/suid]
+tests = ['suid_write_to_suid', 'suid_write_to_sgid', 'suid_write_to_suid_sgid',
+    'suid_write_to_none']
+tags = ['functional', 'suid']
+
 [tests/functional/threadsappend]
 tests = ['threadsappend_001_pos']
 tags = ['functional', 'threadsappend']
index 783fdfb8aa7c0f00e383bf7a1bb9ec08acddcac1..6c9cb3e0492917510086a9d798712f255559dba3 100644 (file)
@@ -68,6 +68,7 @@ SUBDIRS = \
        snapshot \
        snapused \
        sparse \
+       suid \
        threadsappend \
        tmpfile \
        trim \
diff --git a/tests/zfs-tests/tests/functional/suid/.gitignore b/tests/zfs-tests/tests/functional/suid/.gitignore
new file mode 100644 (file)
index 0000000..a9a3db7
--- /dev/null
@@ -0,0 +1 @@
+/suid_write_to_file
diff --git a/tests/zfs-tests/tests/functional/suid/Makefile.am b/tests/zfs-tests/tests/functional/suid/Makefile.am
new file mode 100644 (file)
index 0000000..594d2b7
--- /dev/null
@@ -0,0 +1,16 @@
+include $(top_srcdir)/config/Rules.am
+
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/suid
+
+dist_pkgdata_SCRIPTS = \
+       suid_write_to_suid.ksh \
+       suid_write_to_sgid.ksh \
+       suid_write_to_suid_sgid.ksh \
+       suid_write_to_none.ksh \
+       cleanup.ksh \
+       setup.ksh
+
+pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/suid
+
+pkgexec_PROGRAMS = suid_write_to_file
+suid_write_to_file_SOURCES = suid_write_to_file.c
diff --git a/tests/zfs-tests/tests/functional/suid/cleanup.ksh b/tests/zfs-tests/tests/functional/suid/cleanup.ksh
new file mode 100755 (executable)
index 0000000..6e41e02
--- /dev/null
@@ -0,0 +1,34 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2019 by Tomohiro Kusumi. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/tests/zfs-tests/tests/functional/suid/setup.ksh b/tests/zfs-tests/tests/functional/suid/setup.ksh
new file mode 100755 (executable)
index 0000000..d04d556
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2019 by Tomohiro Kusumi. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+default_setup $DISK
diff --git a/tests/zfs-tests/tests/functional/suid/suid_write_to_file.c b/tests/zfs-tests/tests/functional/suid/suid_write_to_file.c
new file mode 100644 (file)
index 0000000..571dc55
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2019 by Tomohiro Kusumi. All rights reserved.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+static void
+test_stat_mode(mode_t extra)
+{
+       struct stat st;
+       int i, fd;
+       char fpath[1024];
+       char *penv[] = {"TESTDIR", "TESTFILE0"};
+       char buf[] = "test";
+       mode_t res;
+       mode_t mode = 0777 | extra;
+
+       /*
+        * Get the environment variable values.
+        */
+       for (i = 0; i < sizeof (penv) / sizeof (char *); i++) {
+               if ((penv[i] = getenv(penv[i])) == NULL) {
+                       fprintf(stderr, "getenv(penv[%d])\n", i);
+                       exit(1);
+               }
+       }
+
+       umask(0);
+       if (stat(penv[0], &st) == -1 && mkdir(penv[0], mode) == -1) {
+               perror("mkdir");
+               exit(2);
+       }
+
+       snprintf(fpath, sizeof (fpath), "%s/%s", penv[0], penv[1]);
+       unlink(fpath);
+       if (stat(fpath, &st) == 0) {
+               fprintf(stderr, "%s exists\n", fpath);
+               exit(3);
+       }
+
+       fd = creat(fpath, mode);
+       if (fd == -1) {
+               perror("creat");
+               exit(4);
+       }
+       close(fd);
+
+       if (setuid(65534) == -1) {
+               perror("setuid");
+               exit(5);
+       }
+
+       fd = open(fpath, O_RDWR);
+       if (fd == -1) {
+               perror("open");
+               exit(6);
+       }
+
+       if (write(fd, buf, sizeof (buf)) == -1) {
+               perror("write");
+               exit(7);
+       }
+       close(fd);
+
+       if (stat(fpath, &st) == -1) {
+               perror("stat");
+               exit(8);
+       }
+       unlink(fpath);
+
+       /* Verify SUID/SGID are dropped */
+       res = st.st_mode & (0777 | S_ISUID | S_ISGID);
+       if (res != (mode & 0777)) {
+               fprintf(stderr, "stat(2) %o\n", res);
+               exit(9);
+       }
+}
+
+int
+main(int argc, char *argv[])
+{
+       const char *name;
+       mode_t extra;
+
+       if (argc < 2) {
+               fprintf(stderr, "Invalid argc\n");
+               exit(1);
+       }
+
+       name = argv[1];
+       if (strcmp(name, "SUID") == 0) {
+               extra = S_ISUID;
+       } else if (strcmp(name, "SGID") == 0) {
+               extra = S_ISGID;
+       } else if (strcmp(name, "SUID_SGID") == 0) {
+               extra = S_ISUID | S_ISGID;
+       } else if (strcmp(name, "NONE") == 0) {
+               extra = 0;
+       } else {
+               fprintf(stderr, "Invalid name %s\n", name);
+               exit(1);
+       }
+
+       test_stat_mode(extra);
+
+       return (0);
+}
diff --git a/tests/zfs-tests/tests/functional/suid/suid_write_to_none.ksh b/tests/zfs-tests/tests/functional/suid/suid_write_to_none.ksh
new file mode 100755 (executable)
index 0000000..dd01978
--- /dev/null
@@ -0,0 +1,52 @@
+#! /bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2019 by Tomohiro Kusumi. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify write(2) to regular file by non-owner.
+# Also see https://github.com/pjd/pjdfstest/blob/master/tests/chmod/12.t
+#
+# STRATEGY:
+# 1. creat(2) a file.
+# 2. write(2) to the file with uid=65534.
+# 3. stat(2) the file and verify .st_mode value.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       rm -f $TESTDIR/$TESTFILE0
+}
+
+log_onexit cleanup
+log_note "Verify write(2) to regular file by non-owner"
+
+log_must $STF_SUITE/tests/functional/suid/suid_write_to_file "NONE"
+
+log_pass "Verify write(2) to regular file by non-owner passed"
diff --git a/tests/zfs-tests/tests/functional/suid/suid_write_to_sgid.ksh b/tests/zfs-tests/tests/functional/suid/suid_write_to_sgid.ksh
new file mode 100755 (executable)
index 0000000..49ae2bd
--- /dev/null
@@ -0,0 +1,52 @@
+#! /bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2019 by Tomohiro Kusumi. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify write(2) to SGID file by non-owner.
+# Also see https://github.com/pjd/pjdfstest/blob/master/tests/chmod/12.t
+#
+# STRATEGY:
+# 1. creat(2) a file with SGID.
+# 2. write(2) to the file with uid=65534.
+# 3. stat(2) the file and verify .st_mode value.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       rm -f $TESTDIR/$TESTFILE0
+}
+
+log_onexit cleanup
+log_note "Verify write(2) to SGID file by non-owner"
+
+log_must $STF_SUITE/tests/functional/suid/suid_write_to_file "SGID"
+
+log_pass "Verify write(2) to SGID file by non-owner passed"
diff --git a/tests/zfs-tests/tests/functional/suid/suid_write_to_suid.ksh b/tests/zfs-tests/tests/functional/suid/suid_write_to_suid.ksh
new file mode 100755 (executable)
index 0000000..3983aad
--- /dev/null
@@ -0,0 +1,52 @@
+#! /bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2019 by Tomohiro Kusumi. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify write(2) to SUID file by non-owner.
+# Also see https://github.com/pjd/pjdfstest/blob/master/tests/chmod/12.t
+#
+# STRATEGY:
+# 1. creat(2) a file with SUID.
+# 2. write(2) to the file with uid=65534.
+# 3. stat(2) the file and verify .st_mode value.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       rm -f $TESTDIR/$TESTFILE0
+}
+
+log_onexit cleanup
+log_note "Verify write(2) to SUID file by non-owner"
+
+log_must $STF_SUITE/tests/functional/suid/suid_write_to_file "SUID"
+
+log_pass "Verify write(2) to SUID file by non-owner passed"
diff --git a/tests/zfs-tests/tests/functional/suid/suid_write_to_suid_sgid.ksh b/tests/zfs-tests/tests/functional/suid/suid_write_to_suid_sgid.ksh
new file mode 100755 (executable)
index 0000000..a058c7e
--- /dev/null
@@ -0,0 +1,52 @@
+#! /bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2019 by Tomohiro Kusumi. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify write(2) to SUID/SGID file by non-owner.
+# Also see https://github.com/pjd/pjdfstest/blob/master/tests/chmod/12.t
+#
+# STRATEGY:
+# 1. creat(2) a file with SUID/SGID.
+# 2. write(2) to the file with uid=65534.
+# 3. stat(2) the file and verify .st_mode value.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       rm -f $TESTDIR/$TESTFILE0
+}
+
+log_onexit cleanup
+log_note "Verify write(2) to SUID/SGID file by non-owner"
+
+log_must $STF_SUITE/tests/functional/suid/suid_write_to_file "SUID_SGID"
+
+log_pass "Verify write(2) to SUID/SGID file by non-owner passed"