[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