view usr/src/uts/common/fs/nfs/nfs_acl_xdr.c @ 3933:ea83e56013c8

6534147 Vulnerability in the NFS ACL code may lead to kernel panic
author vv149972
date Fri, 30 Mar 2007 07:16:06 -0700
parents 3436e82414c8
children a8930ec16e52
line wrap: on
line source

/*
 * 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.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"


#include <sys/param.h>
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/user.h>
#include <sys/vnode.h>
#include <sys/file.h>
#include <sys/dirent.h>
#include <sys/vfs.h>
#include <sys/stream.h>
#include <sys/strsubr.h>
#include <sys/debug.h>
#include <sys/t_lock.h>
#include <sys/acl.h>

#include <rpc/types.h>
#include <rpc/xdr.h>

#include <nfs/nfs.h>
#include <nfs/nfs_clnt.h>
#include <nfs/nfs_acl.h>

/*
 * These are the XDR routines used to serialize and deserialize
 * the various structures passed as parameters accross the network
 * between ACL clients and servers.
 */

bool_t
xdr_uid(XDR *xdrs, uid32_t *objp)
{
	if (!xdr_int(xdrs, objp))
		return (FALSE);
	return (TRUE);
}

bool_t
xdr_o_mode(XDR *xdrs, o_mode *objp)
{

	if (!xdr_u_short(xdrs, (ushort_t *)objp))
		return (FALSE);
	return (TRUE);
}

bool_t
xdr_aclent(XDR *xdrs, aclent_t *objp)
{

	if (!xdr_int(xdrs, &objp->a_type))
		return (FALSE);
	if (!xdr_uid(xdrs, &objp->a_id))
		return (FALSE);
	if (!xdr_o_mode(xdrs, &objp->a_perm))
		return (FALSE);
	return (TRUE);
}

bool_t
xdr_secattr(XDR *xdrs, vsecattr_t *objp)
{
	uint_t count;

	if (!xdr_u_int(xdrs, &objp->vsa_mask))
		return (FALSE);
	if (!xdr_int(xdrs, &objp->vsa_aclcnt))
		return (FALSE);
	if (objp->vsa_aclentp != NULL)
		count = (uint_t)objp->vsa_aclcnt;
	else
		count = 0;
	if (!xdr_array(xdrs, (char **)&objp->vsa_aclentp, &count,
	    NFS_ACL_MAX_ENTRIES, sizeof (aclent_t), (xdrproc_t)xdr_aclent))
		return (FALSE);
	if (count != 0 && count != (uint_t)objp->vsa_aclcnt) {
		/*
		 * Assign the actual array size to vsa_aclcnt before
		 * aborting on error
		 */
		objp->vsa_aclcnt = (int)count;
		return (FALSE);
	}
	if (!xdr_int(xdrs, &objp->vsa_dfaclcnt))
		return (FALSE);
	if (objp->vsa_dfaclentp != NULL)
		count = (uint_t)objp->vsa_dfaclcnt;
	else
		count = 0;
	if (!xdr_array(xdrs, (char **)&objp->vsa_dfaclentp, &count,
	    NFS_ACL_MAX_ENTRIES, sizeof (aclent_t), (xdrproc_t)xdr_aclent))
		return (FALSE);
	if (count != 0 && count != (uint_t)objp->vsa_dfaclcnt) {
		/*
		 * Assign the actual array size to vsa_dfaclcnt before
		 * aborting on error
		 */
		objp->vsa_dfaclcnt = (int)count;
		return (FALSE);
	}
	return (TRUE);
}

bool_t
xdr_GETACL2args(XDR *xdrs, GETACL2args *objp)
{

	if (!xdr_fhandle(xdrs, &objp->fh))
		return (FALSE);
	if (!xdr_u_int(xdrs, &objp->mask))
		return (FALSE);
	return (TRUE);
}
bool_t
xdr_fastGETACL2args(XDR *xdrs, GETACL2args **objpp)
{
	int32_t *ptr;
#ifdef _LITTLE_ENDIAN
	GETACL2args *objp;
#endif

	if (xdrs->x_op != XDR_DECODE)
		return (FALSE);

	ptr = XDR_INLINE(xdrs, RNDUP(sizeof (GETACL2args)));
	if (ptr != NULL) {
		*objpp = (GETACL2args *)ptr;
#ifdef _LITTLE_ENDIAN
		objp = (GETACL2args *)ptr;
		objp->mask = ntohl(objp->mask);
#endif
		return (TRUE);
	}

	return (FALSE);
}

bool_t
xdr_GETACL2resok(XDR *xdrs, GETACL2resok *objp)
{

	if (!xdr_fattr(xdrs, &objp->attr))
		return (FALSE);
	if (!xdr_secattr(xdrs, &objp->acl))
		return (FALSE);
	return (TRUE);
}

bool_t
xdr_GETACL2res(XDR *xdrs, GETACL2res *objp)
{

	if (!xdr_enum(xdrs, (enum_t *)&objp->status))
		return (FALSE);
	switch (objp->status) {
	case NFS_OK:
		if (!xdr_GETACL2resok(xdrs, &objp->resok))
			return (FALSE);
		break;
	}
	return (TRUE);
}

bool_t
xdr_SETACL2args(XDR *xdrs, SETACL2args *objp)
{

	if (!xdr_fhandle(xdrs, &objp->fh))
		return (FALSE);
	if (!xdr_secattr(xdrs, &objp->acl))
		return (FALSE);
	return (TRUE);
}

bool_t
xdr_SETACL2resok(XDR *xdrs, SETACL2resok *objp)
{

	if (!xdr_fattr(xdrs, &objp->attr))
		return (FALSE);
	return (TRUE);
}
#ifdef _LITTLE_ENDIAN
bool_t
xdr_fastSETACL2resok(XDR *xdrs, SETACL2resok *objp)
{

	if (!xdr_fastfattr(xdrs, &objp->attr))
		return (FALSE);
	return (TRUE);
}
#endif

bool_t
xdr_SETACL2res(XDR *xdrs, SETACL2res *objp)
{

	if (!xdr_enum(xdrs, (enum_t *)&objp->status))
		return (FALSE);
	switch (objp->status) {
	case NFS_OK:
		if (!xdr_SETACL2resok(xdrs, &objp->resok))
			return (FALSE);
		break;
	}
	return (TRUE);
}
#ifdef _LITTLE_ENDIAN
bool_t
xdr_fastSETACL2res(XDR *xdrs, SETACL2res *objp)
{

	if (!xdr_fastenum(xdrs, (enum_t *)&objp->status))
		return (FALSE);
	switch (objp->status) {
	case NFS_OK:
		if (!xdr_fastSETACL2resok(xdrs, &objp->resok))
			return (FALSE);
		break;
	}
	return (TRUE);
}
#endif

bool_t
xdr_GETATTR2args(XDR *xdrs, GETATTR2args *objp)
{

	if (!xdr_fhandle(xdrs, &objp->fh))
		return (FALSE);
	return (TRUE);
}
bool_t
xdr_fastGETATTR2args(XDR *xdrs, GETATTR2args **objpp)
{
	int32_t *ptr;

	if (xdrs->x_op != XDR_DECODE)
		return (FALSE);

	ptr = XDR_INLINE(xdrs, RNDUP(sizeof (GETATTR2args)));
	if (ptr != NULL) {
		*objpp = (GETATTR2args *)ptr;
		return (TRUE);
	}

	return (FALSE);
}

bool_t
xdr_GETATTR2resok(XDR *xdrs, GETATTR2resok *objp)
{

	if (!xdr_fattr(xdrs, &objp->attr))
		return (FALSE);
	return (TRUE);
}
#ifdef _LITTLE_ENDIAN
bool_t
xdr_fastGETATTR2resok(XDR *xdrs, GETATTR2resok *objp)
{

	if (!xdr_fastfattr(xdrs, &objp->attr))
		return (FALSE);
	return (TRUE);
}
#endif

bool_t
xdr_GETATTR2res(XDR *xdrs, GETATTR2res *objp)
{

	if (!xdr_enum(xdrs, (enum_t *)&objp->status))
		return (FALSE);
	switch (objp->status) {
	case NFS_OK:
		if (!xdr_GETATTR2resok(xdrs, &objp->resok))
			return (FALSE);
		break;
	}
	return (TRUE);
}
#ifdef _LITTLE_ENDIAN
bool_t
xdr_fastGETATTR2res(XDR *xdrs, GETATTR2res *objp)
{

	if (!xdr_fastenum(xdrs, (enum_t *)&objp->status))
		return (FALSE);
	switch (objp->status) {
	case NFS_OK:
		if (!xdr_fastGETATTR2resok(xdrs, &objp->resok))
			return (FALSE);
		break;
	}
	return (TRUE);
}
#endif

bool_t
xdr_ACCESS2args(XDR *xdrs, ACCESS2args *objp)
{

	if (!xdr_fhandle(xdrs, &objp->fh))
		return (FALSE);
	if (!xdr_uint32(xdrs, &objp->access))
		return (FALSE);
	return (TRUE);
}
bool_t
xdr_fastACCESS2args(XDR *xdrs, ACCESS2args **objpp)
{
	int32_t *ptr;
#ifdef _LITTLE_ENDIAN
	ACCESS2args *objp;
#endif

	if (xdrs->x_op != XDR_DECODE)
		return (FALSE);

	ptr = XDR_INLINE(xdrs, RNDUP(sizeof (ACCESS2args)));
	if (ptr != NULL) {
		*objpp = (ACCESS2args *)ptr;
#ifdef _LITTLE_ENDIAN
		objp = (ACCESS2args *)ptr;
		objp->access = ntohl(objp->access);
#endif
		return (TRUE);
	}

	return (FALSE);
}

bool_t
xdr_ACCESS2resok(XDR *xdrs, ACCESS2resok *objp)
{

	if (!xdr_fattr(xdrs, &objp->attr))
		return (FALSE);
	if (!xdr_uint32(xdrs, &objp->access))
		return (FALSE);
	return (TRUE);
}
#ifdef _LITTLE_ENDIAN
bool_t
xdr_fastACCESS2resok(XDR *xdrs, ACCESS2resok *objp)
{

	if (!xdr_fastfattr(xdrs, &objp->attr))
		return (FALSE);
	objp->access = ntohl(objp->access);
	return (TRUE);
}
#endif

bool_t
xdr_ACCESS2res(XDR *xdrs, ACCESS2res *objp)
{

	if (!xdr_enum(xdrs, (enum_t *)&objp->status))
		return (FALSE);
	switch (objp->status) {
	case NFS_OK:
		if (!xdr_ACCESS2resok(xdrs, &objp->resok))
			return (FALSE);
		break;
	}
	return (TRUE);
}
#ifdef _LITTLE_ENDIAN
bool_t
xdr_fastACCESS2res(XDR *xdrs, ACCESS2res *objp)
{

	if (!xdr_fastenum(xdrs, (enum_t *)&objp->status))
		return (FALSE);
	switch (objp->status) {
	case NFS_OK:
		if (!xdr_fastACCESS2resok(xdrs, &objp->resok))
			return (FALSE);
		break;
	}
	return (TRUE);
}
#endif

bool_t
xdr_GETXATTRDIR2args(XDR *xdrs, GETXATTRDIR2args *objp)
{
	if (!xdr_fhandle(xdrs, &objp->fh))
		return (FALSE);
	if (!xdr_bool(xdrs, &objp->create))
		return (FALSE);
	return (TRUE);
}

bool_t
xdr_GETXATTRDIR2resok(XDR *xdrs, GETXATTRDIR2resok *objp)
{
	if (!xdr_fhandle(xdrs, &objp->fh))
		return (FALSE);
	if (!xdr_fattr(xdrs, &objp->attr))
		return (FALSE);
	return (TRUE);
}

bool_t
xdr_GETXATTRDIR2res(XDR *xdrs, GETXATTRDIR2res *objp)
{
	if (!xdr_enum(xdrs, (enum_t *)&objp->status))
		return (FALSE);
	switch (objp->status) {
	case NFS_OK:
		if (!xdr_GETXATTRDIR2resok(xdrs, &objp->resok))
			return (FALSE);
		break;
	}
	return (TRUE);
}

bool_t
xdr_GETACL3args(XDR *xdrs, GETACL3args *objp)
{

	switch (xdrs->x_op) {
	case XDR_FREE:
	case XDR_ENCODE:
		if (!xdr_nfs_fh3(xdrs, &objp->fh))
			return (FALSE);
		break;
	case XDR_DECODE:
		if (!xdr_nfs_fh3_server(xdrs, &objp->fh))
			return (FALSE);
		break;
	}
	if (!xdr_u_int(xdrs, &objp->mask))
		return (FALSE);
	return (TRUE);
}

bool_t
xdr_GETACL3resok(XDR *xdrs, GETACL3resok *objp)
{

	if (!xdr_post_op_attr(xdrs, &objp->attr))
		return (FALSE);
	if (!xdr_secattr(xdrs, &objp->acl))
		return (FALSE);
	return (TRUE);
}

bool_t
xdr_GETACL3resfail(XDR *xdrs, GETACL3resfail *objp)
{

	if (!xdr_post_op_attr(xdrs, &objp->attr))
		return (FALSE);
	return (TRUE);
}

bool_t
xdr_GETACL3res(XDR *xdrs, GETACL3res *objp)
{

	if (!xdr_enum(xdrs, (enum_t *)&objp->status))
		return (FALSE);
	switch (objp->status) {
	case NFS3_OK:
		if (!xdr_GETACL3resok(xdrs, &objp->resok))
			return (FALSE);
		break;
	default:
		if (!xdr_GETACL3resfail(xdrs, &objp->resfail))
			return (FALSE);
		break;
	}
	return (TRUE);
}

bool_t
xdr_SETACL3args(XDR *xdrs, SETACL3args *objp)
{

	switch (xdrs->x_op) {
	case XDR_FREE:
	case XDR_ENCODE:
		if (!xdr_nfs_fh3(xdrs, &objp->fh))
			return (FALSE);
		break;
	case XDR_DECODE:
		if (!xdr_nfs_fh3_server(xdrs, &objp->fh))
			return (FALSE);
		break;
	}
	if (!xdr_secattr(xdrs, &objp->acl))
		return (FALSE);
	return (TRUE);
}

bool_t
xdr_SETACL3resok(XDR *xdrs, SETACL3resok *objp)
{

	if (!xdr_post_op_attr(xdrs, &objp->attr))
		return (FALSE);
	return (TRUE);
}

bool_t
xdr_SETACL3resfail(XDR *xdrs, SETACL3resfail *objp)
{

	if (!xdr_post_op_attr(xdrs, &objp->attr))
		return (FALSE);
	return (TRUE);
}

bool_t
xdr_SETACL3res(XDR *xdrs, SETACL3res *objp)
{

	if (!xdr_enum(xdrs, (enum_t *)&objp->status))
		return (FALSE);
	switch (objp->status) {
	case NFS3_OK:
		if (!xdr_SETACL3resok(xdrs, &objp->resok))
			return (FALSE);
		break;
	default:
		if (!xdr_SETACL3resfail(xdrs, &objp->resfail))
			return (FALSE);
		break;
	}
	return (TRUE);
}

bool_t
xdr_GETXATTRDIR3args(XDR *xdrs, GETXATTRDIR3args *objp)
{
	switch (xdrs->x_op) {
	case XDR_FREE:
	case XDR_ENCODE:
		if (!xdr_nfs_fh3(xdrs, &objp->fh))
			return (FALSE);
		break;
	case XDR_DECODE:
		if (!xdr_nfs_fh3_server(xdrs, &objp->fh))
			return (FALSE);
		break;
	}
	if (!xdr_bool(xdrs, &objp->create))
		return (FALSE);
	return (TRUE);
}

bool_t
xdr_GETXATTRDIR3resok(XDR *xdrs, GETXATTRDIR3resok *objp)
{
	switch (xdrs->x_op) {
	case XDR_ENCODE:
		if (!xdr_nfs_fh3_server(xdrs, &objp->fh))
			return (FALSE);
		break;
	case XDR_FREE:
	case XDR_DECODE:
		if (!xdr_nfs_fh3(xdrs, &objp->fh))
			return (FALSE);
		break;
	}
	if (!xdr_post_op_attr(xdrs, &objp->attr))
		return (FALSE);
	return (TRUE);
}

bool_t
xdr_GETXATTRDIR3res(XDR *xdrs, GETXATTRDIR3res *objp)
{
	if (!xdr_enum(xdrs, (enum_t *)&objp->status))
		return (FALSE);
	switch (objp->status) {
	case NFS_OK:
		if (!xdr_GETXATTRDIR3resok(xdrs, &objp->resok))
			return (FALSE);
		break;
	}
	return (TRUE);
}