Commit d1c263a0 authored by Chuck Lever's avatar Chuck Lever
Browse files

NFSD: Replace READ* macros in nfsd4_decode_fattr()



Let's be more careful to avoid overrunning the memory that backs
the bitmap array. This requires updating the synopsis of
nfsd4_decode_fattr().

Bruce points out that a server needs to be careful to return nfs_ok
when a client presents bitmap bits the server doesn't support. This
includes bits in bitmap words the server might not yet support.

The current READ* based implementation is good about that, but that
requirement hasn't been documented.

Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
parent 66f0476c
Loading
Loading
Loading
Loading
+64 −18
Original line number Diff line number Diff line
@@ -260,6 +260,46 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval)
	DECODE_TAIL;
}

/**
 * nfsd4_decode_bitmap4 - Decode an NFSv4 bitmap4
 * @argp: NFSv4 compound argument structure
 * @bmval: pointer to an array of u32's to decode into
 * @bmlen: size of the @bmval array
 *
 * The server needs to return nfs_ok rather than nfserr_bad_xdr when
 * encountering bitmaps containing bits it does not recognize. This
 * includes bits in bitmap words past WORDn, where WORDn is the last
 * bitmap WORD the implementation currently supports. Thus we are
 * careful here to simply ignore bits in bitmap words that this
 * implementation has yet to support explicitly.
 *
 * Return values:
 *   %nfs_ok: @bmval populated successfully
 *   %nfserr_bad_xdr: the encoded bitmap was invalid
 */
static __be32
nfsd4_decode_bitmap4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen)
{
	u32 i, count;
	__be32 *p;

	if (xdr_stream_decode_u32(argp->xdr, &count) < 0)
		return nfserr_bad_xdr;
	/* request sanity */
	if (count > 1000)
		return nfserr_bad_xdr;
	p = xdr_inline_decode(argp->xdr, count << 2);
	if (!p)
		return nfserr_bad_xdr;
	i = 0;
	while (i < count)
		bmval[i++] = be32_to_cpup(p++);
	while (i < bmlen)
		bmval[i++] = 0;

	return nfs_ok;
}

static __be32
nfsd4_decode_nfsace4(struct nfsd4_compoundargs *argp, struct nfs4_ace *ace)
{
@@ -352,17 +392,18 @@ nfsd4_decode_security_label(struct nfsd4_compoundargs *argp,
}

static __be32
nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
nfsd4_decode_fattr4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen,
		    struct iattr *iattr, struct nfs4_acl **acl,
		    struct xdr_netobj *label, int *umask)
{
	unsigned int starting_pos;
	u32 attrlist4_count;
	__be32 *p, status;

	DECODE_HEAD;
	iattr->ia_valid = 0;
	if ((status = nfsd4_decode_bitmap(argp, bmval)))
		return status;
	status = nfsd4_decode_bitmap4(argp, bmval, bmlen);
	if (status)
		return nfserr_bad_xdr;

	if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0
	    || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1
@@ -490,7 +531,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
	if (attrlist4_count != xdr_stream_pos(argp->xdr) - starting_pos)
		return nfserr_bad_xdr;

	DECODE_TAIL;
	return nfs_ok;
}

static __be32
@@ -690,9 +731,10 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create
	if ((status = check_filename(create->cr_name, create->cr_namelen)))
		return status;

	status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr,
				    &create->cr_acl, &create->cr_label,
				    &create->cr_umask);
	status = nfsd4_decode_fattr4(argp, create->cr_bmval,
				    ARRAY_SIZE(create->cr_bmval),
				    &create->cr_iattr, &create->cr_acl,
				    &create->cr_label, &create->cr_umask);
	if (status)
		goto out;

@@ -941,9 +983,10 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
		switch (open->op_createmode) {
		case NFS4_CREATE_UNCHECKED:
		case NFS4_CREATE_GUARDED:
			status = nfsd4_decode_fattr(argp, open->op_bmval,
				&open->op_iattr, &open->op_acl, &open->op_label,
				&open->op_umask);
			status = nfsd4_decode_fattr4(argp, open->op_bmval,
						     ARRAY_SIZE(open->op_bmval),
						     &open->op_iattr, &open->op_acl,
						     &open->op_label, &open->op_umask);
			if (status)
				goto out;
			break;
@@ -956,9 +999,10 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
				goto xdr_error;
			READ_BUF(NFS4_VERIFIER_SIZE);
			COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE);
			status = nfsd4_decode_fattr(argp, open->op_bmval,
				&open->op_iattr, &open->op_acl, &open->op_label,
				&open->op_umask);
			status = nfsd4_decode_fattr4(argp, open->op_bmval,
						     ARRAY_SIZE(open->op_bmval),
						     &open->op_iattr, &open->op_acl,
						     &open->op_label, &open->op_umask);
			if (status)
				goto out;
			break;
@@ -1194,8 +1238,10 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta
	status = nfsd4_decode_stateid(argp, &setattr->sa_stateid);
	if (status)
		return status;
	return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr,
				  &setattr->sa_acl, &setattr->sa_label, NULL);
	return nfsd4_decode_fattr4(argp, setattr->sa_bmval,
				   ARRAY_SIZE(setattr->sa_bmval),
				   &setattr->sa_iattr, &setattr->sa_acl,
				   &setattr->sa_label, NULL);
}

static __be32