CVE-2020-24716 (C, published 2020-08-27T19:15Z)
Description: value: OpenZFS before 2.0.0-rc1, when used on FreeBSD, allows execute permissions for all directories.
Severity: MEDIUM (CVSS v3 base score: 7.8)
Weakness: CWE-863 \u2014 Incorrect Authorization
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.
Repository: https://github.com/openzfs/zfs
Files changed:
include/os/freebsd/spl/sys/idmap.h
include/os/freebsd/spl/sys/kidmap.h
include/os/freebsd/spl/sys/sid.h
module/Makefile.bsd
module/os/freebsd/zfs/zfs_acl.c
module/zfs/zfs_fuid.c
Commit message: 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 

Vulnerable code:
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
	zfs_fuid_os.c \
	boolean_t owner = B_FALSE;
	boolean_t groupmbr = B_FALSE;
	uid_t uid = crgetuid(cr);
	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);
/*
 * 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);
}
#ifdef HAVE_KSID
#else
	/*
	 * The Linux port only supports POSIX IDs, use the passed id.
	 */
	return (fuid);
#endif /* HAVE_KSID */
	uint32_t rid;
	uint64_t idx = 0;
	uid_t		gid;

Fixed code:
/*
 * 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 */
/*
 * 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_ */
#include <sys/idmap.h>
#include <sys/kidmap.h>
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
#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
#endif
	uint32_t rid = 0;
	uint64_t idx = UID_NOBODY;
	uid_t		gid;

#ifdef illumos
#endif /* illumos */