Commit a2805dca authored by Pavel Skripkin's avatar Pavel Skripkin Committed by David S. Miller
Browse files

net: caif: add proper error handling



caif_enroll_dev() can fail in some cases. Ingnoring
these cases can lead to memory leak due to not assigning
link_support pointer to anywhere.

Fixes: 7c18d220 ("caif: Restructure how link caif link layer enroll")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarPavel Skripkin <paskripkin@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent bce130e7
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -119,7 +119,7 @@ void caif_free_client(struct cflayer *adap_layer);
 * The link_support layer is used to add any Link Layer specific
 * framing.
 */
void caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev,
int caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev,
			struct cflayer *link_support, int head_room,
			struct cflayer **layer, int (**rcv_func)(
				struct sk_buff *, struct net_device *,
+1 −1
Original line number Diff line number Diff line
@@ -62,7 +62,7 @@ void cfcnfg_remove(struct cfcnfg *cfg);
 * @fcs:	Specify if checksum is used in CAIF Framing Layer.
 * @head_room:	Head space needed by link specific protocol.
 */
void
int
cfcnfg_add_phy_layer(struct cfcnfg *cnfg,
		     struct net_device *dev, struct cflayer *phy_layer,
		     enum cfcnfg_phy_preference pref,
+5 −3
Original line number Diff line number Diff line
@@ -308,7 +308,7 @@ static void dev_flowctrl(struct net_device *dev, int on)
	caifd_put(caifd);
}

void caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev,
int caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev,
		     struct cflayer *link_support, int head_room,
		     struct cflayer **layer,
		     int (**rcv_func)(struct sk_buff *, struct net_device *,
@@ -319,11 +319,12 @@ void caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev,
	enum cfcnfg_phy_preference pref;
	struct cfcnfg *cfg = get_cfcnfg(dev_net(dev));
	struct caif_device_entry_list *caifdevs;
	int res;

	caifdevs = caif_device_list(dev_net(dev));
	caifd = caif_device_alloc(dev);
	if (!caifd)
		return;
		return -ENOMEM;
	*layer = &caifd->layer;
	spin_lock_init(&caifd->flow_lock);

@@ -344,7 +345,7 @@ void caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev,
	strlcpy(caifd->layer.name, dev->name,
		sizeof(caifd->layer.name));
	caifd->layer.transmit = transmit;
	cfcnfg_add_phy_layer(cfg,
	res = cfcnfg_add_phy_layer(cfg,
				dev,
				&caifd->layer,
				pref,
@@ -354,6 +355,7 @@ void caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev,
	mutex_unlock(&caifdevs->lock);
	if (rcv_func)
		*rcv_func = receive;
	return res;
}
EXPORT_SYMBOL(caif_enroll_dev);

+11 −5
Original line number Diff line number Diff line
@@ -450,7 +450,7 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
	rcu_read_unlock();
}

void
int
cfcnfg_add_phy_layer(struct cfcnfg *cnfg,
		     struct net_device *dev, struct cflayer *phy_layer,
		     enum cfcnfg_phy_preference pref,
@@ -459,7 +459,7 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg,
{
	struct cflayer *frml;
	struct cfcnfg_phyinfo *phyinfo = NULL;
	int i;
	int i, res = 0;
	u8 phyid;

	mutex_lock(&cnfg->lock);
@@ -473,12 +473,15 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg,
			goto got_phyid;
	}
	pr_warn("Too many CAIF Link Layers (max 6)\n");
	res = -EEXIST;
	goto out;

got_phyid:
	phyinfo = kzalloc(sizeof(struct cfcnfg_phyinfo), GFP_ATOMIC);
	if (!phyinfo)
	if (!phyinfo) {
		res = -ENOMEM;
		goto out_err;
	}

	phy_layer->id = phyid;
	phyinfo->pref = pref;
@@ -492,8 +495,10 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg,

	frml = cffrml_create(phyid, fcs);

	if (!frml)
	if (!frml) {
		res = -ENOMEM;
		goto out_err;
	}
	phyinfo->frm_layer = frml;
	layer_set_up(frml, cnfg->mux);

@@ -511,11 +516,12 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg,
	list_add_rcu(&phyinfo->node, &cnfg->phys);
out:
	mutex_unlock(&cnfg->lock);
	return;
	return res;

out_err:
	kfree(phyinfo);
	mutex_unlock(&cnfg->lock);
	return res;
}
EXPORT_SYMBOL(cfcnfg_add_phy_layer);