Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cd93710e authored by Chuck Lever's avatar Chuck Lever Committed by Trond Myklebust
Browse files

NFS: Fix nfs4_verifier memory alignment



Clean up due to code review.

The nfs4_verifier's data field is not guaranteed to be u32-aligned.
Casting an array of chars to a u32 * is considered generally
hazardous.

Fix this by using a __be32 array to generate a verifier's contents,
and then byte-copy the contents into the verifier field.  The contents
of a verifier, for all intents and purposes, are opaque bytes.  Only
local code that generates a verifier need know the actual content and
format.  Everyone else compares the full byte array for exact
equality.

Also, sizeof(nfs4_verifer) is the size of the in-core verifier data
structure, but NFS4_VERIFIER_SIZE is the number of octets in an XDR'd
verifier.  The two are not interchangeable, even if they happen to
have the same value.

Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent ab19b481
Loading
Loading
Loading
Loading
+19 −13
Original line number Original line Diff line number Diff line
@@ -836,13 +836,15 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
	p->o_arg.dir_bitmask = server->cache_consistency_bitmask;
	p->o_arg.dir_bitmask = server->cache_consistency_bitmask;
	p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
	p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
	if (attrs != NULL && attrs->ia_valid != 0) {
	if (attrs != NULL && attrs->ia_valid != 0) {
		u32 *s;
		__be32 verf[2];


		p->o_arg.u.attrs = &p->attrs;
		p->o_arg.u.attrs = &p->attrs;
		memcpy(&p->attrs, attrs, sizeof(p->attrs));
		memcpy(&p->attrs, attrs, sizeof(p->attrs));
		s = (u32 *) p->o_arg.u.verifier.data;

		s[0] = jiffies;
		verf[0] = jiffies;
		s[1] = current->pid;
		verf[1] = current->pid;
		memcpy(p->o_arg.u.verifier.data, verf,
				sizeof(p->o_arg.u.verifier.data));
	}
	}
	p->c_arg.fh = &p->o_res.fh;
	p->c_arg.fh = &p->o_res.fh;
	p->c_arg.stateid = &p->o_res.stateid;
	p->c_arg.stateid = &p->o_res.stateid;
@@ -3819,6 +3821,16 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
	return -EAGAIN;
	return -EAGAIN;
}
}


static void nfs4_construct_boot_verifier(struct nfs_client *clp,
					 nfs4_verifier *bootverf)
{
	__be32 verf[2];

	verf[0] = htonl((u32)clp->cl_boot_time.tv_sec);
	verf[1] = htonl((u32)clp->cl_boot_time.tv_nsec);
	memcpy(bootverf->data, verf, sizeof(bootverf->data));
}

int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
		unsigned short port, struct rpc_cred *cred,
		unsigned short port, struct rpc_cred *cred,
		struct nfs4_setclientid_res *res)
		struct nfs4_setclientid_res *res)
@@ -3835,13 +3847,10 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
		.rpc_resp = res,
		.rpc_resp = res,
		.rpc_cred = cred,
		.rpc_cred = cred,
	};
	};
	__be32 *p;
	int loop = 0;
	int loop = 0;
	int status;
	int status;


	p = (__be32*)sc_verifier.data;
	nfs4_construct_boot_verifier(clp, &sc_verifier);
	*p++ = htonl((u32)clp->cl_boot_time.tv_sec);
	*p = htonl((u32)clp->cl_boot_time.tv_nsec);


	for(;;) {
	for(;;) {
		rcu_read_lock();
		rcu_read_lock();
@@ -4933,6 +4942,7 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
{
{
	nfs4_verifier verifier;
	nfs4_verifier verifier;
	struct nfs41_exchange_id_args args = {
	struct nfs41_exchange_id_args args = {
		.verifier = &verifier,
		.client = clp,
		.client = clp,
		.flags = EXCHGID4_FLAG_SUPP_MOVED_REFER,
		.flags = EXCHGID4_FLAG_SUPP_MOVED_REFER,
	};
	};
@@ -4946,15 +4956,11 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
		.rpc_resp = &res,
		.rpc_resp = &res,
		.rpc_cred = cred,
		.rpc_cred = cred,
	};
	};
	__be32 *p;


	dprintk("--> %s\n", __func__);
	dprintk("--> %s\n", __func__);
	BUG_ON(clp == NULL);
	BUG_ON(clp == NULL);


	p = (u32 *)verifier.data;
	nfs4_construct_boot_verifier(clp, &verifier);
	*p++ = htonl((u32)clp->cl_boot_time.tv_sec);
	*p = htonl((u32)clp->cl_boot_time.tv_nsec);
	args.verifier = &verifier;


	args.id_len = scnprintf(args.id, sizeof(args.id),
	args.id_len = scnprintf(args.id, sizeof(args.id),
				"%s/%s.%s/%u",
				"%s/%s.%s/%u",
+20 −20
Original line number Original line Diff line number Diff line
@@ -1538,7 +1538,7 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
		FATTR4_WORD1_MOUNTED_ON_FILEID,
		FATTR4_WORD1_MOUNTED_ON_FILEID,
	};
	};
	uint32_t dircount = readdir->count >> 1;
	uint32_t dircount = readdir->count >> 1;
	__be32 *p;
	__be32 *p, verf[2];


	if (readdir->plus) {
	if (readdir->plus) {
		attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE|
		attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE|
@@ -1553,10 +1553,11 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
	if (!(readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID))
	if (!(readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID))
		attrs[0] |= FATTR4_WORD0_FILEID;
		attrs[0] |= FATTR4_WORD0_FILEID;


	p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20);
	p = reserve_space(xdr, 12);
	*p++ = cpu_to_be32(OP_READDIR);
	*p++ = cpu_to_be32(OP_READDIR);
	p = xdr_encode_hyper(p, readdir->cookie);
	p = xdr_encode_hyper(p, readdir->cookie);
	p = xdr_encode_opaque_fixed(p, readdir->verifier.data, NFS4_VERIFIER_SIZE);
	encode_nfs4_verifier(xdr, &readdir->verifier);
	p = reserve_space(xdr, 20);
	*p++ = cpu_to_be32(dircount);
	*p++ = cpu_to_be32(dircount);
	*p++ = cpu_to_be32(readdir->count);
	*p++ = cpu_to_be32(readdir->count);
	*p++ = cpu_to_be32(2);
	*p++ = cpu_to_be32(2);
@@ -1565,11 +1566,11 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
	*p = cpu_to_be32(attrs[1] & readdir->bitmask[1]);
	*p = cpu_to_be32(attrs[1] & readdir->bitmask[1]);
	hdr->nops++;
	hdr->nops++;
	hdr->replen += decode_readdir_maxsz;
	hdr->replen += decode_readdir_maxsz;
	memcpy(verf, readdir->verifier.data, sizeof(verf));
	dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n",
	dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n",
			__func__,
			__func__,
			(unsigned long long)readdir->cookie,
			(unsigned long long)readdir->cookie,
			((u32 *)readdir->verifier.data)[0],
			verf[0], verf[1],
			((u32 *)readdir->verifier.data)[1],
			attrs[0] & readdir->bitmask[0],
			attrs[0] & readdir->bitmask[0],
			attrs[1] & readdir->bitmask[1]);
			attrs[1] & readdir->bitmask[1]);
}
}
@@ -1643,9 +1644,9 @@ static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclie
{
{
	__be32 *p;
	__be32 *p;


	p = reserve_space(xdr, 4 + NFS4_VERIFIER_SIZE);
	p = reserve_space(xdr, 4);
	*p++ = cpu_to_be32(OP_SETCLIENTID);
	*p = cpu_to_be32(OP_SETCLIENTID);
	xdr_encode_opaque_fixed(p, setclientid->sc_verifier->data, NFS4_VERIFIER_SIZE);
	encode_nfs4_verifier(xdr, setclientid->sc_verifier);


	encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name);
	encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name);
	p = reserve_space(xdr, 4);
	p = reserve_space(xdr, 4);
@@ -1662,10 +1663,10 @@ static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4
{
{
	__be32 *p;
	__be32 *p;


	p = reserve_space(xdr, 12 + NFS4_VERIFIER_SIZE);
	p = reserve_space(xdr, 12);
	*p++ = cpu_to_be32(OP_SETCLIENTID_CONFIRM);
	*p++ = cpu_to_be32(OP_SETCLIENTID_CONFIRM);
	p = xdr_encode_hyper(p, arg->clientid);
	p = xdr_encode_hyper(p, arg->clientid);
	xdr_encode_opaque_fixed(p, arg->confirm.data, NFS4_VERIFIER_SIZE);
	encode_nfs4_verifier(xdr, &arg->confirm);
	hdr->nops++;
	hdr->nops++;
	hdr->replen += decode_setclientid_confirm_maxsz;
	hdr->replen += decode_setclientid_confirm_maxsz;
}
}
@@ -1708,9 +1709,9 @@ static void encode_exchange_id(struct xdr_stream *xdr,
	char impl_name[NFS4_OPAQUE_LIMIT];
	char impl_name[NFS4_OPAQUE_LIMIT];
	int len = 0;
	int len = 0;


	p = reserve_space(xdr, 4 + sizeof(args->verifier->data));
	p = reserve_space(xdr, 4);
	*p++ = cpu_to_be32(OP_EXCHANGE_ID);
	*p = cpu_to_be32(OP_EXCHANGE_ID);
	xdr_encode_opaque_fixed(p, args->verifier->data, sizeof(args->verifier->data));
	encode_nfs4_verifier(xdr, args->verifier);


	encode_string(xdr, args->id_len, args->id);
	encode_string(xdr, args->id_len, args->id);


@@ -4162,7 +4163,7 @@ static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res)


static int decode_verifier(struct xdr_stream *xdr, void *verifier)
static int decode_verifier(struct xdr_stream *xdr, void *verifier)
{
{
	return decode_opaque_fixed(xdr, verifier, 8);
	return decode_opaque_fixed(xdr, verifier, NFS4_VERIFIER_SIZE);
}
}


static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res)
static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res)
@@ -4854,17 +4855,16 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
	size_t		hdrlen;
	size_t		hdrlen;
	u32		recvd, pglen = rcvbuf->page_len;
	u32		recvd, pglen = rcvbuf->page_len;
	int		status;
	int		status;
	__be32		verf[2];


	status = decode_op_hdr(xdr, OP_READDIR);
	status = decode_op_hdr(xdr, OP_READDIR);
	if (!status)
	if (!status)
		status = decode_verifier(xdr, readdir->verifier.data);
		status = decode_verifier(xdr, readdir->verifier.data);
	if (unlikely(status))
	if (unlikely(status))
		return status;
		return status;
	memcpy(verf, readdir->verifier.data, sizeof(verf));
	dprintk("%s: verifier = %08x:%08x\n",
	dprintk("%s: verifier = %08x:%08x\n",
			__func__,
			__func__, verf[0], verf[1]);
			((u32 *)readdir->verifier.data)[0],
			((u32 *)readdir->verifier.data)[1]);



	hdrlen = (char *) xdr->p - (char *) iov->iov_base;
	hdrlen = (char *) xdr->p - (char *) iov->iov_base;
	recvd = rcvbuf->len - hdrlen;
	recvd = rcvbuf->len - hdrlen;
@@ -5111,7 +5111,7 @@ static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res)
		goto out_overflow;
		goto out_overflow;
	res->count = be32_to_cpup(p++);
	res->count = be32_to_cpup(p++);
	res->verf->committed = be32_to_cpup(p++);
	res->verf->committed = be32_to_cpup(p++);
	memcpy(res->verf->verifier, p, 8);
	memcpy(res->verf->verifier, p, NFS4_VERIFIER_SIZE);
	return 0;
	return 0;
out_overflow:
out_overflow:
	print_overflow_msg(__func__, xdr);
	print_overflow_msg(__func__, xdr);
@@ -5455,7 +5455,7 @@ static int decode_getdevicelist(struct xdr_stream *xdr,
	p += 2;
	p += 2;


	/* Read verifier */
	/* Read verifier */
	p = xdr_decode_opaque_fixed(p, verftemp.verifier, 8);
	p = xdr_decode_opaque_fixed(p, verftemp.verifier, NFS4_VERIFIER_SIZE);


	res->num_devs = be32_to_cpup(p);
	res->num_devs = be32_to_cpup(p);