Commit 23288376 authored by Trond Myklebust's avatar Trond Myklebust Committed by Linus Torvalds

[PATCH] Fix NFS locking over TCP

The 2.5.x RPC code is currently broken in that it demands that all
tasks that call xprt_create_proto() in order to open a TCP socket must
have CAP_NET_BIND_SERVICE capabilities, and must bind to a privileged
port.

This breaks the NLM locking code and its use of the call_bind() RPC
portmapper lookup feature.

This patch allows the built-in portmapper client to use unbound TCP
sockets if the user does not have the necessary capabilities.
parent 63a5ba42
...@@ -146,6 +146,7 @@ struct rpc_xprt { ...@@ -146,6 +146,7 @@ struct rpc_xprt {
unsigned long sockstate; /* Socket state */ unsigned long sockstate; /* Socket state */
unsigned char shutdown : 1, /* being shut down */ unsigned char shutdown : 1, /* being shut down */
nocong : 1, /* no congestion control */ nocong : 1, /* no congestion control */
resvport : 1, /* use a reserved port */
stream : 1; /* TCP */ stream : 1; /* TCP */
/* /*
......
...@@ -89,7 +89,7 @@ static void xprt_disconnect(struct rpc_xprt *); ...@@ -89,7 +89,7 @@ static void xprt_disconnect(struct rpc_xprt *);
static void xprt_conn_status(struct rpc_task *task); static void xprt_conn_status(struct rpc_task *task);
static struct rpc_xprt * xprt_setup(int proto, struct sockaddr_in *ap, static struct rpc_xprt * xprt_setup(int proto, struct sockaddr_in *ap,
struct rpc_timeout *to); struct rpc_timeout *to);
static struct socket *xprt_create_socket(int, struct rpc_timeout *); static struct socket *xprt_create_socket(int, struct rpc_timeout *, int);
static void xprt_bind_socket(struct rpc_xprt *, struct socket *); static void xprt_bind_socket(struct rpc_xprt *, struct socket *);
static int __xprt_get_cong(struct rpc_xprt *, struct rpc_task *); static int __xprt_get_cong(struct rpc_xprt *, struct rpc_task *);
...@@ -442,7 +442,7 @@ xprt_connect(struct rpc_task *task) ...@@ -442,7 +442,7 @@ xprt_connect(struct rpc_task *task)
* Start by resetting any existing state. * Start by resetting any existing state.
*/ */
xprt_close(xprt); xprt_close(xprt);
if (!(sock = xprt_create_socket(xprt->prot, &xprt->timeout))) { if (!(sock = xprt_create_socket(xprt->prot, &xprt->timeout, xprt->resvport))) {
/* couldn't create socket or bind to reserved port; /* couldn't create socket or bind to reserved port;
* this is likely a permanent error, so cause an abort */ * this is likely a permanent error, so cause an abort */
task->tk_status = -EIO; task->tk_status = -EIO;
...@@ -1490,7 +1490,7 @@ xprt_sock_setbufsize(struct rpc_xprt *xprt) ...@@ -1490,7 +1490,7 @@ xprt_sock_setbufsize(struct rpc_xprt *xprt)
* and connect stream sockets. * and connect stream sockets.
*/ */
static struct socket * static struct socket *
xprt_create_socket(int proto, struct rpc_timeout *to) xprt_create_socket(int proto, struct rpc_timeout *to, int resvport)
{ {
struct socket *sock; struct socket *sock;
int type, err; int type, err;
...@@ -1506,7 +1506,7 @@ xprt_create_socket(int proto, struct rpc_timeout *to) ...@@ -1506,7 +1506,7 @@ xprt_create_socket(int proto, struct rpc_timeout *to)
} }
/* If the caller has the capability, bind to a reserved port */ /* If the caller has the capability, bind to a reserved port */
if (capable(CAP_NET_BIND_SERVICE) && xprt_bindresvport(sock) < 0) { if (resvport && xprt_bindresvport(sock) < 0) {
printk("RPC: can't bind to reserved port.\n"); printk("RPC: can't bind to reserved port.\n");
goto failed; goto failed;
} }
...@@ -1528,29 +1528,25 @@ xprt_create_proto(int proto, struct sockaddr_in *sap, struct rpc_timeout *to) ...@@ -1528,29 +1528,25 @@ xprt_create_proto(int proto, struct sockaddr_in *sap, struct rpc_timeout *to)
xprt = xprt_setup(proto, sap, to); xprt = xprt_setup(proto, sap, to);
if (!xprt) if (!xprt)
goto out; goto out_bad;
xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0;
if (!xprt->stream) { if (!xprt->stream) {
struct socket *sock = xprt_create_socket(proto, to); struct socket *sock;
if (sock)
xprt_bind_socket(xprt, sock); sock = xprt_create_socket(proto, to, xprt->resvport);
else { if (!sock)
rpc_free(xprt); goto out_bad;
xprt = NULL; xprt_bind_socket(xprt, sock);
} }
} else
/*
* Don't allow a TCP service user unless they have
* enough capability to bind a reserved port.
*/
if (!capable(CAP_NET_BIND_SERVICE)) {
rpc_free(xprt);
xprt = NULL;
}
out:
dprintk("RPC: xprt_create_proto created xprt %p\n", xprt); dprintk("RPC: xprt_create_proto created xprt %p\n", xprt);
return xprt; return xprt;
out_bad:
dprintk("RPC: xprt_create_proto failed\n");
if (xprt)
rpc_free(xprt);
return NULL;
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment