Skip to content

Commit 082bb94

Browse files
Mani-Sadhasivamdavem330
authored andcommitted
net: qrtr: ns: Fix the incorrect usage of rcu_read_lock()
The rcu_read_lock() is not supposed to lock the kernel_sendmsg() API since it has the lock_sock() in qrtr_sendmsg() which will sleep. Hence, fix it by excluding the locking for kernel_sendmsg(). While at it, let's also use radix_tree_deref_retry() to confirm the validity of the pointer returned by radix_tree_deref_slot() and use radix_tree_iter_resume() to resume iterating the tree properly before releasing the lock as suggested by Doug. Fixes: a7809ff ("net: qrtr: ns: Protect radix_tree_deref_slot() using rcu read locks") Reported-by: Douglas Anderson <[email protected]> Reviewed-by: Douglas Anderson <[email protected]> Tested-by: Douglas Anderson <[email protected]> Tested-by: Alex Elder <[email protected]> Signed-off-by: Manivannan Sadhasivam <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 7575fdd commit 082bb94

File tree

1 file changed

+64
-12
lines changed

1 file changed

+64
-12
lines changed

net/qrtr/ns.c

+64-12
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ static int announce_servers(struct sockaddr_qrtr *sq)
193193
struct qrtr_server *srv;
194194
struct qrtr_node *node;
195195
void __rcu **slot;
196-
int ret = 0;
196+
int ret;
197197

198198
node = node_get(qrtr_ns.local_node);
199199
if (!node)
@@ -203,18 +203,27 @@ static int announce_servers(struct sockaddr_qrtr *sq)
203203
/* Announce the list of servers registered in this node */
204204
radix_tree_for_each_slot(slot, &node->servers, &iter, 0) {
205205
srv = radix_tree_deref_slot(slot);
206+
if (!srv)
207+
continue;
208+
if (radix_tree_deref_retry(srv)) {
209+
slot = radix_tree_iter_retry(&iter);
210+
continue;
211+
}
212+
slot = radix_tree_iter_resume(slot, &iter);
213+
rcu_read_unlock();
206214

207215
ret = service_announce_new(sq, srv);
208216
if (ret < 0) {
209217
pr_err("failed to announce new service\n");
210-
goto err_out;
218+
return ret;
211219
}
220+
221+
rcu_read_lock();
212222
}
213223

214-
err_out:
215224
rcu_read_unlock();
216225

217-
return ret;
226+
return 0;
218227
}
219228

220229
static struct qrtr_server *server_add(unsigned int service,
@@ -339,7 +348,7 @@ static int ctrl_cmd_bye(struct sockaddr_qrtr *from)
339348
struct qrtr_node *node;
340349
void __rcu **slot;
341350
struct kvec iv;
342-
int ret = 0;
351+
int ret;
343352

344353
iv.iov_base = &pkt;
345354
iv.iov_len = sizeof(pkt);
@@ -352,7 +361,16 @@ static int ctrl_cmd_bye(struct sockaddr_qrtr *from)
352361
/* Advertise removal of this client to all servers of remote node */
353362
radix_tree_for_each_slot(slot, &node->servers, &iter, 0) {
354363
srv = radix_tree_deref_slot(slot);
364+
if (!srv)
365+
continue;
366+
if (radix_tree_deref_retry(srv)) {
367+
slot = radix_tree_iter_retry(&iter);
368+
continue;
369+
}
370+
slot = radix_tree_iter_resume(slot, &iter);
371+
rcu_read_unlock();
355372
server_del(node, srv->port);
373+
rcu_read_lock();
356374
}
357375
rcu_read_unlock();
358376

@@ -368,6 +386,14 @@ static int ctrl_cmd_bye(struct sockaddr_qrtr *from)
368386
rcu_read_lock();
369387
radix_tree_for_each_slot(slot, &local_node->servers, &iter, 0) {
370388
srv = radix_tree_deref_slot(slot);
389+
if (!srv)
390+
continue;
391+
if (radix_tree_deref_retry(srv)) {
392+
slot = radix_tree_iter_retry(&iter);
393+
continue;
394+
}
395+
slot = radix_tree_iter_resume(slot, &iter);
396+
rcu_read_unlock();
371397

372398
sq.sq_family = AF_QIPCRTR;
373399
sq.sq_node = srv->node;
@@ -379,14 +405,14 @@ static int ctrl_cmd_bye(struct sockaddr_qrtr *from)
379405
ret = kernel_sendmsg(qrtr_ns.sock, &msg, &iv, 1, sizeof(pkt));
380406
if (ret < 0) {
381407
pr_err("failed to send bye cmd\n");
382-
goto err_out;
408+
return ret;
383409
}
410+
rcu_read_lock();
384411
}
385412

386-
err_out:
387413
rcu_read_unlock();
388414

389-
return ret;
415+
return 0;
390416
}
391417

392418
static int ctrl_cmd_del_client(struct sockaddr_qrtr *from,
@@ -404,7 +430,7 @@ static int ctrl_cmd_del_client(struct sockaddr_qrtr *from,
404430
struct list_head *li;
405431
void __rcu **slot;
406432
struct kvec iv;
407-
int ret = 0;
433+
int ret;
408434

409435
iv.iov_base = &pkt;
410436
iv.iov_len = sizeof(pkt);
@@ -447,6 +473,14 @@ static int ctrl_cmd_del_client(struct sockaddr_qrtr *from,
447473
rcu_read_lock();
448474
radix_tree_for_each_slot(slot, &local_node->servers, &iter, 0) {
449475
srv = radix_tree_deref_slot(slot);
476+
if (!srv)
477+
continue;
478+
if (radix_tree_deref_retry(srv)) {
479+
slot = radix_tree_iter_retry(&iter);
480+
continue;
481+
}
482+
slot = radix_tree_iter_resume(slot, &iter);
483+
rcu_read_unlock();
450484

451485
sq.sq_family = AF_QIPCRTR;
452486
sq.sq_node = srv->node;
@@ -458,14 +492,14 @@ static int ctrl_cmd_del_client(struct sockaddr_qrtr *from,
458492
ret = kernel_sendmsg(qrtr_ns.sock, &msg, &iv, 1, sizeof(pkt));
459493
if (ret < 0) {
460494
pr_err("failed to send del client cmd\n");
461-
goto err_out;
495+
return ret;
462496
}
497+
rcu_read_lock();
463498
}
464499

465-
err_out:
466500
rcu_read_unlock();
467501

468-
return ret;
502+
return 0;
469503
}
470504

471505
static int ctrl_cmd_new_server(struct sockaddr_qrtr *from,
@@ -571,16 +605,34 @@ static int ctrl_cmd_new_lookup(struct sockaddr_qrtr *from,
571605
rcu_read_lock();
572606
radix_tree_for_each_slot(node_slot, &nodes, &node_iter, 0) {
573607
node = radix_tree_deref_slot(node_slot);
608+
if (!node)
609+
continue;
610+
if (radix_tree_deref_retry(node)) {
611+
node_slot = radix_tree_iter_retry(&node_iter);
612+
continue;
613+
}
614+
node_slot = radix_tree_iter_resume(node_slot, &node_iter);
574615

575616
radix_tree_for_each_slot(srv_slot, &node->servers,
576617
&srv_iter, 0) {
577618
struct qrtr_server *srv;
578619

579620
srv = radix_tree_deref_slot(srv_slot);
621+
if (!srv)
622+
continue;
623+
if (radix_tree_deref_retry(srv)) {
624+
srv_slot = radix_tree_iter_retry(&srv_iter);
625+
continue;
626+
}
627+
580628
if (!server_match(srv, &filter))
581629
continue;
582630

631+
srv_slot = radix_tree_iter_resume(srv_slot, &srv_iter);
632+
633+
rcu_read_unlock();
583634
lookup_notify(from, srv, true);
635+
rcu_read_lock();
584636
}
585637
}
586638
rcu_read_unlock();

0 commit comments

Comments
 (0)