diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2012-03-02 17:14:31 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-03-06 10:32:48 -0500 |
commit | cd93710e8d290711ba2e08e1d1a380013aad667d (patch) | |
tree | 28f1a04dabfa3eaa64b61ea4491654e9ba70d889 /fs/nfs | |
parent | ab19b4813fdbdef8f9c8732d1f7a2a69ae78d00b (diff) |
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: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/nfs4proc.c | 32 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 40 |
2 files changed, 39 insertions, 33 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index e0e35288361c..1ec05222ccbc 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -836,13 +836,15 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | |||
836 | p->o_arg.dir_bitmask = server->cache_consistency_bitmask; | 836 | p->o_arg.dir_bitmask = server->cache_consistency_bitmask; |
837 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; | 837 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; |
838 | if (attrs != NULL && attrs->ia_valid != 0) { | 838 | if (attrs != NULL && attrs->ia_valid != 0) { |
839 | u32 *s; | 839 | __be32 verf[2]; |
840 | 840 | ||
841 | p->o_arg.u.attrs = &p->attrs; | 841 | p->o_arg.u.attrs = &p->attrs; |
842 | memcpy(&p->attrs, attrs, sizeof(p->attrs)); | 842 | memcpy(&p->attrs, attrs, sizeof(p->attrs)); |
843 | s = (u32 *) p->o_arg.u.verifier.data; | 843 | |
844 | s[0] = jiffies; | 844 | verf[0] = jiffies; |
845 | s[1] = current->pid; | 845 | verf[1] = current->pid; |
846 | memcpy(p->o_arg.u.verifier.data, verf, | ||
847 | sizeof(p->o_arg.u.verifier.data)); | ||
846 | } | 848 | } |
847 | p->c_arg.fh = &p->o_res.fh; | 849 | p->c_arg.fh = &p->o_res.fh; |
848 | p->c_arg.stateid = &p->o_res.stateid; | 850 | p->c_arg.stateid = &p->o_res.stateid; |
@@ -3819,6 +3821,16 @@ wait_on_recovery: | |||
3819 | return -EAGAIN; | 3821 | return -EAGAIN; |
3820 | } | 3822 | } |
3821 | 3823 | ||
3824 | static void nfs4_construct_boot_verifier(struct nfs_client *clp, | ||
3825 | nfs4_verifier *bootverf) | ||
3826 | { | ||
3827 | __be32 verf[2]; | ||
3828 | |||
3829 | verf[0] = htonl((u32)clp->cl_boot_time.tv_sec); | ||
3830 | verf[1] = htonl((u32)clp->cl_boot_time.tv_nsec); | ||
3831 | memcpy(bootverf->data, verf, sizeof(bootverf->data)); | ||
3832 | } | ||
3833 | |||
3822 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, | 3834 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, |
3823 | unsigned short port, struct rpc_cred *cred, | 3835 | unsigned short port, struct rpc_cred *cred, |
3824 | struct nfs4_setclientid_res *res) | 3836 | struct nfs4_setclientid_res *res) |
@@ -3835,13 +3847,10 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, | |||
3835 | .rpc_resp = res, | 3847 | .rpc_resp = res, |
3836 | .rpc_cred = cred, | 3848 | .rpc_cred = cred, |
3837 | }; | 3849 | }; |
3838 | __be32 *p; | ||
3839 | int loop = 0; | 3850 | int loop = 0; |
3840 | int status; | 3851 | int status; |
3841 | 3852 | ||
3842 | p = (__be32*)sc_verifier.data; | 3853 | nfs4_construct_boot_verifier(clp, &sc_verifier); |
3843 | *p++ = htonl((u32)clp->cl_boot_time.tv_sec); | ||
3844 | *p = htonl((u32)clp->cl_boot_time.tv_nsec); | ||
3845 | 3854 | ||
3846 | for(;;) { | 3855 | for(;;) { |
3847 | rcu_read_lock(); | 3856 | rcu_read_lock(); |
@@ -4933,6 +4942,7 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | |||
4933 | { | 4942 | { |
4934 | nfs4_verifier verifier; | 4943 | nfs4_verifier verifier; |
4935 | struct nfs41_exchange_id_args args = { | 4944 | struct nfs41_exchange_id_args args = { |
4945 | .verifier = &verifier, | ||
4936 | .client = clp, | 4946 | .client = clp, |
4937 | .flags = EXCHGID4_FLAG_SUPP_MOVED_REFER, | 4947 | .flags = EXCHGID4_FLAG_SUPP_MOVED_REFER, |
4938 | }; | 4948 | }; |
@@ -4946,15 +4956,11 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | |||
4946 | .rpc_resp = &res, | 4956 | .rpc_resp = &res, |
4947 | .rpc_cred = cred, | 4957 | .rpc_cred = cred, |
4948 | }; | 4958 | }; |
4949 | __be32 *p; | ||
4950 | 4959 | ||
4951 | dprintk("--> %s\n", __func__); | 4960 | dprintk("--> %s\n", __func__); |
4952 | BUG_ON(clp == NULL); | 4961 | BUG_ON(clp == NULL); |
4953 | 4962 | ||
4954 | p = (u32 *)verifier.data; | 4963 | nfs4_construct_boot_verifier(clp, &verifier); |
4955 | *p++ = htonl((u32)clp->cl_boot_time.tv_sec); | ||
4956 | *p = htonl((u32)clp->cl_boot_time.tv_nsec); | ||
4957 | args.verifier = &verifier; | ||
4958 | 4964 | ||
4959 | args.id_len = scnprintf(args.id, sizeof(args.id), | 4965 | args.id_len = scnprintf(args.id, sizeof(args.id), |
4960 | "%s/%s.%s/%u", | 4966 | "%s/%s.%s/%u", |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index e9d4ac06b5d9..62effaf579c4 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -1538,7 +1538,7 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg | |||
1538 | FATTR4_WORD1_MOUNTED_ON_FILEID, | 1538 | FATTR4_WORD1_MOUNTED_ON_FILEID, |
1539 | }; | 1539 | }; |
1540 | uint32_t dircount = readdir->count >> 1; | 1540 | uint32_t dircount = readdir->count >> 1; |
1541 | __be32 *p; | 1541 | __be32 *p, verf[2]; |
1542 | 1542 | ||
1543 | if (readdir->plus) { | 1543 | if (readdir->plus) { |
1544 | attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE| | 1544 | 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 | |||
1553 | if (!(readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)) | 1553 | if (!(readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)) |
1554 | attrs[0] |= FATTR4_WORD0_FILEID; | 1554 | attrs[0] |= FATTR4_WORD0_FILEID; |
1555 | 1555 | ||
1556 | p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20); | 1556 | p = reserve_space(xdr, 12); |
1557 | *p++ = cpu_to_be32(OP_READDIR); | 1557 | *p++ = cpu_to_be32(OP_READDIR); |
1558 | p = xdr_encode_hyper(p, readdir->cookie); | 1558 | p = xdr_encode_hyper(p, readdir->cookie); |
1559 | p = xdr_encode_opaque_fixed(p, readdir->verifier.data, NFS4_VERIFIER_SIZE); | 1559 | encode_nfs4_verifier(xdr, &readdir->verifier); |
1560 | p = reserve_space(xdr, 20); | ||
1560 | *p++ = cpu_to_be32(dircount); | 1561 | *p++ = cpu_to_be32(dircount); |
1561 | *p++ = cpu_to_be32(readdir->count); | 1562 | *p++ = cpu_to_be32(readdir->count); |
1562 | *p++ = cpu_to_be32(2); | 1563 | *p++ = cpu_to_be32(2); |
@@ -1565,11 +1566,11 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg | |||
1565 | *p = cpu_to_be32(attrs[1] & readdir->bitmask[1]); | 1566 | *p = cpu_to_be32(attrs[1] & readdir->bitmask[1]); |
1566 | hdr->nops++; | 1567 | hdr->nops++; |
1567 | hdr->replen += decode_readdir_maxsz; | 1568 | hdr->replen += decode_readdir_maxsz; |
1569 | memcpy(verf, readdir->verifier.data, sizeof(verf)); | ||
1568 | dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n", | 1570 | dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n", |
1569 | __func__, | 1571 | __func__, |
1570 | (unsigned long long)readdir->cookie, | 1572 | (unsigned long long)readdir->cookie, |
1571 | ((u32 *)readdir->verifier.data)[0], | 1573 | verf[0], verf[1], |
1572 | ((u32 *)readdir->verifier.data)[1], | ||
1573 | attrs[0] & readdir->bitmask[0], | 1574 | attrs[0] & readdir->bitmask[0], |
1574 | attrs[1] & readdir->bitmask[1]); | 1575 | attrs[1] & readdir->bitmask[1]); |
1575 | } | 1576 | } |
@@ -1643,9 +1644,9 @@ static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclie | |||
1643 | { | 1644 | { |
1644 | __be32 *p; | 1645 | __be32 *p; |
1645 | 1646 | ||
1646 | p = reserve_space(xdr, 4 + NFS4_VERIFIER_SIZE); | 1647 | p = reserve_space(xdr, 4); |
1647 | *p++ = cpu_to_be32(OP_SETCLIENTID); | 1648 | *p = cpu_to_be32(OP_SETCLIENTID); |
1648 | xdr_encode_opaque_fixed(p, setclientid->sc_verifier->data, NFS4_VERIFIER_SIZE); | 1649 | encode_nfs4_verifier(xdr, setclientid->sc_verifier); |
1649 | 1650 | ||
1650 | encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name); | 1651 | encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name); |
1651 | p = reserve_space(xdr, 4); | 1652 | p = reserve_space(xdr, 4); |
@@ -1662,10 +1663,10 @@ static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4 | |||
1662 | { | 1663 | { |
1663 | __be32 *p; | 1664 | __be32 *p; |
1664 | 1665 | ||
1665 | p = reserve_space(xdr, 12 + NFS4_VERIFIER_SIZE); | 1666 | p = reserve_space(xdr, 12); |
1666 | *p++ = cpu_to_be32(OP_SETCLIENTID_CONFIRM); | 1667 | *p++ = cpu_to_be32(OP_SETCLIENTID_CONFIRM); |
1667 | p = xdr_encode_hyper(p, arg->clientid); | 1668 | p = xdr_encode_hyper(p, arg->clientid); |
1668 | xdr_encode_opaque_fixed(p, arg->confirm.data, NFS4_VERIFIER_SIZE); | 1669 | encode_nfs4_verifier(xdr, &arg->confirm); |
1669 | hdr->nops++; | 1670 | hdr->nops++; |
1670 | hdr->replen += decode_setclientid_confirm_maxsz; | 1671 | hdr->replen += decode_setclientid_confirm_maxsz; |
1671 | } | 1672 | } |
@@ -1708,9 +1709,9 @@ static void encode_exchange_id(struct xdr_stream *xdr, | |||
1708 | char impl_name[NFS4_OPAQUE_LIMIT]; | 1709 | char impl_name[NFS4_OPAQUE_LIMIT]; |
1709 | int len = 0; | 1710 | int len = 0; |
1710 | 1711 | ||
1711 | p = reserve_space(xdr, 4 + sizeof(args->verifier->data)); | 1712 | p = reserve_space(xdr, 4); |
1712 | *p++ = cpu_to_be32(OP_EXCHANGE_ID); | 1713 | *p = cpu_to_be32(OP_EXCHANGE_ID); |
1713 | xdr_encode_opaque_fixed(p, args->verifier->data, sizeof(args->verifier->data)); | 1714 | encode_nfs4_verifier(xdr, args->verifier); |
1714 | 1715 | ||
1715 | encode_string(xdr, args->id_len, args->id); | 1716 | encode_string(xdr, args->id_len, args->id); |
1716 | 1717 | ||
@@ -4162,7 +4163,7 @@ static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res) | |||
4162 | 4163 | ||
4163 | static int decode_verifier(struct xdr_stream *xdr, void *verifier) | 4164 | static int decode_verifier(struct xdr_stream *xdr, void *verifier) |
4164 | { | 4165 | { |
4165 | return decode_opaque_fixed(xdr, verifier, 8); | 4166 | return decode_opaque_fixed(xdr, verifier, NFS4_VERIFIER_SIZE); |
4166 | } | 4167 | } |
4167 | 4168 | ||
4168 | static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res) | 4169 | 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 | |||
4854 | size_t hdrlen; | 4855 | size_t hdrlen; |
4855 | u32 recvd, pglen = rcvbuf->page_len; | 4856 | u32 recvd, pglen = rcvbuf->page_len; |
4856 | int status; | 4857 | int status; |
4858 | __be32 verf[2]; | ||
4857 | 4859 | ||
4858 | status = decode_op_hdr(xdr, OP_READDIR); | 4860 | status = decode_op_hdr(xdr, OP_READDIR); |
4859 | if (!status) | 4861 | if (!status) |
4860 | status = decode_verifier(xdr, readdir->verifier.data); | 4862 | status = decode_verifier(xdr, readdir->verifier.data); |
4861 | if (unlikely(status)) | 4863 | if (unlikely(status)) |
4862 | return status; | 4864 | return status; |
4865 | memcpy(verf, readdir->verifier.data, sizeof(verf)); | ||
4863 | dprintk("%s: verifier = %08x:%08x\n", | 4866 | dprintk("%s: verifier = %08x:%08x\n", |
4864 | __func__, | 4867 | __func__, verf[0], verf[1]); |
4865 | ((u32 *)readdir->verifier.data)[0], | ||
4866 | ((u32 *)readdir->verifier.data)[1]); | ||
4867 | |||
4868 | 4868 | ||
4869 | hdrlen = (char *) xdr->p - (char *) iov->iov_base; | 4869 | hdrlen = (char *) xdr->p - (char *) iov->iov_base; |
4870 | recvd = rcvbuf->len - hdrlen; | 4870 | recvd = rcvbuf->len - hdrlen; |
@@ -5111,7 +5111,7 @@ static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res) | |||
5111 | goto out_overflow; | 5111 | goto out_overflow; |
5112 | res->count = be32_to_cpup(p++); | 5112 | res->count = be32_to_cpup(p++); |
5113 | res->verf->committed = be32_to_cpup(p++); | 5113 | res->verf->committed = be32_to_cpup(p++); |
5114 | memcpy(res->verf->verifier, p, 8); | 5114 | memcpy(res->verf->verifier, p, NFS4_VERIFIER_SIZE); |
5115 | return 0; | 5115 | return 0; |
5116 | out_overflow: | 5116 | out_overflow: |
5117 | print_overflow_msg(__func__, xdr); | 5117 | print_overflow_msg(__func__, xdr); |
@@ -5455,7 +5455,7 @@ static int decode_getdevicelist(struct xdr_stream *xdr, | |||
5455 | p += 2; | 5455 | p += 2; |
5456 | 5456 | ||
5457 | /* Read verifier */ | 5457 | /* Read verifier */ |
5458 | p = xdr_decode_opaque_fixed(p, verftemp.verifier, 8); | 5458 | p = xdr_decode_opaque_fixed(p, verftemp.verifier, NFS4_VERIFIER_SIZE); |
5459 | 5459 | ||
5460 | res->num_devs = be32_to_cpup(p); | 5460 | res->num_devs = be32_to_cpup(p); |
5461 | 5461 | ||