rds: avoid potential stack overflow

[ Upstream commit f862e07cf95d5b62a5fc5e981dd7d0dbaf33a501 ]

The rds_iw_update_cm_id function stores a large 'struct rds_sock' object
on the stack in order to pass a pair of addresses. This happens to just
fit withint the 1024 byte stack size warning limit on x86, but just
exceed that limit on ARM, which gives us this warning:

net/rds/iw_rdma.c:200:1: warning: the frame size of 1056 bytes is larger than 1024 bytes [-Wframe-larger-than=]

As the use of this large variable is basically bogus, we can rearrange
the code to not do that. Instead of passing an rds socket into
rds_iw_get_device, we now just pass the two addresses that we have
available in rds_iw_update_cm_id, and we change rds_iw_get_mr accordingly,
to create two address structures on the stack there.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Sowmini Varadhan <sowmini.varadhan@oracle.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Arnd Bergmann 2015-03-11 22:46:59 +01:00 committed by Greg Kroah-Hartman
parent e2f572a9be
commit 895652af31
1 changed files with 22 additions and 18 deletions

View File

@ -88,7 +88,9 @@ static unsigned int rds_iw_unmap_fastreg_list(struct rds_iw_mr_pool *pool,
int *unpinned); int *unpinned);
static void rds_iw_destroy_fastreg(struct rds_iw_mr_pool *pool, struct rds_iw_mr *ibmr); static void rds_iw_destroy_fastreg(struct rds_iw_mr_pool *pool, struct rds_iw_mr *ibmr);
static int rds_iw_get_device(struct rds_sock *rs, struct rds_iw_device **rds_iwdev, struct rdma_cm_id **cm_id) static int rds_iw_get_device(struct sockaddr_in *src, struct sockaddr_in *dst,
struct rds_iw_device **rds_iwdev,
struct rdma_cm_id **cm_id)
{ {
struct rds_iw_device *iwdev; struct rds_iw_device *iwdev;
struct rds_iw_cm_id *i_cm_id; struct rds_iw_cm_id *i_cm_id;
@ -112,15 +114,15 @@ static int rds_iw_get_device(struct rds_sock *rs, struct rds_iw_device **rds_iwd
src_addr->sin_port, src_addr->sin_port,
dst_addr->sin_addr.s_addr, dst_addr->sin_addr.s_addr,
dst_addr->sin_port, dst_addr->sin_port,
rs->rs_bound_addr, src->sin_addr.s_addr,
rs->rs_bound_port, src->sin_port,
rs->rs_conn_addr, dst->sin_addr.s_addr,
rs->rs_conn_port); dst->sin_port);
#ifdef WORKING_TUPLE_DETECTION #ifdef WORKING_TUPLE_DETECTION
if (src_addr->sin_addr.s_addr == rs->rs_bound_addr && if (src_addr->sin_addr.s_addr == src->sin_addr.s_addr &&
src_addr->sin_port == rs->rs_bound_port && src_addr->sin_port == src->sin_port &&
dst_addr->sin_addr.s_addr == rs->rs_conn_addr && dst_addr->sin_addr.s_addr == dst->sin_addr.s_addr &&
dst_addr->sin_port == rs->rs_conn_port) { dst_addr->sin_port == dst->sin_port) {
#else #else
/* FIXME - needs to compare the local and remote /* FIXME - needs to compare the local and remote
* ipaddr/port tuple, but the ipaddr is the only * ipaddr/port tuple, but the ipaddr is the only
@ -128,7 +130,7 @@ static int rds_iw_get_device(struct rds_sock *rs, struct rds_iw_device **rds_iwd
* zero'ed. It doesn't appear to be properly populated * zero'ed. It doesn't appear to be properly populated
* during connection setup... * during connection setup...
*/ */
if (src_addr->sin_addr.s_addr == rs->rs_bound_addr) { if (src_addr->sin_addr.s_addr == src->sin_addr.s_addr) {
#endif #endif
spin_unlock_irq(&iwdev->spinlock); spin_unlock_irq(&iwdev->spinlock);
*rds_iwdev = iwdev; *rds_iwdev = iwdev;
@ -180,19 +182,13 @@ int rds_iw_update_cm_id(struct rds_iw_device *rds_iwdev, struct rdma_cm_id *cm_i
{ {
struct sockaddr_in *src_addr, *dst_addr; struct sockaddr_in *src_addr, *dst_addr;
struct rds_iw_device *rds_iwdev_old; struct rds_iw_device *rds_iwdev_old;
struct rds_sock rs;
struct rdma_cm_id *pcm_id; struct rdma_cm_id *pcm_id;
int rc; int rc;
src_addr = (struct sockaddr_in *)&cm_id->route.addr.src_addr; src_addr = (struct sockaddr_in *)&cm_id->route.addr.src_addr;
dst_addr = (struct sockaddr_in *)&cm_id->route.addr.dst_addr; dst_addr = (struct sockaddr_in *)&cm_id->route.addr.dst_addr;
rs.rs_bound_addr = src_addr->sin_addr.s_addr; rc = rds_iw_get_device(src_addr, dst_addr, &rds_iwdev_old, &pcm_id);
rs.rs_bound_port = src_addr->sin_port;
rs.rs_conn_addr = dst_addr->sin_addr.s_addr;
rs.rs_conn_port = dst_addr->sin_port;
rc = rds_iw_get_device(&rs, &rds_iwdev_old, &pcm_id);
if (rc) if (rc)
rds_iw_remove_cm_id(rds_iwdev, cm_id); rds_iw_remove_cm_id(rds_iwdev, cm_id);
@ -598,9 +594,17 @@ void *rds_iw_get_mr(struct scatterlist *sg, unsigned long nents,
struct rds_iw_device *rds_iwdev; struct rds_iw_device *rds_iwdev;
struct rds_iw_mr *ibmr = NULL; struct rds_iw_mr *ibmr = NULL;
struct rdma_cm_id *cm_id; struct rdma_cm_id *cm_id;
struct sockaddr_in src = {
.sin_addr.s_addr = rs->rs_bound_addr,
.sin_port = rs->rs_bound_port,
};
struct sockaddr_in dst = {
.sin_addr.s_addr = rs->rs_conn_addr,
.sin_port = rs->rs_conn_port,
};
int ret; int ret;
ret = rds_iw_get_device(rs, &rds_iwdev, &cm_id); ret = rds_iw_get_device(&src, &dst, &rds_iwdev, &cm_id);
if (ret || !cm_id) { if (ret || !cm_id) {
ret = -ENODEV; ret = -ENODEV;
goto out; goto out;