diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2019-02-11 11:24:58 -0500 |
---|---|---|
committer | Anna Schumaker <Anna.Schumaker@Netapp.com> | 2019-02-14 09:11:18 -0500 |
commit | a0584ee9aed805446b044ce855e67264f0dc619e (patch) | |
tree | f32c32e668db5a918b86f6562c639f71f353b6cf | |
parent | 7f5667a5f8c4ff85b14ccce9d41f9244bd30ab68 (diff) |
SUNRPC: Use struct xdr_stream when decoding RPC Reply header
Modernize and harden the code path that parses an RPC Reply
message.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
-rw-r--r-- | include/linux/sunrpc/auth.h | 15 | ||||
-rw-r--r-- | include/linux/sunrpc/xdr.h | 1 | ||||
-rw-r--r-- | net/sunrpc/auth.c | 63 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 204 | ||||
-rw-r--r-- | net/sunrpc/auth_null.c | 31 | ||||
-rw-r--r-- | net/sunrpc/auth_unix.c | 42 | ||||
-rw-r--r-- | net/sunrpc/clnt.c | 88 |
7 files changed, 243 insertions, 201 deletions
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index 96e237f8e60b..c51e1893f77e 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h | |||
@@ -134,11 +134,12 @@ struct rpc_credops { | |||
134 | int (*crmarshal)(struct rpc_task *task, | 134 | int (*crmarshal)(struct rpc_task *task, |
135 | struct xdr_stream *xdr); | 135 | struct xdr_stream *xdr); |
136 | int (*crrefresh)(struct rpc_task *); | 136 | int (*crrefresh)(struct rpc_task *); |
137 | __be32 * (*crvalidate)(struct rpc_task *, __be32 *); | 137 | int (*crvalidate)(struct rpc_task *task, |
138 | struct xdr_stream *xdr); | ||
138 | int (*crwrap_req)(struct rpc_task *task, | 139 | int (*crwrap_req)(struct rpc_task *task, |
139 | struct xdr_stream *xdr); | 140 | struct xdr_stream *xdr); |
140 | int (*crunwrap_resp)(struct rpc_task *, kxdrdproc_t, | 141 | int (*crunwrap_resp)(struct rpc_task *task, |
141 | void *, __be32 *, void *); | 142 | struct xdr_stream *xdr); |
142 | int (*crkey_timeout)(struct rpc_cred *); | 143 | int (*crkey_timeout)(struct rpc_cred *); |
143 | char * (*crstringify_acceptor)(struct rpc_cred *); | 144 | char * (*crstringify_acceptor)(struct rpc_cred *); |
144 | bool (*crneed_reencode)(struct rpc_task *); | 145 | bool (*crneed_reencode)(struct rpc_task *); |
@@ -168,12 +169,16 @@ struct rpc_cred * rpcauth_lookupcred(struct rpc_auth *, int); | |||
168 | void put_rpccred(struct rpc_cred *); | 169 | void put_rpccred(struct rpc_cred *); |
169 | int rpcauth_marshcred(struct rpc_task *task, | 170 | int rpcauth_marshcred(struct rpc_task *task, |
170 | struct xdr_stream *xdr); | 171 | struct xdr_stream *xdr); |
171 | __be32 * rpcauth_checkverf(struct rpc_task *, __be32 *); | 172 | int rpcauth_checkverf(struct rpc_task *task, |
173 | struct xdr_stream *xdr); | ||
172 | int rpcauth_wrap_req_encode(struct rpc_task *task, | 174 | int rpcauth_wrap_req_encode(struct rpc_task *task, |
173 | struct xdr_stream *xdr); | 175 | struct xdr_stream *xdr); |
174 | int rpcauth_wrap_req(struct rpc_task *task, | 176 | int rpcauth_wrap_req(struct rpc_task *task, |
175 | struct xdr_stream *xdr); | 177 | struct xdr_stream *xdr); |
176 | int rpcauth_unwrap_resp(struct rpc_task *task, kxdrdproc_t decode, void *rqstp, __be32 *data, void *obj); | 178 | int rpcauth_unwrap_resp_decode(struct rpc_task *task, |
179 | struct xdr_stream *xdr); | ||
180 | int rpcauth_unwrap_resp(struct rpc_task *task, | ||
181 | struct xdr_stream *xdr); | ||
177 | bool rpcauth_xmit_need_reencode(struct rpc_task *task); | 182 | bool rpcauth_xmit_need_reencode(struct rpc_task *task); |
178 | int rpcauth_refreshcred(struct rpc_task *); | 183 | int rpcauth_refreshcred(struct rpc_task *); |
179 | void rpcauth_invalcred(struct rpc_task *); | 184 | void rpcauth_invalcred(struct rpc_task *); |
diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index c54041950cc0..65af6a204b75 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h | |||
@@ -89,6 +89,7 @@ xdr_buf_init(struct xdr_buf *buf, void *start, size_t len) | |||
89 | 89 | ||
90 | #define rpc_auth_null cpu_to_be32(RPC_AUTH_NULL) | 90 | #define rpc_auth_null cpu_to_be32(RPC_AUTH_NULL) |
91 | #define rpc_auth_unix cpu_to_be32(RPC_AUTH_UNIX) | 91 | #define rpc_auth_unix cpu_to_be32(RPC_AUTH_UNIX) |
92 | #define rpc_auth_short cpu_to_be32(RPC_AUTH_SHORT) | ||
92 | #define rpc_auth_gss cpu_to_be32(RPC_AUTH_GSS) | 93 | #define rpc_auth_gss cpu_to_be32(RPC_AUTH_GSS) |
93 | 94 | ||
94 | #define rpc_call cpu_to_be32(RPC_CALL) | 95 | #define rpc_call cpu_to_be32(RPC_CALL) |
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index add2135d9b01..e7861026b9e5 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c | |||
@@ -17,6 +17,8 @@ | |||
17 | #include <linux/sunrpc/gss_api.h> | 17 | #include <linux/sunrpc/gss_api.h> |
18 | #include <linux/spinlock.h> | 18 | #include <linux/spinlock.h> |
19 | 19 | ||
20 | #include <trace/events/sunrpc.h> | ||
21 | |||
20 | #define RPC_CREDCACHE_DEFAULT_HASHBITS (4) | 22 | #define RPC_CREDCACHE_DEFAULT_HASHBITS (4) |
21 | struct rpc_cred_cache { | 23 | struct rpc_cred_cache { |
22 | struct hlist_head *hashtable; | 24 | struct hlist_head *hashtable; |
@@ -773,14 +775,6 @@ int rpcauth_marshcred(struct rpc_task *task, struct xdr_stream *xdr) | |||
773 | return ops->crmarshal(task, xdr); | 775 | return ops->crmarshal(task, xdr); |
774 | } | 776 | } |
775 | 777 | ||
776 | __be32 * | ||
777 | rpcauth_checkverf(struct rpc_task *task, __be32 *p) | ||
778 | { | ||
779 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; | ||
780 | |||
781 | return cred->cr_ops->crvalidate(task, p); | ||
782 | } | ||
783 | |||
784 | /** | 778 | /** |
785 | * rpcauth_wrap_req_encode - XDR encode the RPC procedure | 779 | * rpcauth_wrap_req_encode - XDR encode the RPC procedure |
786 | * @task: controlling RPC task | 780 | * @task: controlling RPC task |
@@ -814,27 +808,52 @@ int rpcauth_wrap_req(struct rpc_task *task, struct xdr_stream *xdr) | |||
814 | return ops->crwrap_req(task, xdr); | 808 | return ops->crwrap_req(task, xdr); |
815 | } | 809 | } |
816 | 810 | ||
817 | static int | 811 | /** |
818 | rpcauth_unwrap_req_decode(kxdrdproc_t decode, struct rpc_rqst *rqstp, | 812 | * rpcauth_checkverf - Validate verifier in RPC Reply header |
819 | __be32 *data, void *obj) | 813 | * @task: controlling RPC task |
814 | * @xdr: xdr_stream containing RPC Reply header | ||
815 | * | ||
816 | * On success, @xdr is updated to point past the verifier and | ||
817 | * zero is returned. Otherwise, @xdr is in an undefined state | ||
818 | * and a negative errno is returned. | ||
819 | */ | ||
820 | int | ||
821 | rpcauth_checkverf(struct rpc_task *task, struct xdr_stream *xdr) | ||
820 | { | 822 | { |
821 | struct xdr_stream xdr; | 823 | const struct rpc_credops *ops = task->tk_rqstp->rq_cred->cr_ops; |
822 | 824 | ||
823 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, data, rqstp); | 825 | return ops->crvalidate(task, xdr); |
824 | return decode(rqstp, &xdr, obj); | ||
825 | } | 826 | } |
826 | 827 | ||
828 | /** | ||
829 | * rpcauth_unwrap_resp_decode - Invoke XDR decode function | ||
830 | * @task: controlling RPC task | ||
831 | * @xdr: stream where the Reply message resides | ||
832 | * | ||
833 | * Returns zero on success; otherwise a negative errno is returned. | ||
834 | */ | ||
827 | int | 835 | int |
828 | rpcauth_unwrap_resp(struct rpc_task *task, kxdrdproc_t decode, void *rqstp, | 836 | rpcauth_unwrap_resp_decode(struct rpc_task *task, struct xdr_stream *xdr) |
829 | __be32 *data, void *obj) | ||
830 | { | 837 | { |
831 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; | 838 | kxdrdproc_t decode = task->tk_msg.rpc_proc->p_decode; |
839 | |||
840 | return decode(task->tk_rqstp, xdr, task->tk_msg.rpc_resp); | ||
841 | } | ||
842 | EXPORT_SYMBOL_GPL(rpcauth_unwrap_resp_decode); | ||
843 | |||
844 | /** | ||
845 | * rpcauth_unwrap_resp - Invoke unwrap and decode function for the cred | ||
846 | * @task: controlling RPC task | ||
847 | * @xdr: stream where the Reply message resides | ||
848 | * | ||
849 | * Returns zero on success; otherwise a negative errno is returned. | ||
850 | */ | ||
851 | int | ||
852 | rpcauth_unwrap_resp(struct rpc_task *task, struct xdr_stream *xdr) | ||
853 | { | ||
854 | const struct rpc_credops *ops = task->tk_rqstp->rq_cred->cr_ops; | ||
832 | 855 | ||
833 | if (cred->cr_ops->crunwrap_resp) | 856 | return ops->crunwrap_resp(task, xdr); |
834 | return cred->cr_ops->crunwrap_resp(task, decode, rqstp, | ||
835 | data, obj); | ||
836 | /* By default, we decode the arguments normally. */ | ||
837 | return rpcauth_unwrap_req_decode(decode, rqstp, data, obj); | ||
838 | } | 857 | } |
839 | 858 | ||
840 | bool | 859 | bool |
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index b333b1bdad45..206788e8b787 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -1671,59 +1671,62 @@ gss_refresh_null(struct rpc_task *task) | |||
1671 | return 0; | 1671 | return 0; |
1672 | } | 1672 | } |
1673 | 1673 | ||
1674 | static __be32 * | 1674 | static int |
1675 | gss_validate(struct rpc_task *task, __be32 *p) | 1675 | gss_validate(struct rpc_task *task, struct xdr_stream *xdr) |
1676 | { | 1676 | { |
1677 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; | 1677 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; |
1678 | struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); | 1678 | struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); |
1679 | __be32 *seq = NULL; | 1679 | __be32 *p, *seq = NULL; |
1680 | struct kvec iov; | 1680 | struct kvec iov; |
1681 | struct xdr_buf verf_buf; | 1681 | struct xdr_buf verf_buf; |
1682 | struct xdr_netobj mic; | 1682 | struct xdr_netobj mic; |
1683 | u32 flav,len; | 1683 | u32 len, maj_stat; |
1684 | u32 maj_stat; | 1684 | int status; |
1685 | __be32 *ret = ERR_PTR(-EIO); | ||
1686 | 1685 | ||
1687 | dprintk("RPC: %5u %s\n", task->tk_pid, __func__); | 1686 | p = xdr_inline_decode(xdr, 2 * sizeof(*p)); |
1687 | if (!p) | ||
1688 | goto validate_failed; | ||
1689 | if (*p++ != rpc_auth_gss) | ||
1690 | goto validate_failed; | ||
1691 | len = be32_to_cpup(p); | ||
1692 | if (len > RPC_MAX_AUTH_SIZE) | ||
1693 | goto validate_failed; | ||
1694 | p = xdr_inline_decode(xdr, len); | ||
1695 | if (!p) | ||
1696 | goto validate_failed; | ||
1688 | 1697 | ||
1689 | flav = ntohl(*p++); | ||
1690 | if ((len = ntohl(*p++)) > RPC_MAX_AUTH_SIZE) | ||
1691 | goto out_bad; | ||
1692 | if (flav != RPC_AUTH_GSS) | ||
1693 | goto out_bad; | ||
1694 | seq = kmalloc(4, GFP_NOFS); | 1698 | seq = kmalloc(4, GFP_NOFS); |
1695 | if (!seq) | 1699 | if (!seq) |
1696 | goto out_bad; | 1700 | goto validate_failed; |
1697 | *seq = htonl(task->tk_rqstp->rq_seqno); | 1701 | *seq = cpu_to_be32(task->tk_rqstp->rq_seqno); |
1698 | iov.iov_base = seq; | 1702 | iov.iov_base = seq; |
1699 | iov.iov_len = 4; | 1703 | iov.iov_len = 4; |
1700 | xdr_buf_from_iov(&iov, &verf_buf); | 1704 | xdr_buf_from_iov(&iov, &verf_buf); |
1701 | mic.data = (u8 *)p; | 1705 | mic.data = (u8 *)p; |
1702 | mic.len = len; | 1706 | mic.len = len; |
1703 | |||
1704 | ret = ERR_PTR(-EACCES); | ||
1705 | maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &verf_buf, &mic); | 1707 | maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &verf_buf, &mic); |
1706 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) | 1708 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) |
1707 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); | 1709 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); |
1708 | if (maj_stat) { | 1710 | if (maj_stat) |
1709 | dprintk("RPC: %5u %s: gss_verify_mic returned error 0x%08x\n", | 1711 | goto bad_mic; |
1710 | task->tk_pid, __func__, maj_stat); | 1712 | |
1711 | goto out_bad; | ||
1712 | } | ||
1713 | /* We leave it to unwrap to calculate au_rslack. For now we just | 1713 | /* We leave it to unwrap to calculate au_rslack. For now we just |
1714 | * calculate the length of the verifier: */ | 1714 | * calculate the length of the verifier: */ |
1715 | cred->cr_auth->au_verfsize = XDR_QUADLEN(len) + 2; | 1715 | cred->cr_auth->au_verfsize = XDR_QUADLEN(len) + 2; |
1716 | status = 0; | ||
1717 | out: | ||
1716 | gss_put_ctx(ctx); | 1718 | gss_put_ctx(ctx); |
1717 | dprintk("RPC: %5u %s: gss_verify_mic succeeded.\n", | ||
1718 | task->tk_pid, __func__); | ||
1719 | kfree(seq); | ||
1720 | return p + XDR_QUADLEN(len); | ||
1721 | out_bad: | ||
1722 | gss_put_ctx(ctx); | ||
1723 | dprintk("RPC: %5u %s failed ret %ld.\n", task->tk_pid, __func__, | ||
1724 | PTR_ERR(ret)); | ||
1725 | kfree(seq); | 1719 | kfree(seq); |
1726 | return ret; | 1720 | return status; |
1721 | |||
1722 | validate_failed: | ||
1723 | status = -EIO; | ||
1724 | goto out; | ||
1725 | bad_mic: | ||
1726 | dprintk("RPC: %5u %s: gss_verify_mic returned error 0x%08x\n", | ||
1727 | task->tk_pid, __func__, maj_stat); | ||
1728 | status = -EACCES; | ||
1729 | goto out; | ||
1727 | } | 1730 | } |
1728 | 1731 | ||
1729 | static int gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx, | 1732 | static int gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx, |
@@ -1921,79 +1924,98 @@ out: | |||
1921 | return status; | 1924 | return status; |
1922 | } | 1925 | } |
1923 | 1926 | ||
1924 | static inline int | 1927 | static int |
1928 | gss_unwrap_resp_auth(struct rpc_cred *cred) | ||
1929 | { | ||
1930 | cred->cr_auth->au_rslack = cred->cr_auth->au_verfsize; | ||
1931 | return 0; | ||
1932 | } | ||
1933 | |||
1934 | static int | ||
1925 | gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx, | 1935 | gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx, |
1926 | struct rpc_rqst *rqstp, __be32 **p) | 1936 | struct rpc_rqst *rqstp, struct xdr_stream *xdr) |
1927 | { | 1937 | { |
1928 | struct xdr_buf *rcv_buf = &rqstp->rq_rcv_buf; | 1938 | struct xdr_buf integ_buf, *rcv_buf = &rqstp->rq_rcv_buf; |
1929 | struct xdr_buf integ_buf; | 1939 | u32 data_offset, mic_offset, integ_len, maj_stat; |
1930 | struct xdr_netobj mic; | 1940 | struct xdr_netobj mic; |
1931 | u32 data_offset, mic_offset; | 1941 | __be32 *p; |
1932 | u32 integ_len; | ||
1933 | u32 maj_stat; | ||
1934 | int status = -EIO; | ||
1935 | 1942 | ||
1936 | integ_len = ntohl(*(*p)++); | 1943 | p = xdr_inline_decode(xdr, 2 * sizeof(*p)); |
1944 | if (unlikely(!p)) | ||
1945 | goto unwrap_failed; | ||
1946 | integ_len = be32_to_cpup(p++); | ||
1937 | if (integ_len & 3) | 1947 | if (integ_len & 3) |
1938 | return status; | 1948 | goto unwrap_failed; |
1939 | data_offset = (u8 *)(*p) - (u8 *)rcv_buf->head[0].iov_base; | 1949 | data_offset = (u8 *)(p) - (u8 *)rcv_buf->head[0].iov_base; |
1940 | mic_offset = integ_len + data_offset; | 1950 | mic_offset = integ_len + data_offset; |
1941 | if (mic_offset > rcv_buf->len) | 1951 | if (mic_offset > rcv_buf->len) |
1942 | return status; | 1952 | goto unwrap_failed; |
1943 | if (ntohl(*(*p)++) != rqstp->rq_seqno) | 1953 | if (be32_to_cpup(p) != rqstp->rq_seqno) |
1944 | return status; | 1954 | goto unwrap_failed; |
1945 | |||
1946 | if (xdr_buf_subsegment(rcv_buf, &integ_buf, data_offset, | ||
1947 | mic_offset - data_offset)) | ||
1948 | return status; | ||
1949 | 1955 | ||
1956 | if (xdr_buf_subsegment(rcv_buf, &integ_buf, data_offset, integ_len)) | ||
1957 | goto unwrap_failed; | ||
1950 | if (xdr_buf_read_netobj(rcv_buf, &mic, mic_offset)) | 1958 | if (xdr_buf_read_netobj(rcv_buf, &mic, mic_offset)) |
1951 | return status; | 1959 | goto unwrap_failed; |
1952 | |||
1953 | maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &integ_buf, &mic); | 1960 | maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &integ_buf, &mic); |
1954 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) | 1961 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) |
1955 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); | 1962 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); |
1956 | if (maj_stat != GSS_S_COMPLETE) | 1963 | if (maj_stat != GSS_S_COMPLETE) |
1957 | return status; | 1964 | goto bad_mic; |
1965 | |||
1966 | cred->cr_auth->au_rslack = cred->cr_auth->au_verfsize + 2 + | ||
1967 | 1 + XDR_QUADLEN(mic.len); | ||
1958 | return 0; | 1968 | return 0; |
1969 | unwrap_failed: | ||
1970 | return -EIO; | ||
1971 | bad_mic: | ||
1972 | dprintk("RPC: %s: gss_verify_mic returned error 0x%08x\n", | ||
1973 | __func__, maj_stat); | ||
1974 | return -EIO; | ||
1959 | } | 1975 | } |
1960 | 1976 | ||
1961 | static inline int | 1977 | static int |
1962 | gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx, | 1978 | gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx, |
1963 | struct rpc_rqst *rqstp, __be32 **p) | 1979 | struct rpc_rqst *rqstp, struct xdr_stream *xdr) |
1964 | { | 1980 | { |
1965 | struct xdr_buf *rcv_buf = &rqstp->rq_rcv_buf; | 1981 | struct xdr_buf *rcv_buf = &rqstp->rq_rcv_buf; |
1966 | u32 offset; | 1982 | struct kvec *head = rqstp->rq_rcv_buf.head; |
1967 | u32 opaque_len; | 1983 | unsigned int savedlen = rcv_buf->len; |
1968 | u32 maj_stat; | 1984 | u32 offset, opaque_len, maj_stat; |
1969 | int status = -EIO; | 1985 | __be32 *p; |
1970 | 1986 | ||
1971 | opaque_len = ntohl(*(*p)++); | 1987 | p = xdr_inline_decode(xdr, 2 * sizeof(*p)); |
1972 | offset = (u8 *)(*p) - (u8 *)rcv_buf->head[0].iov_base; | 1988 | if (unlikely(!p)) |
1989 | goto unwrap_failed; | ||
1990 | opaque_len = be32_to_cpup(p++); | ||
1991 | offset = (u8 *)(p) - (u8 *)head->iov_base; | ||
1973 | if (offset + opaque_len > rcv_buf->len) | 1992 | if (offset + opaque_len > rcv_buf->len) |
1974 | return status; | 1993 | goto unwrap_failed; |
1975 | /* remove padding: */ | ||
1976 | rcv_buf->len = offset + opaque_len; | 1994 | rcv_buf->len = offset + opaque_len; |
1977 | 1995 | ||
1978 | maj_stat = gss_unwrap(ctx->gc_gss_ctx, offset, rcv_buf); | 1996 | maj_stat = gss_unwrap(ctx->gc_gss_ctx, offset, rcv_buf); |
1979 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) | 1997 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) |
1980 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); | 1998 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); |
1981 | if (maj_stat != GSS_S_COMPLETE) | 1999 | if (maj_stat != GSS_S_COMPLETE) |
1982 | return status; | 2000 | goto bad_unwrap; |
1983 | if (ntohl(*(*p)++) != rqstp->rq_seqno) | 2001 | /* gss_unwrap decrypted the sequence number */ |
1984 | return status; | 2002 | if (be32_to_cpup(p++) != rqstp->rq_seqno) |
1985 | 2003 | goto unwrap_failed; | |
1986 | return 0; | ||
1987 | } | ||
1988 | 2004 | ||
1989 | static int | 2005 | /* gss_unwrap redacts the opaque blob from the head iovec. |
1990 | gss_unwrap_req_decode(kxdrdproc_t decode, struct rpc_rqst *rqstp, | 2006 | * rcv_buf has changed, thus the stream needs to be reset. |
1991 | __be32 *p, void *obj) | 2007 | */ |
1992 | { | 2008 | xdr_init_decode(xdr, rcv_buf, p, rqstp); |
1993 | struct xdr_stream xdr; | ||
1994 | 2009 | ||
1995 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p, rqstp); | 2010 | cred->cr_auth->au_rslack = cred->cr_auth->au_verfsize + 2 + |
1996 | return decode(rqstp, &xdr, obj); | 2011 | XDR_QUADLEN(savedlen - rcv_buf->len); |
2012 | return 0; | ||
2013 | unwrap_failed: | ||
2014 | return -EIO; | ||
2015 | bad_unwrap: | ||
2016 | dprintk("RPC: %s: gss_unwrap returned error 0x%08x\n", | ||
2017 | __func__, maj_stat); | ||
2018 | return -EIO; | ||
1997 | } | 2019 | } |
1998 | 2020 | ||
1999 | static bool | 2021 | static bool |
@@ -2037,39 +2059,33 @@ out: | |||
2037 | } | 2059 | } |
2038 | 2060 | ||
2039 | static int | 2061 | static int |
2040 | gss_unwrap_resp(struct rpc_task *task, | 2062 | gss_unwrap_resp(struct rpc_task *task, struct xdr_stream *xdr) |
2041 | kxdrdproc_t decode, void *rqstp, __be32 *p, void *obj) | ||
2042 | { | 2063 | { |
2043 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; | 2064 | struct rpc_rqst *rqstp = task->tk_rqstp; |
2065 | struct rpc_cred *cred = rqstp->rq_cred; | ||
2044 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, | 2066 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, |
2045 | gc_base); | 2067 | gc_base); |
2046 | struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); | 2068 | struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); |
2047 | __be32 *savedp = p; | 2069 | int status = -EIO; |
2048 | struct kvec *head = ((struct rpc_rqst *)rqstp)->rq_rcv_buf.head; | ||
2049 | int savedlen = head->iov_len; | ||
2050 | int status = -EIO; | ||
2051 | 2070 | ||
2052 | if (ctx->gc_proc != RPC_GSS_PROC_DATA) | 2071 | if (ctx->gc_proc != RPC_GSS_PROC_DATA) |
2053 | goto out_decode; | 2072 | goto out_decode; |
2054 | switch (gss_cred->gc_service) { | 2073 | switch (gss_cred->gc_service) { |
2055 | case RPC_GSS_SVC_NONE: | 2074 | case RPC_GSS_SVC_NONE: |
2075 | status = gss_unwrap_resp_auth(cred); | ||
2056 | break; | 2076 | break; |
2057 | case RPC_GSS_SVC_INTEGRITY: | 2077 | case RPC_GSS_SVC_INTEGRITY: |
2058 | status = gss_unwrap_resp_integ(cred, ctx, rqstp, &p); | 2078 | status = gss_unwrap_resp_integ(cred, ctx, rqstp, xdr); |
2059 | if (status) | ||
2060 | goto out; | ||
2061 | break; | 2079 | break; |
2062 | case RPC_GSS_SVC_PRIVACY: | 2080 | case RPC_GSS_SVC_PRIVACY: |
2063 | status = gss_unwrap_resp_priv(cred, ctx, rqstp, &p); | 2081 | status = gss_unwrap_resp_priv(cred, ctx, rqstp, xdr); |
2064 | if (status) | ||
2065 | goto out; | ||
2066 | break; | 2082 | break; |
2067 | } | 2083 | } |
2068 | /* take into account extra slack for integrity and privacy cases: */ | 2084 | if (status) |
2069 | cred->cr_auth->au_rslack = cred->cr_auth->au_verfsize + (p - savedp) | 2085 | goto out; |
2070 | + (savedlen - head->iov_len); | 2086 | |
2071 | out_decode: | 2087 | out_decode: |
2072 | status = gss_unwrap_req_decode(decode, rqstp, p, obj); | 2088 | status = rpcauth_unwrap_resp_decode(task, xdr); |
2073 | out: | 2089 | out: |
2074 | gss_put_ctx(ctx); | 2090 | gss_put_ctx(ctx); |
2075 | dprintk("RPC: %5u %s returning %d\n", | 2091 | dprintk("RPC: %5u %s returning %d\n", |
diff --git a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c index 797f8472c21b..bf96975ffc4b 100644 --- a/net/sunrpc/auth_null.c +++ b/net/sunrpc/auth_null.c | |||
@@ -86,25 +86,19 @@ nul_refresh(struct rpc_task *task) | |||
86 | return 0; | 86 | return 0; |
87 | } | 87 | } |
88 | 88 | ||
89 | static __be32 * | 89 | static int |
90 | nul_validate(struct rpc_task *task, __be32 *p) | 90 | nul_validate(struct rpc_task *task, struct xdr_stream *xdr) |
91 | { | 91 | { |
92 | rpc_authflavor_t flavor; | 92 | __be32 *p; |
93 | u32 size; | 93 | |
94 | 94 | p = xdr_inline_decode(xdr, 2 * sizeof(*p)); | |
95 | flavor = ntohl(*p++); | 95 | if (!p) |
96 | if (flavor != RPC_AUTH_NULL) { | 96 | return -EIO; |
97 | printk("RPC: bad verf flavor: %u\n", flavor); | 97 | if (*p++ != rpc_auth_null) |
98 | return ERR_PTR(-EIO); | 98 | return -EIO; |
99 | } | 99 | if (*p != xdr_zero) |
100 | 100 | return -EIO; | |
101 | size = ntohl(*p++); | 101 | return 0; |
102 | if (size != 0) { | ||
103 | printk("RPC: bad verf size: %u\n", size); | ||
104 | return ERR_PTR(-EIO); | ||
105 | } | ||
106 | |||
107 | return p; | ||
108 | } | 102 | } |
109 | 103 | ||
110 | const struct rpc_authops authnull_ops = { | 104 | const struct rpc_authops authnull_ops = { |
@@ -134,6 +128,7 @@ const struct rpc_credops null_credops = { | |||
134 | .crwrap_req = rpcauth_wrap_req_encode, | 128 | .crwrap_req = rpcauth_wrap_req_encode, |
135 | .crrefresh = nul_refresh, | 129 | .crrefresh = nul_refresh, |
136 | .crvalidate = nul_validate, | 130 | .crvalidate = nul_validate, |
131 | .crunwrap_resp = rpcauth_unwrap_resp_decode, | ||
137 | }; | 132 | }; |
138 | 133 | ||
139 | static | 134 | static |
diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c index 1d5b7ed9c6f7..5ea84a96f96e 100644 --- a/net/sunrpc/auth_unix.c +++ b/net/sunrpc/auth_unix.c | |||
@@ -160,29 +160,32 @@ unx_refresh(struct rpc_task *task) | |||
160 | return 0; | 160 | return 0; |
161 | } | 161 | } |
162 | 162 | ||
163 | static __be32 * | 163 | static int |
164 | unx_validate(struct rpc_task *task, __be32 *p) | 164 | unx_validate(struct rpc_task *task, struct xdr_stream *xdr) |
165 | { | 165 | { |
166 | rpc_authflavor_t flavor; | 166 | __be32 *p; |
167 | u32 size; | 167 | u32 size; |
168 | |||
169 | flavor = ntohl(*p++); | ||
170 | if (flavor != RPC_AUTH_NULL && | ||
171 | flavor != RPC_AUTH_UNIX && | ||
172 | flavor != RPC_AUTH_SHORT) { | ||
173 | printk("RPC: bad verf flavor: %u\n", flavor); | ||
174 | return ERR_PTR(-EIO); | ||
175 | } | ||
176 | 168 | ||
177 | size = ntohl(*p++); | 169 | p = xdr_inline_decode(xdr, 2 * sizeof(*p)); |
178 | if (size > RPC_MAX_AUTH_SIZE) { | 170 | if (!p) |
179 | printk("RPC: giant verf size: %u\n", size); | 171 | return -EIO; |
180 | return ERR_PTR(-EIO); | 172 | switch (*p++) { |
173 | case rpc_auth_null: | ||
174 | case rpc_auth_unix: | ||
175 | case rpc_auth_short: | ||
176 | break; | ||
177 | default: | ||
178 | return -EIO; | ||
181 | } | 179 | } |
182 | task->tk_rqstp->rq_cred->cr_auth->au_rslack = (size >> 2) + 2; | 180 | size = be32_to_cpup(p); |
183 | p += (size >> 2); | 181 | if (size > RPC_MAX_AUTH_SIZE) |
182 | return -EIO; | ||
183 | p = xdr_inline_decode(xdr, size); | ||
184 | if (!p) | ||
185 | return -EIO; | ||
184 | 186 | ||
185 | return p; | 187 | task->tk_rqstp->rq_cred->cr_auth->au_rslack = (size >> 2) + 2; |
188 | return 0; | ||
186 | } | 189 | } |
187 | 190 | ||
188 | int __init rpc_init_authunix(void) | 191 | int __init rpc_init_authunix(void) |
@@ -223,4 +226,5 @@ const struct rpc_credops unix_credops = { | |||
223 | .crwrap_req = rpcauth_wrap_req_encode, | 226 | .crwrap_req = rpcauth_wrap_req_encode, |
224 | .crrefresh = unx_refresh, | 227 | .crrefresh = unx_refresh, |
225 | .crvalidate = unx_validate, | 228 | .crvalidate = unx_validate, |
229 | .crunwrap_resp = rpcauth_unwrap_resp_decode, | ||
226 | }; | 230 | }; |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index e9735089bd66..803e93105af1 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -79,7 +79,8 @@ static void call_connect_status(struct rpc_task *task); | |||
79 | 79 | ||
80 | static int rpc_encode_header(struct rpc_task *task, | 80 | static int rpc_encode_header(struct rpc_task *task, |
81 | struct xdr_stream *xdr); | 81 | struct xdr_stream *xdr); |
82 | static __be32 *rpc_decode_header(struct rpc_task *task); | 82 | static int rpc_decode_header(struct rpc_task *task, |
83 | struct xdr_stream *xdr); | ||
83 | static int rpc_ping(struct rpc_clnt *clnt); | 84 | static int rpc_ping(struct rpc_clnt *clnt); |
84 | 85 | ||
85 | static void rpc_register_client(struct rpc_clnt *clnt) | 86 | static void rpc_register_client(struct rpc_clnt *clnt) |
@@ -2251,12 +2252,11 @@ call_decode(struct rpc_task *task) | |||
2251 | { | 2252 | { |
2252 | struct rpc_clnt *clnt = task->tk_client; | 2253 | struct rpc_clnt *clnt = task->tk_client; |
2253 | struct rpc_rqst *req = task->tk_rqstp; | 2254 | struct rpc_rqst *req = task->tk_rqstp; |
2254 | kxdrdproc_t decode = task->tk_msg.rpc_proc->p_decode; | 2255 | struct xdr_stream xdr; |
2255 | __be32 *p; | ||
2256 | 2256 | ||
2257 | dprint_status(task); | 2257 | dprint_status(task); |
2258 | 2258 | ||
2259 | if (!decode) { | 2259 | if (!task->tk_msg.rpc_proc->p_decode) { |
2260 | task->tk_action = rpc_exit_task; | 2260 | task->tk_action = rpc_exit_task; |
2261 | return; | 2261 | return; |
2262 | } | 2262 | } |
@@ -2292,29 +2292,27 @@ call_decode(struct rpc_task *task) | |||
2292 | goto out_retry; | 2292 | goto out_retry; |
2293 | } | 2293 | } |
2294 | 2294 | ||
2295 | p = rpc_decode_header(task); | 2295 | xdr_init_decode(&xdr, &req->rq_rcv_buf, |
2296 | if (IS_ERR(p)) { | 2296 | req->rq_rcv_buf.head[0].iov_base, req); |
2297 | if (p == ERR_PTR(-EAGAIN)) | 2297 | switch (rpc_decode_header(task, &xdr)) { |
2298 | goto out_retry; | 2298 | case 0: |
2299 | task->tk_action = rpc_exit_task; | ||
2300 | task->tk_status = rpcauth_unwrap_resp(task, &xdr); | ||
2301 | dprintk("RPC: %5u %s result %d\n", | ||
2302 | task->tk_pid, __func__, task->tk_status); | ||
2299 | return; | 2303 | return; |
2300 | } | 2304 | case -EAGAIN: |
2301 | task->tk_action = rpc_exit_task; | ||
2302 | |||
2303 | task->tk_status = rpcauth_unwrap_resp(task, decode, req, p, | ||
2304 | task->tk_msg.rpc_resp); | ||
2305 | |||
2306 | dprintk("RPC: %5u call_decode result %d\n", task->tk_pid, | ||
2307 | task->tk_status); | ||
2308 | return; | ||
2309 | out_retry: | 2305 | out_retry: |
2310 | task->tk_status = 0; | 2306 | task->tk_status = 0; |
2311 | /* Note: rpc_decode_header() may have freed the RPC slot */ | 2307 | /* Note: rpc_decode_header() may have freed the RPC slot */ |
2312 | if (task->tk_rqstp == req) { | 2308 | if (task->tk_rqstp == req) { |
2313 | xdr_free_bvec(&req->rq_rcv_buf); | 2309 | xdr_free_bvec(&req->rq_rcv_buf); |
2314 | req->rq_reply_bytes_recvd = req->rq_rcv_buf.len = 0; | 2310 | req->rq_reply_bytes_recvd = 0; |
2315 | if (task->tk_client->cl_discrtry) | 2311 | req->rq_rcv_buf.len = 0; |
2316 | xprt_conditional_disconnect(req->rq_xprt, | 2312 | if (task->tk_client->cl_discrtry) |
2317 | req->rq_connect_cookie); | 2313 | xprt_conditional_disconnect(req->rq_xprt, |
2314 | req->rq_connect_cookie); | ||
2315 | } | ||
2318 | } | 2316 | } |
2319 | } | 2317 | } |
2320 | 2318 | ||
@@ -2347,14 +2345,12 @@ out_fail: | |||
2347 | return error; | 2345 | return error; |
2348 | } | 2346 | } |
2349 | 2347 | ||
2350 | static noinline __be32 * | 2348 | static noinline int |
2351 | rpc_decode_header(struct rpc_task *task) | 2349 | rpc_decode_header(struct rpc_task *task, struct xdr_stream *xdr) |
2352 | { | 2350 | { |
2353 | struct rpc_clnt *clnt = task->tk_client; | 2351 | struct rpc_clnt *clnt = task->tk_client; |
2354 | struct kvec *iov = &task->tk_rqstp->rq_rcv_buf.head[0]; | ||
2355 | int len = task->tk_rqstp->rq_rcv_buf.len >> 2; | ||
2356 | __be32 *p = iov->iov_base; | ||
2357 | int error = -EACCES; | 2352 | int error = -EACCES; |
2353 | __be32 *p; | ||
2358 | 2354 | ||
2359 | /* RFC-1014 says that the representation of XDR data must be a | 2355 | /* RFC-1014 says that the representation of XDR data must be a |
2360 | * multiple of four bytes | 2356 | * multiple of four bytes |
@@ -2363,25 +2359,26 @@ rpc_decode_header(struct rpc_task *task) | |||
2363 | */ | 2359 | */ |
2364 | if (task->tk_rqstp->rq_rcv_buf.len & 3) | 2360 | if (task->tk_rqstp->rq_rcv_buf.len & 3) |
2365 | goto out_badlen; | 2361 | goto out_badlen; |
2366 | if ((len -= 3) < 0) | ||
2367 | goto out_unparsable; | ||
2368 | 2362 | ||
2363 | p = xdr_inline_decode(xdr, 3 * sizeof(*p)); | ||
2364 | if (!p) | ||
2365 | goto out_unparsable; | ||
2369 | p++; /* skip XID */ | 2366 | p++; /* skip XID */ |
2370 | if (*p++ != rpc_reply) | 2367 | if (*p++ != rpc_reply) |
2371 | goto out_unparsable; | 2368 | goto out_unparsable; |
2372 | if (*p++ != rpc_msg_accepted) | 2369 | if (*p++ != rpc_msg_accepted) |
2373 | goto out_msg_denied; | 2370 | goto out_msg_denied; |
2374 | 2371 | ||
2375 | p = rpcauth_checkverf(task, p); | 2372 | error = rpcauth_checkverf(task, xdr); |
2376 | if (IS_ERR(p)) | 2373 | if (error) |
2377 | goto out_verifier; | 2374 | goto out_verifier; |
2378 | 2375 | ||
2379 | len = p - (__be32 *)iov->iov_base - 1; | 2376 | p = xdr_inline_decode(xdr, sizeof(*p)); |
2380 | if (len < 0) | 2377 | if (!p) |
2381 | goto out_unparsable; | 2378 | goto out_unparsable; |
2382 | switch (*p++) { | 2379 | switch (*p) { |
2383 | case rpc_success: | 2380 | case rpc_success: |
2384 | return p; | 2381 | return 0; |
2385 | case rpc_prog_unavail: | 2382 | case rpc_prog_unavail: |
2386 | trace_rpc__prog_unavail(task); | 2383 | trace_rpc__prog_unavail(task); |
2387 | error = -EPFNOSUPPORT; | 2384 | error = -EPFNOSUPPORT; |
@@ -2406,11 +2403,11 @@ out_garbage: | |||
2406 | if (task->tk_garb_retry) { | 2403 | if (task->tk_garb_retry) { |
2407 | task->tk_garb_retry--; | 2404 | task->tk_garb_retry--; |
2408 | task->tk_action = call_encode; | 2405 | task->tk_action = call_encode; |
2409 | return ERR_PTR(-EAGAIN); | 2406 | return -EAGAIN; |
2410 | } | 2407 | } |
2411 | out_err: | 2408 | out_err: |
2412 | rpc_exit(task, error); | 2409 | rpc_exit(task, error); |
2413 | return ERR_PTR(error); | 2410 | return error; |
2414 | 2411 | ||
2415 | out_badlen: | 2412 | out_badlen: |
2416 | trace_rpc__unparsable(task); | 2413 | trace_rpc__unparsable(task); |
@@ -2424,10 +2421,12 @@ out_unparsable: | |||
2424 | 2421 | ||
2425 | out_verifier: | 2422 | out_verifier: |
2426 | trace_rpc_bad_verifier(task); | 2423 | trace_rpc_bad_verifier(task); |
2427 | error = PTR_ERR(p); | ||
2428 | goto out_garbage; | 2424 | goto out_garbage; |
2429 | 2425 | ||
2430 | out_msg_denied: | 2426 | out_msg_denied: |
2427 | p = xdr_inline_decode(xdr, sizeof(*p)); | ||
2428 | if (!p) | ||
2429 | goto out_unparsable; | ||
2431 | switch (*p++) { | 2430 | switch (*p++) { |
2432 | case rpc_auth_error: | 2431 | case rpc_auth_error: |
2433 | break; | 2432 | break; |
@@ -2441,6 +2440,9 @@ out_msg_denied: | |||
2441 | goto out_err; | 2440 | goto out_err; |
2442 | } | 2441 | } |
2443 | 2442 | ||
2443 | p = xdr_inline_decode(xdr, sizeof(*p)); | ||
2444 | if (!p) | ||
2445 | goto out_unparsable; | ||
2444 | switch (*p++) { | 2446 | switch (*p++) { |
2445 | case rpc_autherr_rejectedcred: | 2447 | case rpc_autherr_rejectedcred: |
2446 | case rpc_autherr_rejectedverf: | 2448 | case rpc_autherr_rejectedverf: |
@@ -2454,7 +2456,7 @@ out_msg_denied: | |||
2454 | /* Ensure we obtain a new XID! */ | 2456 | /* Ensure we obtain a new XID! */ |
2455 | xprt_release(task); | 2457 | xprt_release(task); |
2456 | task->tk_action = call_reserve; | 2458 | task->tk_action = call_reserve; |
2457 | return ERR_PTR(-EAGAIN); | 2459 | return -EAGAIN; |
2458 | case rpc_autherr_badcred: | 2460 | case rpc_autherr_badcred: |
2459 | case rpc_autherr_badverf: | 2461 | case rpc_autherr_badverf: |
2460 | /* possibly garbled cred/verf? */ | 2462 | /* possibly garbled cred/verf? */ |
@@ -2463,7 +2465,7 @@ out_msg_denied: | |||
2463 | task->tk_garb_retry--; | 2465 | task->tk_garb_retry--; |
2464 | trace_rpc__bad_creds(task); | 2466 | trace_rpc__bad_creds(task); |
2465 | task->tk_action = call_encode; | 2467 | task->tk_action = call_encode; |
2466 | return ERR_PTR(-EAGAIN); | 2468 | return -EAGAIN; |
2467 | case rpc_autherr_tooweak: | 2469 | case rpc_autherr_tooweak: |
2468 | trace_rpc__auth_tooweak(task); | 2470 | trace_rpc__auth_tooweak(task); |
2469 | pr_warn("RPC: server %s requires stronger authentication.\n", | 2471 | pr_warn("RPC: server %s requires stronger authentication.\n", |