aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAvinash Repaka <avinash.repaka@oracle.com>2018-07-24 23:31:58 -0400
committerDavid S. Miller <davem@davemloft.net>2018-07-26 17:03:07 -0400
commit9e630bcb7701f94dbd729fe57d37c089c763ad9f (patch)
tree4d067bad8a0ab8fdf27a8e1daac089353726cbea
parent7effaf06c3cdef6855e127886c7405b9ab62f90d (diff)
RDS: RDMA: Fix the NULL-ptr deref in rds_ib_get_mr
Registration of a memory region(MR) through FRMR/fastreg(unlike FMR) needs a connection/qp. With a proxy qp, this dependency on connection will be removed, but that needs more infrastructure patches, which is a work in progress. As an intermediate fix, the get_mr returns EOPNOTSUPP when connection details are not populated. The MR registration through sendmsg() will continue to work even with fast registration, since connection in this case is formed upfront. This patch fixes the following crash: kasan: GPF could be caused by NULL-ptr deref or user memory access general protection fault: 0000 [#1] SMP KASAN Modules linked in: CPU: 1 PID: 4244 Comm: syzkaller468044 Not tainted 4.16.0-rc6+ #361 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 RIP: 0010:rds_ib_get_mr+0x5c/0x230 net/rds/ib_rdma.c:544 RSP: 0018:ffff8801b059f890 EFLAGS: 00010202 RAX: dffffc0000000000 RBX: ffff8801b07e1300 RCX: ffffffff8562d96e RDX: 000000000000000d RSI: 0000000000000001 RDI: 0000000000000068 RBP: ffff8801b059f8b8 R08: ffffed0036274244 R09: ffff8801b13a1200 R10: 0000000000000004 R11: ffffed0036274243 R12: ffff8801b13a1200 R13: 0000000000000001 R14: ffff8801ca09fa9c R15: 0000000000000000 FS: 00007f4d050af700(0000) GS:ffff8801db300000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f4d050aee78 CR3: 00000001b0d9b006 CR4: 00000000001606e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: __rds_rdma_map+0x710/0x1050 net/rds/rdma.c:271 rds_get_mr_for_dest+0x1d4/0x2c0 net/rds/rdma.c:357 rds_setsockopt+0x6cc/0x980 net/rds/af_rds.c:347 SYSC_setsockopt net/socket.c:1849 [inline] SyS_setsockopt+0x189/0x360 net/socket.c:1828 do_syscall_64+0x281/0x940 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x42/0xb7 RIP: 0033:0x4456d9 RSP: 002b:00007f4d050aedb8 EFLAGS: 00000246 ORIG_RAX: 0000000000000036 RAX: ffffffffffffffda RBX: 00000000006dac3c RCX: 00000000004456d9 RDX: 0000000000000007 RSI: 0000000000000114 RDI: 0000000000000004 RBP: 00000000006dac38 R08: 00000000000000a0 R09: 0000000000000000 R10: 0000000020000380 R11: 0000000000000246 R12: 0000000000000000 R13: 00007fffbfb36d6f R14: 00007f4d050af9c0 R15: 0000000000000005 Code: fa 48 c1 ea 03 80 3c 02 00 0f 85 cc 01 00 00 4c 8b bb 80 04 00 00 48 b8 00 00 00 00 00 fc ff df 49 8d 7f 68 48 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 9c 01 00 00 4d 8b 7f 68 48 b8 00 00 00 00 00 RIP: rds_ib_get_mr+0x5c/0x230 net/rds/ib_rdma.c:544 RSP: ffff8801b059f890 ---[ end trace 7e1cea13b85473b0 ]--- Reported-by: syzbot+b51c77ef956678a65834@syzkaller.appspotmail.com Signed-off-by: Santosh Shilimkar <santosh.shilimkar@oracle.com> Signed-off-by: Avinash Repaka <avinash.repaka@oracle.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/rds/ib_frmr.c5
-rw-r--r--net/rds/ib_mr.h3
-rw-r--r--net/rds/ib_rdma.c21
-rw-r--r--net/rds/rdma.c13
-rw-r--r--net/rds/rds.h5
-rw-r--r--net/rds/send.c12
6 files changed, 39 insertions, 20 deletions
diff --git a/net/rds/ib_frmr.c b/net/rds/ib_frmr.c
index 48332a6ed738..d152e48ea371 100644
--- a/net/rds/ib_frmr.c
+++ b/net/rds/ib_frmr.c
@@ -344,6 +344,11 @@ struct rds_ib_mr *rds_ib_reg_frmr(struct rds_ib_device *rds_ibdev,
344 struct rds_ib_frmr *frmr; 344 struct rds_ib_frmr *frmr;
345 int ret; 345 int ret;
346 346
347 if (!ic) {
348 /* TODO: Add FRWR support for RDS_GET_MR using proxy qp*/
349 return ERR_PTR(-EOPNOTSUPP);
350 }
351
347 do { 352 do {
348 if (ibmr) 353 if (ibmr)
349 rds_ib_free_frmr(ibmr, true); 354 rds_ib_free_frmr(ibmr, true);
diff --git a/net/rds/ib_mr.h b/net/rds/ib_mr.h
index 0ea4ab017a8c..655f01d427fe 100644
--- a/net/rds/ib_mr.h
+++ b/net/rds/ib_mr.h
@@ -115,7 +115,8 @@ void rds_ib_get_mr_info(struct rds_ib_device *rds_ibdev,
115 struct rds_info_rdma_connection *iinfo); 115 struct rds_info_rdma_connection *iinfo);
116void rds_ib_destroy_mr_pool(struct rds_ib_mr_pool *); 116void rds_ib_destroy_mr_pool(struct rds_ib_mr_pool *);
117void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents, 117void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
118 struct rds_sock *rs, u32 *key_ret); 118 struct rds_sock *rs, u32 *key_ret,
119 struct rds_connection *conn);
119void rds_ib_sync_mr(void *trans_private, int dir); 120void rds_ib_sync_mr(void *trans_private, int dir);
120void rds_ib_free_mr(void *trans_private, int invalidate); 121void rds_ib_free_mr(void *trans_private, int invalidate);
121void rds_ib_flush_mrs(void); 122void rds_ib_flush_mrs(void);
diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c
index e678699268a2..2e49a40a5e11 100644
--- a/net/rds/ib_rdma.c
+++ b/net/rds/ib_rdma.c
@@ -537,11 +537,12 @@ void rds_ib_flush_mrs(void)
537} 537}
538 538
539void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents, 539void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
540 struct rds_sock *rs, u32 *key_ret) 540 struct rds_sock *rs, u32 *key_ret,
541 struct rds_connection *conn)
541{ 542{
542 struct rds_ib_device *rds_ibdev; 543 struct rds_ib_device *rds_ibdev;
543 struct rds_ib_mr *ibmr = NULL; 544 struct rds_ib_mr *ibmr = NULL;
544 struct rds_ib_connection *ic = rs->rs_conn->c_transport_data; 545 struct rds_ib_connection *ic = NULL;
545 int ret; 546 int ret;
546 547
547 rds_ibdev = rds_ib_get_device(rs->rs_bound_addr); 548 rds_ibdev = rds_ib_get_device(rs->rs_bound_addr);
@@ -550,6 +551,9 @@ void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
550 goto out; 551 goto out;
551 } 552 }
552 553
554 if (conn)
555 ic = conn->c_transport_data;
556
553 if (!rds_ibdev->mr_8k_pool || !rds_ibdev->mr_1m_pool) { 557 if (!rds_ibdev->mr_8k_pool || !rds_ibdev->mr_1m_pool) {
554 ret = -ENODEV; 558 ret = -ENODEV;
555 goto out; 559 goto out;
@@ -559,17 +563,18 @@ void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
559 ibmr = rds_ib_reg_frmr(rds_ibdev, ic, sg, nents, key_ret); 563 ibmr = rds_ib_reg_frmr(rds_ibdev, ic, sg, nents, key_ret);
560 else 564 else
561 ibmr = rds_ib_reg_fmr(rds_ibdev, sg, nents, key_ret); 565 ibmr = rds_ib_reg_fmr(rds_ibdev, sg, nents, key_ret);
562 if (ibmr) 566 if (IS_ERR(ibmr)) {
563 rds_ibdev = NULL; 567 ret = PTR_ERR(ibmr);
564
565 out:
566 if (!ibmr)
567 pr_warn("RDS/IB: rds_ib_get_mr failed (errno=%d)\n", ret); 568 pr_warn("RDS/IB: rds_ib_get_mr failed (errno=%d)\n", ret);
569 } else {
570 return ibmr;
571 }
568 572
573 out:
569 if (rds_ibdev) 574 if (rds_ibdev)
570 rds_ib_dev_put(rds_ibdev); 575 rds_ib_dev_put(rds_ibdev);
571 576
572 return ibmr; 577 return ERR_PTR(ret);
573} 578}
574 579
575void rds_ib_destroy_mr_pool(struct rds_ib_mr_pool *pool) 580void rds_ib_destroy_mr_pool(struct rds_ib_mr_pool *pool)
diff --git a/net/rds/rdma.c b/net/rds/rdma.c
index 634cfcb7bba6..80920e47f2c7 100644
--- a/net/rds/rdma.c
+++ b/net/rds/rdma.c
@@ -170,7 +170,8 @@ static int rds_pin_pages(unsigned long user_addr, unsigned int nr_pages,
170} 170}
171 171
172static int __rds_rdma_map(struct rds_sock *rs, struct rds_get_mr_args *args, 172static int __rds_rdma_map(struct rds_sock *rs, struct rds_get_mr_args *args,
173 u64 *cookie_ret, struct rds_mr **mr_ret) 173 u64 *cookie_ret, struct rds_mr **mr_ret,
174 struct rds_conn_path *cp)
174{ 175{
175 struct rds_mr *mr = NULL, *found; 176 struct rds_mr *mr = NULL, *found;
176 unsigned int nr_pages; 177 unsigned int nr_pages;
@@ -269,7 +270,8 @@ static int __rds_rdma_map(struct rds_sock *rs, struct rds_get_mr_args *args,
269 * Note that dma_map() implies that pending writes are 270 * Note that dma_map() implies that pending writes are
270 * flushed to RAM, so no dma_sync is needed here. */ 271 * flushed to RAM, so no dma_sync is needed here. */
271 trans_private = rs->rs_transport->get_mr(sg, nents, rs, 272 trans_private = rs->rs_transport->get_mr(sg, nents, rs,
272 &mr->r_key); 273 &mr->r_key,
274 cp ? cp->cp_conn : NULL);
273 275
274 if (IS_ERR(trans_private)) { 276 if (IS_ERR(trans_private)) {
275 for (i = 0 ; i < nents; i++) 277 for (i = 0 ; i < nents; i++)
@@ -330,7 +332,7 @@ int rds_get_mr(struct rds_sock *rs, char __user *optval, int optlen)
330 sizeof(struct rds_get_mr_args))) 332 sizeof(struct rds_get_mr_args)))
331 return -EFAULT; 333 return -EFAULT;
332 334
333 return __rds_rdma_map(rs, &args, NULL, NULL); 335 return __rds_rdma_map(rs, &args, NULL, NULL, NULL);
334} 336}
335 337
336int rds_get_mr_for_dest(struct rds_sock *rs, char __user *optval, int optlen) 338int rds_get_mr_for_dest(struct rds_sock *rs, char __user *optval, int optlen)
@@ -354,7 +356,7 @@ int rds_get_mr_for_dest(struct rds_sock *rs, char __user *optval, int optlen)
354 new_args.cookie_addr = args.cookie_addr; 356 new_args.cookie_addr = args.cookie_addr;
355 new_args.flags = args.flags; 357 new_args.flags = args.flags;
356 358
357 return __rds_rdma_map(rs, &new_args, NULL, NULL); 359 return __rds_rdma_map(rs, &new_args, NULL, NULL, NULL);
358} 360}
359 361
360/* 362/*
@@ -782,7 +784,8 @@ int rds_cmsg_rdma_map(struct rds_sock *rs, struct rds_message *rm,
782 rm->m_rdma_cookie != 0) 784 rm->m_rdma_cookie != 0)
783 return -EINVAL; 785 return -EINVAL;
784 786
785 return __rds_rdma_map(rs, CMSG_DATA(cmsg), &rm->m_rdma_cookie, &rm->rdma.op_rdma_mr); 787 return __rds_rdma_map(rs, CMSG_DATA(cmsg), &rm->m_rdma_cookie,
788 &rm->rdma.op_rdma_mr, rm->m_conn_path);
786} 789}
787 790
788/* 791/*
diff --git a/net/rds/rds.h b/net/rds/rds.h
index f2272fb8cd45..60b3b787fbdb 100644
--- a/net/rds/rds.h
+++ b/net/rds/rds.h
@@ -464,6 +464,8 @@ struct rds_message {
464 struct scatterlist *op_sg; 464 struct scatterlist *op_sg;
465 } data; 465 } data;
466 }; 466 };
467
468 struct rds_conn_path *m_conn_path;
467}; 469};
468 470
469/* 471/*
@@ -544,7 +546,8 @@ struct rds_transport {
544 unsigned int avail); 546 unsigned int avail);
545 void (*exit)(void); 547 void (*exit)(void);
546 void *(*get_mr)(struct scatterlist *sg, unsigned long nr_sg, 548 void *(*get_mr)(struct scatterlist *sg, unsigned long nr_sg,
547 struct rds_sock *rs, u32 *key_ret); 549 struct rds_sock *rs, u32 *key_ret,
550 struct rds_connection *conn);
548 void (*sync_mr)(void *trans_private, int direction); 551 void (*sync_mr)(void *trans_private, int direction);
549 void (*free_mr)(void *trans_private, int invalidate); 552 void (*free_mr)(void *trans_private, int invalidate);
550 void (*flush_mrs)(void); 553 void (*flush_mrs)(void);
diff --git a/net/rds/send.c b/net/rds/send.c
index 94c7f74909be..59f17a2335f4 100644
--- a/net/rds/send.c
+++ b/net/rds/send.c
@@ -1169,6 +1169,13 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len)
1169 rs->rs_conn = conn; 1169 rs->rs_conn = conn;
1170 } 1170 }
1171 1171
1172 if (conn->c_trans->t_mp_capable)
1173 cpath = &conn->c_path[rds_send_mprds_hash(rs, conn)];
1174 else
1175 cpath = &conn->c_path[0];
1176
1177 rm->m_conn_path = cpath;
1178
1172 /* Parse any control messages the user may have included. */ 1179 /* Parse any control messages the user may have included. */
1173 ret = rds_cmsg_send(rs, rm, msg, &allocated_mr); 1180 ret = rds_cmsg_send(rs, rm, msg, &allocated_mr);
1174 if (ret) { 1181 if (ret) {
@@ -1192,11 +1199,6 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len)
1192 goto out; 1199 goto out;
1193 } 1200 }
1194 1201
1195 if (conn->c_trans->t_mp_capable)
1196 cpath = &conn->c_path[rds_send_mprds_hash(rs, conn)];
1197 else
1198 cpath = &conn->c_path[0];
1199
1200 if (rds_destroy_pending(conn)) { 1202 if (rds_destroy_pending(conn)) {
1201 ret = -EAGAIN; 1203 ret = -EAGAIN;
1202 goto out; 1204 goto out;