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

Commit 5895a280 authored by Subash Abhinov Kasiviswanathan's avatar Subash Abhinov Kasiviswanathan
Browse files

soc: qcom: qmi: Fix possible use after free



Packets in transmit path maybe freed before checking for the
content for bearer level flow control limit.
Fix this by checking this before the transmit.

CRs-Fixed: 2259239
Change-Id: If50af5a2e6c6bb3bfddfe583c422c7f648783aea
Signed-off-by: default avatarSubash Abhinov Kasiviswanathan <subashab@codeaurora.org>
parent 9522112f
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -62,8 +62,8 @@ static netdev_tx_t rmnet_vnd_start_xmit(struct sk_buff *skb,

	priv = netdev_priv(dev);
	if (priv->real_dev) {
		rmnet_egress_handler(skb);
		qmi_rmnet_burst_fc_check(dev, skb);
		rmnet_egress_handler(skb);
	} else {
		this_cpu_inc(priv->pcpu_stats->stats.tx_drops);
		kfree_skb(skb);
+2 −38
Original line number Diff line number Diff line
@@ -28,15 +28,6 @@
#define NO_CHANGE 1
#define UPDATED 2

struct dfc_work {
	struct work_struct work;
	struct net_device *dev;
	u8 bearer_id;
	u8  ack_req;
	u16 seq;
	u8 mux_id;
};

struct dfc_qmi_data {
	void *rmnet_port;
	struct workqueue_struct *dfc_wq;
@@ -63,7 +54,6 @@ static void dfc_ind_reg_dereg(struct work_struct *work);

static void dfc_svc_init(struct work_struct *work);
static void dfc_do_burst_flow_control(struct work_struct *work);
static void dfc_disable_flow(struct work_struct *work);

/* **************************************************** */
#define DFC_SERVICE_ID_V01 0x4E
@@ -546,9 +536,7 @@ static int dfc_disable_bearer_flows(struct net_device *dev, u8 bearer_id)
			return 0;

		if (itm->bearer_id == bearer_id) {
			rtnl_lock();
			tc_qdisc_flow_control(dev, itm->tcm_handle, 0);
			rtnl_unlock();
			rc++;
		}
	}
@@ -595,15 +583,6 @@ static int dfc_do_fc(struct net_device *dev, u32 flow_id,
	return len;
}

static void dfc_disable_flow(struct work_struct *work)
{
	struct dfc_work *data = (struct dfc_work *)work;
	int rc = dfc_disable_bearer_flows(data->dev, data->bearer_id);

	pr_debug("%s() %d flows disabled\n", __func__, rc);
	kfree(data);
}

static void dfc_do_flow_controls(struct net_device *dev,
				 struct dfc_flow_status_info_type_v01 *flow)
{
@@ -865,11 +844,10 @@ void dfc_qmi_burst_check(struct net_device *dev, struct qos_info *qos,
			 struct sk_buff *skb)
{
	struct rmnet_bearer_map *bearer;
	struct dfc_work *svc_check;
	struct rmnet_flow_map *itm;
	int ip_type;

	if (!qos || !skb)
	if (!qos)
		return;

	if (!rtnl_trylock())
@@ -888,22 +866,8 @@ void dfc_qmi_burst_check(struct net_device *dev, struct qos_info *qos,
		if (bearer->counter >= bearer->grant_size) {
			bearer->counter = 0;

			svc_check = kmalloc(sizeof(struct dfc_work),
					    GFP_ATOMIC);
			if (!svc_check) {
				rtnl_unlock();
				return;
			}

			INIT_WORK((struct work_struct *)svc_check,
				  dfc_disable_flow);
			svc_check->dev = dev;
			svc_check->bearer_id = bearer->bearer_id;
			svc_check->ack_req = bearer->ack_req;
			svc_check->seq = bearer->seq;
			svc_check->mux_id = qos->mux_id;
			dfc_disable_bearer_flows(dev, bearer->bearer_id);
			rtnl_unlock();
			schedule_work((struct work_struct *)svc_check);
		} else {
			rtnl_unlock();
		}