Thread (6 messages) 6 messages, 3 authors, 2021-05-01

Re: Coverity: frwr_unmap_sync(): Null pointer dereferences

From: Chuck Lever III <hidden>
Date: 2021-05-01 00:49:58

On Apr 30, 2021, at 8:27 PM, Trond Myklebust [off-list ref] wrote:

On Fri, 2021-04-30 at 20:12 +0000, Chuck Lever III wrote:
quoted
quoted
On Apr 30, 2021, at 3:09 PM, Trond Myklebust <
trondmy@hammerspace.com> wrote:

On Fri, 2021-04-30 at 18:45 +0000, Chuck Lever III wrote:
quoted
quoted
On Apr 30, 2021, at 2:26 PM, coverity-bot <
keescook@chromium.org>
wrote:

Hello!

This is an experimental semi-automated report about issues
detected
by
Coverity from a scan of next-20210430 as part of the linux-next
scan project:
https://scan.coverity.com/projects/linux-next-weekly-scan

You're getting this email because you were associated with the
identified
lines of code (noted below) that were touched by commits:

 Mon Apr 26 09:27:06 2021 -0400
   9a301cafc861 ("xprtrdma: Move fr_linv_done field to struct
rpcrdma_mr")

Coverity reported the following:

*** CID 1504556:  Null pointer dereferences  (FORWARD_NULL)
/net/sunrpc/xprtrdma/frwr_ops.c: 539 in frwr_unmap_sync()
533
534             /* Strong send queue ordering guarantees that
when
the
535              * last WR in the chain completes, all WRs in
the
chain
536              * are complete.
537              */
538             last->wr_cqe->done = frwr_wc_localinv_wake;
vvv     CID 1504556:  Null pointer dereferences  (FORWARD_NULL)
vvv     Passing null pointer "&mr->mr_linv_done" to
"reinit_completion", which dereferences it.
539             reinit_completion(&mr->mr_linv_done);
540
541             /* Transport disconnect drains the receive CQ
before it
542              * replaces the QP. The RPC reply handler won't
call us
543              * unless re_id->qp is a valid pointer.
544              */

If this is a false positive, please let us know so we can mark
it
as
such, or teach the Coverity rules to be smarter.
Sure, not my proudest moment here.

The sole call site for frwr_unmap_sync() is this one:

net/sunrpc/xprtrdma/transport.c:
606         if (unlikely(!list_empty(&req->rl_registered))) {
607                 trace_xprtrdma_mrs_zap(task);
608                 frwr_unmap_sync(rpcx_to_rdmax(rqst->rq_xprt),
req);
609         }

Thus, in the current code base, the while() loop:

net/sunrpc/xprtrdma/frwr_ops.c:
514         while ((mr = rpcrdma_mr_pop(&req->rl_registered))) {

Should always terminate with mr containing a non-NULL address.

Seems to me the frwr_unmap_sync() code before fdf5ecb1934b
("xprtrdma: Move fr_linv_done field to struct rpcrdma_mr") has
the same risk -- frwr can be NULL if rl_registered is empty.

I'm open to suggestions for improvement, but I'm not seeing this
rise to the level of a pervasive and high impact issue.
Chuck, I think the point is that you can't ever exit that while()
loop
_unless_ mr == NULL. So calling reinit_completion(&mr-
quoted
mr_linv_done)
after exiting that loop will indeed Oops.
D'oh.

quoted
So will the call to wait_for_completion(&mr->mr_linv_done).

IOW: I think you need to save the last non-NULL value of 'mr'
inside
the loop.
I think following the while() loop with:

   mr = container_of(last, struct rpcrdma_mr, mr_invwr);

Might also work.
Sounds good. Will be you sending me an updated+tested patch?
I’ll post a fix by Sunday evening. You can squash it into the original if you like.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help