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 /net/sunrpc/clnt.c | |
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>
Diffstat (limited to 'net/sunrpc/clnt.c')
-rw-r--r-- | net/sunrpc/clnt.c | 88 |
1 files changed, 45 insertions, 43 deletions
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", |