[rds-devel] [PATCH] Fix RDS TCP loopback crash
Olaf Kirch
olaf.kirch at oracle.com
Thu Jan 10 03:40:11 PST 2008
[RDS] Prevent TCP crash on loopback
This patch addresses OFED Bug #734
It's possible to provoke a crash by issuing "telnet localhost 18634".
The reason is this:
- when we accept an incoming connection, we call rds_conn_create
to create a rds_connection object, using the tcp_transport.
- rds_conn_create notices that the destination address is in
fact a local address, and substitutes the loopback transport.
- The TCP code calls tcp_set_callbacks, and tries to retrieve
the TCP private transport data from the newly created conn.
However, since it's a loop conn, not a tcp conn, there is
no private transport data, and we die dereferencing a NULL
pointer.
So the bug is obviously the ill-guided decision to substitute the
loopback transport even though it's an incoming connection, and
we *have* to use the transport that the connection arrived on.
The patch renames rds_conn_create to rds_conn_create_outgoing,
and creates a new rds_conn_create which works like before,
minus the automatic substitution of the loop transport.
I also changed two call sites (in send.c and rdma.c) to use the
new _outgoing function to look up a connection.
Signed-off-by: Olaf Kirch <olaf.kirch at oracle.com>
---
net/rds/connection.c | 21 ++++++++++++++++++---
net/rds/rdma.c | 2 +-
net/rds/rds.h | 2 ++
net/rds/send.c | 5 +++--
4 files changed, 24 insertions(+), 6 deletions(-)
Index: ofa_kernel-1.3/net/rds/connection.c
===================================================================
--- ofa_kernel-1.3.orig/net/rds/connection.c
+++ ofa_kernel-1.3/net/rds/connection.c
@@ -128,8 +128,9 @@ void rds_conn_reset(struct rds_connectio
* For now they are not garbage collected once they're created. They
* are torn down as the module is removed, if ever.
*/
-struct rds_connection *rds_conn_create(__be32 laddr, __be32 faddr,
- struct rds_transport *trans, gfp_t gfp)
+static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
+ struct rds_transport *trans, gfp_t gfp,
+ int allow_loop_transport)
{
struct rds_connection *conn, *tmp;
struct hlist_head *head = rds_conn_bucket(laddr, faddr);
@@ -184,7 +185,7 @@ struct rds_connection *rds_conn_create(_
* can bind to the destination address then we'd rather the messages
* flow through loopback rather than either transport.
*/
- if (rds_trans_get_preferred(faddr))
+ if (allow_loop_transport && rds_trans_get_preferred(faddr))
trans = &rds_loop_transport;
conn->c_trans = trans;
@@ -225,7 +226,21 @@ struct rds_connection *rds_conn_create(_
out:
return conn;
}
+
+struct rds_connection *rds_conn_create(__be32 laddr, __be32 faddr,
+ struct rds_transport *trans, gfp_t gfp)
+{
+ return __rds_conn_create(laddr, faddr, trans, gfp, 0);
+}
+
+struct rds_connection *rds_conn_create_outgoing(__be32 laddr, __be32 faddr,
+ struct rds_transport *trans, gfp_t gfp)
+{
+ return __rds_conn_create(laddr, faddr, trans, gfp, 1);
+}
+
EXPORT_SYMBOL_GPL(rds_conn_create);
+EXPORT_SYMBOL_GPL(rds_conn_create_outgoing);
static void rds_conn_message_info(struct socket *sock, unsigned int len,
struct rds_info_iterator *iter,
Index: ofa_kernel-1.3/net/rds/rdma.c
===================================================================
--- ofa_kernel-1.3.orig/net/rds/rdma.c
+++ ofa_kernel-1.3/net/rds/rdma.c
@@ -686,7 +686,7 @@ int rds_barrier(struct rds_sock *rs, cha
goto out;
}
- conn = rds_conn_create(rs->rs_bound_addr, daddr, rs->rs_transport,
+ conn = rds_conn_create_outgoing(rs->rs_bound_addr, daddr, rs->rs_transport,
sk->sk_allocation);
if (IS_ERR(conn)) {
ret = PTR_ERR(conn);
Index: ofa_kernel-1.3/net/rds/rds.h
===================================================================
--- ofa_kernel-1.3.orig/net/rds/rds.h
+++ ofa_kernel-1.3/net/rds/rds.h
@@ -506,6 +506,8 @@ int __init rds_conn_init(void);
void __exit rds_conn_exit(void);
struct rds_connection *rds_conn_create(__be32 laddr, __be32 faddr,
struct rds_transport *trans, gfp_t gfp);
+struct rds_connection *rds_conn_create_outgoing(__be32 laddr, __be32 faddr,
+ struct rds_transport *trans, gfp_t gfp);
void rds_conn_reset(struct rds_connection *conn);
void rds_conn_drop(struct rds_connection *conn);
void __rds_conn_error(struct rds_connection *conn, const char *, ...)
Index: ofa_kernel-1.3/net/rds/send.c
===================================================================
--- ofa_kernel-1.3.orig/net/rds/send.c
+++ ofa_kernel-1.3/net/rds/send.c
@@ -636,8 +636,9 @@ int rds_sendmsg(struct kiocb *iocb, stru
/* rds_conn_create has a spinlock that runs with IRQ off.
* Caching the conn in the socket helps a lot. */
if ((conn = rs->rs_conn) == NULL || conn->c_faddr != daddr) {
- conn = rds_conn_create(rs->rs_bound_addr, daddr, rs->rs_transport,
- sock->sk->sk_allocation);
+ conn = rds_conn_create_outgoing(rs->rs_bound_addr, daddr,
+ rs->rs_transport,
+ sock->sk->sk_allocation);
if (IS_ERR(conn)) {
ret = PTR_ERR(conn);
goto out;
--
Olaf Kirch | --- o --- Nous sommes du soleil we love when we play
okir at lst.de | / | \ sol.dhoop.naytheet.ah kin.ir.samse.qurax
More information about the rds-devel
mailing list