SUNRPC: Fix generation of universal addresses for
authorChuck Lever <chuck.lever@oracle.com>
Thu, 16 Aug 2007 20:03:31 +0000 (16:03 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 9 Oct 2007 21:16:32 +0000 (17:16 -0400)
Fix some problems with rpcbind v3 and v4 queries from the in-kernel rpcbind
client:

1.  The r_addr argument must be a full universal address, not just an IP
address, and

2.  The universal address in r_addr is the address of the remote rpcbind
server, not the RPC service being requested

This addresses bugzilla.kernel.org report 8891 for 2.6.23-rc and greater.

In addition, if the rpcbind client is unable to start the rpcbind request,
make sure not to leak the xprt.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
net/sunrpc/rpcb_clnt.c

index 7db75e177e6788392933756c8c40e33d6a68754b..0bb6709018de2a044c026bc92af86fb717b90209 100644 (file)
@@ -387,6 +387,15 @@ void rpcb_getport_async(struct rpc_task *task)
        dprintk("RPC: %5u %s: trying rpcbind version %u\n",
                task->tk_pid, __FUNCTION__, bind_version);
 
+       rpcb_clnt = rpcb_create(clnt->cl_server, &addr, xprt->prot,
+                               bind_version, 0);
+       if (IS_ERR(rpcb_clnt)) {
+               status = PTR_ERR(rpcb_clnt);
+               dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n",
+                       task->tk_pid, __FUNCTION__, PTR_ERR(rpcb_clnt));
+               goto bailout_nofree;
+       }
+
        map = kzalloc(sizeof(struct rpcbind_args), GFP_ATOMIC);
        if (!map) {
                status = -ENOMEM;
@@ -401,25 +410,18 @@ void rpcb_getport_async(struct rpc_task *task)
        map->r_xprt = xprt_get(xprt);
        map->r_netid = (xprt->prot == IPPROTO_TCP) ? RPCB_NETID_TCP :
                                                   RPCB_NETID_UDP;
-       memcpy(&map->r_addr, rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR),
-                       sizeof(map->r_addr));
+       memcpy(&map->r_addr,
+              rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR),
+              sizeof(map->r_addr));
        map->r_owner = RPCB_OWNER_STRING;       /* ignored for GETADDR */
 
-       rpcb_clnt = rpcb_create(clnt->cl_server, &addr, xprt->prot, bind_version, 0);
-       if (IS_ERR(rpcb_clnt)) {
-               status = PTR_ERR(rpcb_clnt);
-               dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n",
-                       task->tk_pid, __FUNCTION__, PTR_ERR(rpcb_clnt));
-               goto bailout;
-       }
-
        child = rpc_run_task(rpcb_clnt, RPC_TASK_ASYNC, &rpcb_getport_ops, map);
        rpc_release_client(rpcb_clnt);
        if (IS_ERR(child)) {
                status = -EIO;
                dprintk("RPC: %5u %s: rpc_run_task failed\n",
                        task->tk_pid, __FUNCTION__);
-               goto bailout_nofree;
+               goto bailout;
        }
        rpc_put_task(child);