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

Commit 92a93fd5 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'isdn-null-deref'



Karsten Keil says:

====================
Fix potential NULL pointer access and memory leak in ISDN layer2 functions

Insu Yun did brinup the issue with not checking the skb_clone() return
value in the layer2 I-frame ull functions.
This series fix the issue in a way which avoid protocol violations/data loss
on a temporary memory shortage.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 4ef7ea91 c96356a9
Loading
Loading
Loading
Loading
+8 −12
Original line number Diff line number Diff line
@@ -1247,7 +1247,7 @@ static void
l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
{
	struct PStack *st = fi->userdata;
	struct sk_buff *skb;
	struct sk_buff *skb, *nskb;
	struct Layer2 *l2 = &st->l2;
	u_char header[MAX_HEADER_LEN];
	int i, hdr_space_needed;
@@ -1262,15 +1262,11 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
		return;

	hdr_space_needed = l2headersize(l2, 0);
	if (hdr_space_needed > skb_headroom(skb)) {
		struct sk_buff *orig_skb = skb;

		skb = skb_realloc_headroom(skb, hdr_space_needed);
		if (!skb) {
			dev_kfree_skb(orig_skb);
	nskb = skb_realloc_headroom(skb, hdr_space_needed);
	if (!nskb) {
		skb_queue_head(&l2->i_queue, skb);
		return;
	}
	}
	spin_lock_irqsave(&l2->lock, flags);
	if (test_bit(FLG_MOD128, &l2->flag))
		p1 = (l2->vs - l2->va) % 128;
@@ -1282,7 +1278,7 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
		       p1);
		dev_kfree_skb(l2->windowar[p1]);
	}
	l2->windowar[p1] = skb_clone(skb, GFP_ATOMIC);
	l2->windowar[p1] = skb;

	i = sethdraddr(&st->l2, header, CMD);

@@ -1295,8 +1291,8 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
		l2->vs = (l2->vs + 1) % 8;
	}
	spin_unlock_irqrestore(&l2->lock, flags);
	memcpy(skb_push(skb, i), header, i);
	st->l2.l2l1(st, PH_PULL | INDICATION, skb);
	memcpy(skb_push(nskb, i), header, i);
	st->l2.l2l1(st, PH_PULL | INDICATION, nskb);
	test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
	if (!test_and_set_bit(FLG_T200_RUN, &st->l2.flag)) {
		FsmDelTimer(&st->l2.t203, 13);
+20 −34
Original line number Diff line number Diff line
@@ -1476,7 +1476,7 @@ static void
l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
{
	struct layer2	*l2 = fi->userdata;
	struct sk_buff	*skb, *nskb, *oskb;
	struct sk_buff	*skb, *nskb;
	u_char		header[MAX_L2HEADER_LEN];
	u_int		i, p1;

@@ -1486,11 +1486,26 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
	skb = skb_dequeue(&l2->i_queue);
	if (!skb)
		return;

	if (test_bit(FLG_MOD128, &l2->flag))
	i = sethdraddr(l2, header, CMD);
	if (test_bit(FLG_MOD128, &l2->flag)) {
		header[i++] = l2->vs << 1;
		header[i++] = l2->vr << 1;
	} else
		header[i++] = (l2->vr << 5) | (l2->vs << 1);
	nskb = skb_realloc_headroom(skb, i);
	if (!nskb) {
		printk(KERN_WARNING "%s: no headroom(%d) copy for IFrame\n",
		       mISDNDevName4ch(&l2->ch), i);
		skb_queue_head(&l2->i_queue, skb);
		return;
	}
	if (test_bit(FLG_MOD128, &l2->flag)) {
		p1 = (l2->vs - l2->va) % 128;
	else
		l2->vs = (l2->vs + 1) % 128;
	} else {
		p1 = (l2->vs - l2->va) % 8;
		l2->vs = (l2->vs + 1) % 8;
	}
	p1 = (p1 + l2->sow) % l2->window;
	if (l2->windowar[p1]) {
		printk(KERN_WARNING "%s: l2 try overwrite ack queue entry %d\n",
@@ -1498,36 +1513,7 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
		dev_kfree_skb(l2->windowar[p1]);
	}
	l2->windowar[p1] = skb;
	i = sethdraddr(l2, header, CMD);
	if (test_bit(FLG_MOD128, &l2->flag)) {
		header[i++] = l2->vs << 1;
		header[i++] = l2->vr << 1;
		l2->vs = (l2->vs + 1) % 128;
	} else {
		header[i++] = (l2->vr << 5) | (l2->vs << 1);
		l2->vs = (l2->vs + 1) % 8;
	}

	nskb = skb_clone(skb, GFP_ATOMIC);
	p1 = skb_headroom(nskb);
	if (p1 >= i)
	memcpy(skb_push(nskb, i), header, i);
	else {
		printk(KERN_WARNING
		       "%s: L2 pull_iqueue skb header(%d/%d) too short\n",
		       mISDNDevName4ch(&l2->ch), i, p1);
		oskb = nskb;
		nskb = mI_alloc_skb(oskb->len + i, GFP_ATOMIC);
		if (!nskb) {
			dev_kfree_skb(oskb);
			printk(KERN_WARNING "%s: no skb mem in %s\n",
			       mISDNDevName4ch(&l2->ch), __func__);
			return;
		}
		memcpy(skb_put(nskb, i), header, i);
		memcpy(skb_put(nskb, oskb->len), oskb->data, oskb->len);
		dev_kfree_skb(oskb);
	}
	l2down(l2, PH_DATA_REQ, l2_newid(l2), nskb);
	test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
	if (!test_and_set_bit(FLG_T200_RUN, &l2->flag)) {