Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c72e4b0e authored by Weiyi Chen's avatar Weiyi Chen Committed by Gerrit - the friendly Code Review server
Browse files

rmnet_core: fix race condition in rmnet_get_packets



In rmnet powersave work, rmnet_get_packets() could access NULL dev pointer
if rmnet_dellink() is nullifying the dev pointer at the same time.

18377 [   72.651710][ T1527] Unable to handle kernel NULL pointer dereference
at virtual address 00000000000009d0

18424 [   72.653999][ T1527] Call trace:
18425 [   72.654085][ T1527]  rmnet_get_packets+0xc4/0x11c [rmnet_core]
18426 [   72.654170][ T1527]  qmi_rmnet_check_stats_2+0x80/0x410 [rmnet_core]
18427 [   72.654180][ T1527]  process_one_work+0x260/0x804

This change Uses the rcu variant of the hlist traversal function in
rmnet_get_packet for safe concurrency with the hlist del primitives.
It also checks dev pointer before accessing the dev private structure.
The existing synchronize rcu call in rmnet_dellink ensures that the ep
and dev structure are not freed while being referenced in rcu read
session of rmnet_get_packets.

Change-Id: Ib5f5aff6e76f9fffd9110a2aa924ad6ab090991f
Signed-off-by: default avatarWeiyi Chen <quic_weiyic@quicinc.com>
parent 21e13df8
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
/* Copyright (c) 2013-2021, The Linux Foundation. All rights reserved.
 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -641,6 +642,7 @@ EXPORT_SYMBOL(rmnet_init_qmi_pt);

void rmnet_get_packets(void *port, u64 *rx, u64 *tx)
{
	struct net_device *dev;
	struct rmnet_priv *priv;
	struct rmnet_pcpu_stats *ps;
	unsigned int cpu, start;
@@ -654,8 +656,12 @@ void rmnet_get_packets(void *port, u64 *rx, u64 *tx)
	*tx = 0;
	*rx = 0;
	rcu_read_lock();
	hash_for_each(((struct rmnet_port *)port)->muxed_ep, bkt, ep, hlnode) {
		priv = netdev_priv(ep->egress_dev);
	hash_for_each_rcu(((struct rmnet_port *)port)->muxed_ep, bkt, ep,
			  hlnode) {
		dev = ep->egress_dev;
		if (!dev)
			continue;
		priv = netdev_priv(dev);
		for_each_possible_cpu(cpu) {
			ps = per_cpu_ptr(priv->pcpu_stats, cpu);
			do {