Commit 7937f9e5 authored by hayeswang's avatar hayeswang Committed by David S. Miller

r8152: fix tx/rx memory overflow

The tx/rx would access the memory which is out of the desired range.
Modify the method of checking the end of the memory to avoid it.

For r8152_tx_agg_fill(), the variable remain may become negative.
However, the declaration is unsigned, so the while loop wouldn't
break when reaching the end of the desied memory. Although to change
the declaration from unsigned to signed is enough to fix it, I also
modify the checking method for safe. Replace

		remain = rx_buf_sz - sizeof(*tx_desc) -
			 (u32)((void *)tx_data - agg->head);

with

		remain = rx_buf_sz - (int)(tx_agg_align(tx_data) - agg->head);

to make sure the variable remain is always positive. Then, the
overflow wouldn't happen.

For rx_bottom(), the rx_desc should not be used to calculate the
packet length before making sure the rx_desc is in the desired range.
Change the checking to two parts. First, check the descriptor is in
the memory. The other, using the descriptor to find out the packet
length and check if the packet is in the memory.
Signed-off-by: default avatarHayes Wang <hayeswang@realtek.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b4789b8e
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#include <linux/ipv6.h> #include <linux/ipv6.h>
/* Version Information */ /* Version Information */
#define DRIVER_VERSION "v1.01.0 (2013/08/12)" #define DRIVER_VERSION "v1.02.0 (2013/10/28)"
#define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>" #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
#define DRIVER_DESC "Realtek RTL8152 Based USB 2.0 Ethernet Adapters" #define DRIVER_DESC "Realtek RTL8152 Based USB 2.0 Ethernet Adapters"
#define MODULENAME "r8152" #define MODULENAME "r8152"
...@@ -1136,14 +1136,14 @@ r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, struct sk_buff *skb) ...@@ -1136,14 +1136,14 @@ r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, struct sk_buff *skb)
static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
{ {
u32 remain; int remain;
u8 *tx_data; u8 *tx_data;
tx_data = agg->head; tx_data = agg->head;
agg->skb_num = agg->skb_len = 0; agg->skb_num = agg->skb_len = 0;
remain = rx_buf_sz - sizeof(struct tx_desc); remain = rx_buf_sz;
while (remain >= ETH_ZLEN) { while (remain >= ETH_ZLEN + sizeof(struct tx_desc)) {
struct tx_desc *tx_desc; struct tx_desc *tx_desc;
struct sk_buff *skb; struct sk_buff *skb;
unsigned int len; unsigned int len;
...@@ -1152,12 +1152,14 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) ...@@ -1152,12 +1152,14 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
if (!skb) if (!skb)
break; break;
remain -= sizeof(*tx_desc);
len = skb->len; len = skb->len;
if (remain < len) { if (remain < len) {
skb_queue_head(&tp->tx_queue, skb); skb_queue_head(&tp->tx_queue, skb);
break; break;
} }
tx_data = tx_agg_align(tx_data);
tx_desc = (struct tx_desc *)tx_data; tx_desc = (struct tx_desc *)tx_data;
tx_data += sizeof(*tx_desc); tx_data += sizeof(*tx_desc);
...@@ -1167,9 +1169,8 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) ...@@ -1167,9 +1169,8 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
agg->skb_len += len; agg->skb_len += len;
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
tx_data = tx_agg_align(tx_data + len); tx_data += len;
remain = rx_buf_sz - sizeof(*tx_desc) - remain = rx_buf_sz - (int)(tx_agg_align(tx_data) - agg->head);
(u32)((void *)tx_data - agg->head);
} }
usb_fill_bulk_urb(agg->urb, tp->udev, usb_sndbulkpipe(tp->udev, 2), usb_fill_bulk_urb(agg->urb, tp->udev, usb_sndbulkpipe(tp->udev, 2),
...@@ -1188,7 +1189,6 @@ static void rx_bottom(struct r8152 *tp) ...@@ -1188,7 +1189,6 @@ static void rx_bottom(struct r8152 *tp)
list_for_each_safe(cursor, next, &tp->rx_done) { list_for_each_safe(cursor, next, &tp->rx_done) {
struct rx_desc *rx_desc; struct rx_desc *rx_desc;
struct rx_agg *agg; struct rx_agg *agg;
unsigned pkt_len;
int len_used = 0; int len_used = 0;
struct urb *urb; struct urb *urb;
u8 *rx_data; u8 *rx_data;
...@@ -1204,17 +1204,22 @@ static void rx_bottom(struct r8152 *tp) ...@@ -1204,17 +1204,22 @@ static void rx_bottom(struct r8152 *tp)
rx_desc = agg->head; rx_desc = agg->head;
rx_data = agg->head; rx_data = agg->head;
pkt_len = le32_to_cpu(rx_desc->opts1) & RX_LEN_MASK; len_used += sizeof(struct rx_desc);
len_used += sizeof(struct rx_desc) + pkt_len;
while (urb->actual_length >= len_used) { while (urb->actual_length > len_used) {
struct net_device *netdev = tp->netdev; struct net_device *netdev = tp->netdev;
struct net_device_stats *stats; struct net_device_stats *stats;
unsigned int pkt_len;
struct sk_buff *skb; struct sk_buff *skb;
pkt_len = le32_to_cpu(rx_desc->opts1) & RX_LEN_MASK;
if (pkt_len < ETH_ZLEN) if (pkt_len < ETH_ZLEN)
break; break;
len_used += pkt_len;
if (urb->actual_length < len_used)
break;
stats = rtl8152_get_stats(netdev); stats = rtl8152_get_stats(netdev);
pkt_len -= 4; /* CRC */ pkt_len -= 4; /* CRC */
...@@ -1234,9 +1239,8 @@ static void rx_bottom(struct r8152 *tp) ...@@ -1234,9 +1239,8 @@ static void rx_bottom(struct r8152 *tp)
rx_data = rx_agg_align(rx_data + pkt_len + 4); rx_data = rx_agg_align(rx_data + pkt_len + 4);
rx_desc = (struct rx_desc *)rx_data; rx_desc = (struct rx_desc *)rx_data;
pkt_len = le32_to_cpu(rx_desc->opts1) & RX_LEN_MASK;
len_used = (int)(rx_data - (u8 *)agg->head); len_used = (int)(rx_data - (u8 *)agg->head);
len_used += sizeof(struct rx_desc) + pkt_len; len_used += sizeof(struct rx_desc);
} }
submit: submit:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment