summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wan/comx-proto-lapb.c4
-rw-r--r--drivers/net/wan/hdlc_x25.c7
-rw-r--r--drivers/net/wan/lapbether.c22
-rw-r--r--include/net/lapb.h2
-rw-r--r--net/lapb/lapb_in.c5
-rw-r--r--net/lapb/lapb_subr.c16
6 files changed, 45 insertions, 11 deletions
diff --git a/drivers/net/wan/comx-proto-lapb.c b/drivers/net/wan/comx-proto-lapb.c
index 30c818601ecf..f3d0fb325c53 100644
--- a/drivers/net/wan/comx-proto-lapb.c
+++ b/drivers/net/wan/comx-proto-lapb.c
@@ -372,6 +372,10 @@ static int comxlapb_data_indication(void *token, struct sk_buff *skb)
if (ch->dev->type == ARPHRD_X25) {
skb_push(skb, 1);
+
+ if (skb_cow(skb, 1))
+ return NET_RX_DROP;
+
skb->data[0] = 0; // indicate data for X25
skb->protocol = htons(ETH_P_X25);
} else {
diff --git a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c
index 3f0612c4c4be..76e7daf5c3e1 100644
--- a/drivers/net/wan/hdlc_x25.c
+++ b/drivers/net/wan/hdlc_x25.c
@@ -68,7 +68,12 @@ static int x25_data_indication(void *token, struct sk_buff *skb)
hdlc_device *hdlc = token;
unsigned char *ptr;
- ptr = skb_push(skb, 1);
+ skb_push(skb, 1);
+
+ if (skb_cow(skb, 1))
+ return NET_RX_DROP;
+
+ ptr = skb->data;
*ptr = 0;
skb->dev = hdlc_to_dev(hdlc);
diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c
index 293ce6cf9aca..271b7c64ebca 100644
--- a/drivers/net/wan/lapbether.c
+++ b/drivers/net/wan/lapbether.c
@@ -89,14 +89,15 @@ static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
int len, err;
struct lapbethdev *lapbeth;
- skb->sk = NULL; /* Initially we don't know who it's for */
+ if (!pskb_may_pull(skb, 2))
+ goto drop;
rcu_read_lock();
lapbeth = lapbeth_get_x25_dev(dev);
if (!lapbeth)
- goto drop;
+ goto drop_unlock;
if (!netif_running(lapbeth->axdev))
- goto drop;
+ goto drop_unlock;
lapbeth->stats.rx_packets++;
@@ -108,14 +109,17 @@ static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
if ((err = lapb_data_received(lapbeth, skb)) != LAPB_OK) {
printk(KERN_DEBUG "lapbether: lapb_data_received err - %d\n", err);
- goto drop;
+ goto drop_unlock;
}
out:
rcu_read_unlock();
return 0;
-drop:
+drop_unlock:
kfree_skb(skb);
goto out;
+drop:
+ kfree_skb(skb);
+ return 0;
}
static int lapbeth_data_indication(void *token, struct sk_buff *skb)
@@ -123,7 +127,12 @@ static int lapbeth_data_indication(void *token, struct sk_buff *skb)
struct lapbethdev *lapbeth = (struct lapbethdev *)token;
unsigned char *ptr;
- ptr = skb_push(skb, 1);
+ skb_push(skb, 1);
+
+ if (skb_cow(skb, 1))
+ return NET_RX_DROP;
+
+ ptr = skb->data;
*ptr = 0x00;
skb->dev = lapbeth->axdev;
@@ -426,6 +435,7 @@ static int lapbeth_device_event(struct notifier_block *this,
static struct packet_type lapbeth_packet_type = {
.type = __constant_htons(ETH_P_DEC),
.func = lapbeth_rcv,
+ .data = PKT_CAN_SHARE_SKB,
};
static struct notifier_block lapbeth_dev_notifier = {
diff --git a/include/net/lapb.h b/include/net/lapb.h
index 50292be77a71..83a241043842 100644
--- a/include/net/lapb.h
+++ b/include/net/lapb.h
@@ -129,7 +129,7 @@ extern void lapb_clear_queues(struct lapb_cb *lapb);
extern void lapb_frames_acked(struct lapb_cb *lapb, unsigned short);
extern void lapb_requeue_frames(struct lapb_cb *lapb);
extern int lapb_validate_nr(struct lapb_cb *lapb, unsigned short);
-extern void lapb_decode(struct lapb_cb *lapb, struct sk_buff *, struct lapb_frame *);
+extern int lapb_decode(struct lapb_cb *lapb, struct sk_buff *, struct lapb_frame *);
extern void lapb_send_control(struct lapb_cb *lapb, int, int, int);
extern void lapb_transmit_frmr(struct lapb_cb *lapb);
diff --git a/net/lapb/lapb_in.c b/net/lapb/lapb_in.c
index 431c6918aaf0..2275e15a9719 100644
--- a/net/lapb/lapb_in.c
+++ b/net/lapb/lapb_in.c
@@ -702,7 +702,10 @@ void lapb_data_input(struct lapb_cb *lapb, struct sk_buff *skb)
{
struct lapb_frame frame;
- lapb_decode(lapb, skb, &frame);
+ if (lapb_decode(lapb, skb, &frame) < 0) {
+ kfree_skb(skb);
+ return;
+ }
switch (lapb->state) {
case LAPB_STATE_0:
diff --git a/net/lapb/lapb_subr.c b/net/lapb/lapb_subr.c
index 36e1769330e4..e1ae5fd7302d 100644
--- a/net/lapb/lapb_subr.c
+++ b/net/lapb/lapb_subr.c
@@ -107,8 +107,8 @@ int lapb_validate_nr(struct lapb_cb *lapb, unsigned short nr)
* This routine is the centralised routine for parsing the control
* information for the different frame formats.
*/
-void lapb_decode(struct lapb_cb *lapb, struct sk_buff *skb,
- struct lapb_frame *frame)
+int lapb_decode(struct lapb_cb *lapb, struct sk_buff *skb,
+ struct lapb_frame *frame)
{
frame->type = LAPB_ILLEGAL;
@@ -118,6 +118,12 @@ void lapb_decode(struct lapb_cb *lapb, struct sk_buff *skb,
skb->data[0], skb->data[1], skb->data[2]);
#endif
+ /* We always need to look at 2 bytes, sometimes we need
+ * to look at 3 and those cases are handled below.
+ */
+ if (!pskb_may_pull(skb, 2))
+ return -1;
+
if (lapb->mode & LAPB_MLP) {
if (lapb->mode & LAPB_DCE) {
if (skb->data[0] == LAPB_ADDR_D)
@@ -148,6 +154,8 @@ void lapb_decode(struct lapb_cb *lapb, struct sk_buff *skb,
if (lapb->mode & LAPB_EXTENDED) {
if (!(skb->data[0] & LAPB_S)) {
+ if (!pskb_may_pull(skb, 2))
+ return -1;
/*
* I frame - carries NR/NS/PF
*/
@@ -159,6 +167,8 @@ void lapb_decode(struct lapb_cb *lapb, struct sk_buff *skb,
frame->control[1] = skb->data[1];
skb_pull(skb, 2);
} else if ((skb->data[0] & LAPB_U) == 1) {
+ if (!pskb_may_pull(skb, 2))
+ return -1;
/*
* S frame - take out PF/NR
*/
@@ -206,6 +216,8 @@ void lapb_decode(struct lapb_cb *lapb, struct sk_buff *skb,
skb_pull(skb, 1);
}
+
+ return 0;
}
/*