aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhayeswang <hayeswang@realtek.com>2013-11-20 04:30:54 -0500
committerDavid S. Miller <davem@davemloft.net>2013-11-20 15:09:41 -0500
commit7937f9e5141c9d4864d399d91325605a35cd5831 (patch)
treebfae2019d68b7a3bf74a1a3acf8e532728f21364
parentb4789b8e6be3151a955ade74872822f30e8cd914 (diff)
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: Hayes Wang <hayeswang@realtek.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/usb/r8152.c30
1 files changed, 17 insertions, 13 deletions
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index f3fce412c0c1..428600d5c056 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -24,7 +24,7 @@
24#include <linux/ipv6.h> 24#include <linux/ipv6.h>
25 25
26/* Version Information */ 26/* Version Information */
27#define DRIVER_VERSION "v1.01.0 (2013/08/12)" 27#define DRIVER_VERSION "v1.02.0 (2013/10/28)"
28#define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>" 28#define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
29#define DRIVER_DESC "Realtek RTL8152 Based USB 2.0 Ethernet Adapters" 29#define DRIVER_DESC "Realtek RTL8152 Based USB 2.0 Ethernet Adapters"
30#define MODULENAME "r8152" 30#define MODULENAME "r8152"
@@ -1136,14 +1136,14 @@ r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, struct sk_buff *skb)
1136 1136
1137static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) 1137static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
1138{ 1138{
1139 u32 remain; 1139 int remain;
1140 u8 *tx_data; 1140 u8 *tx_data;
1141 1141
1142 tx_data = agg->head; 1142 tx_data = agg->head;
1143 agg->skb_num = agg->skb_len = 0; 1143 agg->skb_num = agg->skb_len = 0;
1144 remain = rx_buf_sz - sizeof(struct tx_desc); 1144 remain = rx_buf_sz;
1145 1145
1146 while (remain >= ETH_ZLEN) { 1146 while (remain >= ETH_ZLEN + sizeof(struct tx_desc)) {
1147 struct tx_desc *tx_desc; 1147 struct tx_desc *tx_desc;
1148 struct sk_buff *skb; 1148 struct sk_buff *skb;
1149 unsigned int len; 1149 unsigned int len;
@@ -1152,12 +1152,14 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
1152 if (!skb) 1152 if (!skb)
1153 break; 1153 break;
1154 1154
1155 remain -= sizeof(*tx_desc);
1155 len = skb->len; 1156 len = skb->len;
1156 if (remain < len) { 1157 if (remain < len) {
1157 skb_queue_head(&tp->tx_queue, skb); 1158 skb_queue_head(&tp->tx_queue, skb);
1158 break; 1159 break;
1159 } 1160 }
1160 1161
1162 tx_data = tx_agg_align(tx_data);
1161 tx_desc = (struct tx_desc *)tx_data; 1163 tx_desc = (struct tx_desc *)tx_data;
1162 tx_data += sizeof(*tx_desc); 1164 tx_data += sizeof(*tx_desc);
1163 1165
@@ -1167,9 +1169,8 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
1167 agg->skb_len += len; 1169 agg->skb_len += len;
1168 dev_kfree_skb_any(skb); 1170 dev_kfree_skb_any(skb);
1169 1171
1170 tx_data = tx_agg_align(tx_data + len); 1172 tx_data += len;
1171 remain = rx_buf_sz - sizeof(*tx_desc) - 1173 remain = rx_buf_sz - (int)(tx_agg_align(tx_data) - agg->head);
1172 (u32)((void *)tx_data - agg->head);
1173 } 1174 }
1174 1175
1175 usb_fill_bulk_urb(agg->urb, tp->udev, usb_sndbulkpipe(tp->udev, 2), 1176 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 list_for_each_safe(cursor, next, &tp->rx_done) { 1189 list_for_each_safe(cursor, next, &tp->rx_done) {
1189 struct rx_desc *rx_desc; 1190 struct rx_desc *rx_desc;
1190 struct rx_agg *agg; 1191 struct rx_agg *agg;
1191 unsigned pkt_len;
1192 int len_used = 0; 1192 int len_used = 0;
1193 struct urb *urb; 1193 struct urb *urb;
1194 u8 *rx_data; 1194 u8 *rx_data;
@@ -1204,17 +1204,22 @@ static void rx_bottom(struct r8152 *tp)
1204 1204
1205 rx_desc = agg->head; 1205 rx_desc = agg->head;
1206 rx_data = agg->head; 1206 rx_data = agg->head;
1207 pkt_len = le32_to_cpu(rx_desc->opts1) & RX_LEN_MASK; 1207 len_used += sizeof(struct rx_desc);
1208 len_used += sizeof(struct rx_desc) + pkt_len;
1209 1208
1210 while (urb->actual_length >= len_used) { 1209 while (urb->actual_length > len_used) {
1211 struct net_device *netdev = tp->netdev; 1210 struct net_device *netdev = tp->netdev;
1212 struct net_device_stats *stats; 1211 struct net_device_stats *stats;
1212 unsigned int pkt_len;
1213 struct sk_buff *skb; 1213 struct sk_buff *skb;
1214 1214
1215 pkt_len = le32_to_cpu(rx_desc->opts1) & RX_LEN_MASK;
1215 if (pkt_len < ETH_ZLEN) 1216 if (pkt_len < ETH_ZLEN)
1216 break; 1217 break;
1217 1218
1219 len_used += pkt_len;
1220 if (urb->actual_length < len_used)
1221 break;
1222
1218 stats = rtl8152_get_stats(netdev); 1223 stats = rtl8152_get_stats(netdev);
1219 1224
1220 pkt_len -= 4; /* CRC */ 1225 pkt_len -= 4; /* CRC */
@@ -1234,9 +1239,8 @@ static void rx_bottom(struct r8152 *tp)
1234 1239
1235 rx_data = rx_agg_align(rx_data + pkt_len + 4); 1240 rx_data = rx_agg_align(rx_data + pkt_len + 4);
1236 rx_desc = (struct rx_desc *)rx_data; 1241 rx_desc = (struct rx_desc *)rx_data;
1237 pkt_len = le32_to_cpu(rx_desc->opts1) & RX_LEN_MASK;
1238 len_used = (int)(rx_data - (u8 *)agg->head); 1242 len_used = (int)(rx_data - (u8 *)agg->head);
1239 len_used += sizeof(struct rx_desc) + pkt_len; 1243 len_used += sizeof(struct rx_desc);
1240 } 1244 }
1241 1245
1242submit: 1246submit: