CVE-2020-24716 (published 2020-08-27T19:15Z)

OpenZFS before 2.0.0-rc1, when used on FreeBSD, allows execute permissions for all directories.

Severity: MEDIUM
CVSS v2 base score: 4.6 (AV:L/AC:L/Au:N/C:P/I:P/A:P)
CVSS v3 base score: 7.8, HIGH (CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-863
cwe_name: Incorrect Authorization
description: The product performs an authorization check when an actor attempts to access a resource or perform an action, but it does not correctly perform the check. This allows attackers to bypass intended access restrictions.
extended_description: 
            Assuming a user with a given identity, authorization is the process of determining whether that user can access a given resource, based on the user's privileges and any permissions or other access-control specifications that apply to the resource.
            When access control checks are incorrectly applied, users are able to access data or perform actions that they should not be allowed to perform. This can lead to a wide range of problems, including information exposures, denial of service, and arbitrary code execution.
         
         

Fix information:
repo_url: https://github.com/openzfs/zfs
commit_details: repo_url: https://github.com/openzfs/zfs
author: Matthew Macy
author_date: 2020-08-18 09:57:07-07:00
msg: FreeBSD: Fix UNIX permissions checking

Reviewed-by: Ryan Moeller <ryan@iXsystems.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Matt Macy <mmacy@FreeBSD.org>
Closes #10727
repository: repo_url: https://github.com/openzfs/zfs
repo_name: openzfs/zfs
description: OpenZFS on Linux and FreeBSD
repo_language: C
owner: openzfs
file_changes: filename: idmap.h
change_type: ModificationType.ADD
diff: @@ -0,0 +1,97 @@
+/*
+ * 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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_IDMAP_H
+#define	_SYS_IDMAP_H
+
+
+/* Idmap status codes */
+#define	IDMAP_SUCCESS			0
+#define	IDMAP_NEXT			1
+#define	IDMAP_ERR_OTHER			-10000
+#define	IDMAP_ERR_INTERNAL		-9999
+#define	IDMAP_ERR_MEMORY		-9998
+#define	IDMAP_ERR_NORESULT		-9997
+#define	IDMAP_ERR_NOTUSER		-9996
+#define	IDMAP_ERR_NOTGROUP		-9995
+#define	IDMAP_ERR_NOTSUPPORTED		-9994
+#define	IDMAP_ERR_W2U_NAMERULE		-9993
+#define	IDMAP_ERR_U2W_NAMERULE		-9992
+#define	IDMAP_ERR_CACHE			-9991
+#define	IDMAP_ERR_DB			-9990
+#define	IDMAP_ERR_ARG			-9989
+#define	IDMAP_ERR_SID			-9988
+#define	IDMAP_ERR_IDTYPE		-9987
+#define	IDMAP_ERR_RPC_HANDLE		-9986
+#define	IDMAP_ERR_RPC			-9985
+#define	IDMAP_ERR_CLIENT_HANDLE		-9984
+#define	IDMAP_ERR_BUSY			-9983
+#define	IDMAP_ERR_PERMISSION_DENIED	-9982
+#define	IDMAP_ERR_NOMAPPING		-9981
+#define	IDMAP_ERR_NEW_ID_ALLOC_REQD	-9980
+#define	IDMAP_ERR_DOMAIN		-9979
+#define	IDMAP_ERR_SECURITY		-9978
+#define	IDMAP_ERR_NOTFOUND		-9977
+#define	IDMAP_ERR_DOMAIN_NOTFOUND	-9976
+#define	IDMAP_ERR_UPDATE_NOTALLOWED	-9975
+#define	IDMAP_ERR_CFG			-9974
+#define	IDMAP_ERR_CFG_CHANGE		-9973
+#define	IDMAP_ERR_NOTMAPPED_WELLKNOWN	-9972
+#define	IDMAP_ERR_RETRIABLE_NET_ERR	-9971
+#define	IDMAP_ERR_W2U_NAMERULE_CONFLICT	-9970
+#define	IDMAP_ERR_U2W_NAMERULE_CONFLICT	-9969
+#define	IDMAP_ERR_BAD_UTF8		-9968
+#define	IDMAP_ERR_NONE_GENERATED	-9967
+#define	IDMAP_ERR_PROP_UNKNOWN		-9966
+#define	IDMAP_ERR_NS_LDAP_OP_FAILED	-9965
+#define	IDMAP_ERR_NS_LDAP_PARTIAL	-9964
+#define	IDMAP_ERR_NS_LDAP_CFG		-9963
+#define	IDMAP_ERR_NS_LDAP_BAD_WINNAME	-9962
+#define	IDMAP_ERR_NO_ACTIVEDIRECTORY	-9961
+
+/* Reserved GIDs for some well-known SIDs */
+#define	IDMAP_WK_LOCAL_SYSTEM_GID	2147483648U /* 0x80000000 */
+#define	IDMAP_WK_CREATOR_GROUP_GID	2147483649U
+#define	IDMAP_WK__MAX_GID		2147483649U
+
+/* Reserved UIDs for some well-known SIDs */
+#define	IDMAP_WK_CREATOR_OWNER_UID	2147483648U
+#define	IDMAP_WK__MAX_UID		2147483648U
+
+/* Reserved SIDs */
+#define	IDMAP_WK_CREATOR_SID_AUTHORITY	"S-1-3"
+
+/*
+ * Max door RPC size for ID mapping (can't be too large relative to the
+ * default user-land thread stack size, since clnt_door_call()
+ * alloca()s).  See libidmap:idmap_init().
+ */
+#define	IDMAP_MAX_DOOR_RPC		(256 * 1024)
+
+#define	IDMAP_SENTINEL_PID		UINT32_MAX
+#define	IDMAP_ID_IS_EPHEMERAL(pid)	\
+	(((pid) > INT32_MAX) && ((pid) != IDMAP_SENTINEL_PID))
+
+#endif /* _SYS_IDMAP_H */

programming_language: C
filename: kidmap.h
change_type: ModificationType.ADD
diff: @@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _OPENSOLARIS_SYS_KIDMAP_H_
+#define	_OPENSOLARIS_SYS_KIDMAP_H_
+
+#include <sys/idmap.h>
+
+typedef int32_t	idmap_stat;
+typedef void	idmap_get_handle_t;
+
+#define	kidmap_get_create()		(NULL)
+#define	kidmap_get_destroy(hdl)		do { } while (0)
+#define	kidmap_get_mappings(hdl)	(NULL)
+
+#endif	/* _OPENSOLARIS_SYS_KIDMAP_H_ */

programming_language: C
filename: sid.h
change_type: ModificationType.MODIFY
diff: @@ -28,6 +28,8 @@
 
 #ifndef _OPENSOLARIS_SYS_SID_H_
 #define	_OPENSOLARIS_SYS_SID_H_
+#include <sys/idmap.h>
+#include <sys/kidmap.h>
 
 typedef struct ksiddomain {
 	char	*kd_name;	/* Domain part of SID */

programming_language: C
filename: Makefile.bsd
change_type: ModificationType.MODIFY
diff: @@ -27,9 +27,9 @@ CFLAGS+= -I${INCDIR}/os/freebsd/spl
 CFLAGS+= -I${INCDIR}/os/freebsd/zfs
 CFLAGS+= -include ${INCDIR}/os/freebsd/spl/sys/ccompile.h
 
-CFLAGS+= -D__KERNEL__ -DFREEBSD_NAMECACHE -DBUILDING_ZFS  -D__BSD_VISIBLE=1
-CFLAGS+= -DHAVE_UIO_ZEROCOPY -DWITHOUT_NETDUMP -D__KERNEL -D_SYS_CONDVAR_H_
-CFLAGS+= -D_SYS_VMEM_H_ -DKDTRACE_HOOKS -DSMP
+CFLAGS+= -D__KERNEL__ -DFREEBSD_NAMECACHE -DBUILDING_ZFS  -D__BSD_VISIBLE=1 \
+	 -DHAVE_UIO_ZEROCOPY -DWITHOUT_NETDUMP -D__KERNEL -D_SYS_CONDVAR_H_ \
+	 -D_SYS_VMEM_H_ -DKDTRACE_HOOKS -DSMP -DHAVE_KSID
 
 .if ${MACHINE_ARCH} == "amd64"
 CFLAGS+= -DHAVE_AVX2 -DHAVE_AVX -D__x86_64 -DHAVE_SSE2 -DHAVE_AVX512F -DHAVE_SSSE3
@@ -276,7 +276,6 @@ SRCS+=	abd.c \
 	zfs_file_os.c \
 	zfs_fm.c \
 	zfs_fuid.c \
-	zfs_fuid_os.c \
 	zfs_ioctl.c \
 	zfs_onexit.c \
 	zfs_quota.c \

programming_language: Shell
filename: zfs_acl.c
change_type: ModificationType.MODIFY
diff: @@ -2305,10 +2305,7 @@ zfs_zaccess_append(znode_t *zp, uint32_t *working_mode, boolean_t *check_privs,
 int
 zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr)
 {
-	boolean_t owner = B_FALSE;
-	boolean_t groupmbr = B_FALSE;
 	boolean_t is_attr;
-	uid_t uid = crgetuid(cr);
 
 	if (zdp->z_pflags & ZFS_AV_QUARANTINED)
 		return (1);
@@ -2321,37 +2318,6 @@ zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr)
 	if (zdp->z_pflags & ZFS_NO_EXECS_DENIED)
 		return (0);
 
-	mutex_enter(&zdp->z_acl_lock);
-	if (FUID_INDEX(zdp->z_uid) != 0 || FUID_INDEX(zdp->z_gid) != 0) {
-		goto out_slow;
-	}
-
-	if (uid == zdp->z_uid) {
-		owner = B_TRUE;
-		if (zdp->z_mode & S_IXUSR) {
-			goto out;
-		} else {
-			goto out_slow;
-		}
-	}
-	if (groupmember(zdp->z_gid, cr)) {
-		groupmbr = B_TRUE;
-		if (zdp->z_mode & S_IXGRP) {
-			goto out;
-		} else {
-			goto out_slow;
-		}
-	}
-	if (!owner && !groupmbr) {
-		if (zdp->z_mode & S_IXOTH) {
-			goto out;
-		}
-	}
-out:
-	mutex_exit(&zdp->z_acl_lock);
-	return (0);
-out_slow:
-	mutex_exit(&zdp->z_acl_lock);
 	return (1);
 }
 

programming_language: C
filename: zfs_fuid_os.c
change_type: ModificationType.DELETE
diff: @@ -1,51 +0,0 @@
-/*
- * 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) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-#include <sys/zfs_context.h>
-#include <sys/dmu.h>
-#include <sys/avl.h>
-#include <sys/zap.h>
-#include <sys/nvpair.h>
-#ifdef _KERNEL
-#include <sys/sid.h>
-#include <sys/zfs_vfsops.h>
-#include <sys/zfs_znode.h>
-#endif
-#include <sys/zfs_fuid.h>
-
-uint64_t
-zfs_fuid_create_cred(zfsvfs_t *zfsvfs, zfs_fuid_type_t type,
-    cred_t *cr, zfs_fuid_info_t **fuidp)
-{
-	uid_t		id;
-
-	VERIFY(type == ZFS_OWNER || type == ZFS_GROUP);
-
-	id = (type == ZFS_OWNER) ? crgetuid(cr) : crgetgid(cr);
-
-	if (IS_EPHEMERAL(id))
-		return ((type == ZFS_OWNER) ? UID_NOBODY : GID_NOBODY);
-
-	return ((uint64_t)id);
-}

programming_language: unknown
filename: zfs_fuid.c
change_type: ModificationType.MODIFY
diff: @@ -387,11 +387,34 @@ zfs_fuid_map_ids(znode_t *zp, cred_t *cr, uid_t *uidp, uid_t *gidp)
 	    cr, ZFS_GROUP);
 }
 
+#ifdef __FreeBSD__
+uid_t
+zfs_fuid_map_id(zfsvfs_t *zfsvfs, uint64_t fuid,
+    cred_t *cr, zfs_fuid_type_t type)
+{
+	uint32_t index = FUID_INDEX(fuid);
+
+	if (index == 0)
+		return (fuid);
+
+	return (UID_NOBODY);
+}
+#elif defined(__linux__)
+uid_t
+zfs_fuid_map_id(zfsvfs_t *zfsvfs, uint64_t fuid,
+    cred_t *cr, zfs_fuid_type_t type)
+{
+	/*
+	 * The Linux port only supports POSIX IDs, use the passed id.
+	 */
+	return (fuid);
+}
+
+#else
 uid_t
 zfs_fuid_map_id(zfsvfs_t *zfsvfs, uint64_t fuid,
     cred_t *cr, zfs_fuid_type_t type)
 {
-#ifdef HAVE_KSID
 	uint32_t index = FUID_INDEX(fuid);
 	const char *domain;
 	uid_t id;
@@ -410,13 +433,8 @@ zfs_fuid_map_id(zfsvfs_t *zfsvfs, uint64_t fuid,
 		    FUID_RID(fuid), &id);
 	}
 	return (id);
-#else
-	/*
-	 * The Linux port only supports POSIX IDs, use the passed id.
-	 */
-	return (fuid);
-#endif /* HAVE_KSID */
 }
+#endif
 
 /*
  * Add a FUID node to the list of fuid's being created for this
@@ -559,9 +577,9 @@ zfs_fuid_create(zfsvfs_t *zfsvfs, uint64_t id, cred_t *cr,
 	const char *domain;
 	char *kdomain;
 	uint32_t fuid_idx = FUID_INDEX(id);
-	uint32_t rid;
+	uint32_t rid = 0;
 	idmap_stat status;
-	uint64_t idx = 0;
+	uint64_t idx = UID_NOBODY;
 	zfs_fuid_t *zfuid = NULL;
 	zfs_fuid_info_t *fuidp = NULL;
 
@@ -711,9 +729,11 @@ boolean_t
 zfs_groupmember(zfsvfs_t *zfsvfs, uint64_t id, cred_t *cr)
 {
 #ifdef HAVE_KSID
+	uid_t		gid;
+
+#ifdef illumos
 	ksid_t		*ksid = crgetsid(cr, KSID_GROUP);
 	ksidlist_t	*ksidlist = crgetsidlist(cr);
-	uid_t		gid;
 
 	if (ksid && ksidlist) {
 		int		i;
@@ -746,6 +766,7 @@ zfs_groupmember(zfsvfs_t *zfsvfs, uint64_t id, cred_t *cr)
 			}
 		}
 	}
+#endif /* illumos */
 
 	/*
 	 * Not found in ksidlist, check posix groups

programming_language: C