Commit d861b05ea30e6ac177de9b679da96194ebe21afc
1 parent
191abaa2
Avoid buffer overflow when sending slirp packets.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1744 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
5 changed files
with
68 additions
and
20 deletions
hw/lance.c
... | ... | @@ -283,6 +283,11 @@ static CPUWriteMemoryFunc *lance_mem_write[3] = { |
283 | 283 | |
284 | 284 | #define MIN_BUF_SIZE 60 |
285 | 285 | |
286 | +static void lance_can_receive(void *opaque) | |
287 | +{ | |
288 | + return 1; | |
289 | +} | |
290 | + | |
286 | 291 | static void lance_receive(void *opaque, const uint8_t *buf, int size) |
287 | 292 | { |
288 | 293 | LANCEState *s = opaque; |
... | ... | @@ -440,7 +445,7 @@ void lance_init(NICInfo *nd, int irq, uint32_t leaddr, uint32_t ledaddr) |
440 | 445 | |
441 | 446 | lance_reset(s); |
442 | 447 | |
443 | - s->vc = qemu_new_vlan_client(nd->vlan, lance_receive, s); | |
448 | + s->vc = qemu_new_vlan_client(nd->vlan, lance_receive, lance_can_receive, s); | |
444 | 449 | |
445 | 450 | snprintf(s->vc->info_str, sizeof(s->vc->info_str), |
446 | 451 | "lance macaddr=%02x:%02x:%02x:%02x:%02x:%02x", | ... | ... |
hw/ne2000.c
... | ... | @@ -200,14 +200,10 @@ static int compute_mcast_idx(const uint8_t *ep) |
200 | 200 | return (crc >> 26); |
201 | 201 | } |
202 | 202 | |
203 | -/* return the max buffer size if the NE2000 can receive more data */ | |
204 | -static int ne2000_can_receive(void *opaque) | |
203 | +static int ne2000_buffer_full(NE2000State *s) | |
205 | 204 | { |
206 | - NE2000State *s = opaque; | |
207 | 205 | int avail, index, boundary; |
208 | - | |
209 | - if (s->cmd & E8390_STOP) | |
210 | - return 0; | |
206 | + | |
211 | 207 | index = s->curpag << 8; |
212 | 208 | boundary = s->boundary << 8; |
213 | 209 | if (index < boundary) |
... | ... | @@ -215,8 +211,17 @@ static int ne2000_can_receive(void *opaque) |
215 | 211 | else |
216 | 212 | avail = (s->stop - s->start) - (index - boundary); |
217 | 213 | if (avail < (MAX_ETH_FRAME_SIZE + 4)) |
218 | - return 0; | |
219 | - return MAX_ETH_FRAME_SIZE; | |
214 | + return 1; | |
215 | + return 0; | |
216 | +} | |
217 | + | |
218 | +static int ne2000_can_receive(void *opaque) | |
219 | +{ | |
220 | + NE2000State *s = opaque; | |
221 | + | |
222 | + if (s->cmd & E8390_STOP) | |
223 | + return 1; | |
224 | + return !ne2000_buffer_full(s); | |
220 | 225 | } |
221 | 226 | |
222 | 227 | #define MIN_BUF_SIZE 60 |
... | ... | @@ -234,7 +239,7 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size) |
234 | 239 | printf("NE2000: received len=%d\n", size); |
235 | 240 | #endif |
236 | 241 | |
237 | - if (!ne2000_can_receive(s)) | |
242 | + if (s->cmd & E8390_STOP || ne2000_buffer_full(s)) | |
238 | 243 | return; |
239 | 244 | |
240 | 245 | /* XXX: check this */ |
... | ... | @@ -722,7 +727,8 @@ void isa_ne2000_init(int base, int irq, NICInfo *nd) |
722 | 727 | |
723 | 728 | ne2000_reset(s); |
724 | 729 | |
725 | - s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive, s); | |
730 | + s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive, | |
731 | + ne2000_can_receive, s); | |
726 | 732 | |
727 | 733 | snprintf(s->vc->info_str, sizeof(s->vc->info_str), |
728 | 734 | "ne2000 macaddr=%02x:%02x:%02x:%02x:%02x:%02x", |
... | ... | @@ -791,7 +797,8 @@ void pci_ne2000_init(PCIBus *bus, NICInfo *nd) |
791 | 797 | s->pci_dev = (PCIDevice *)d; |
792 | 798 | memcpy(s->macaddr, nd->macaddr, 6); |
793 | 799 | ne2000_reset(s); |
794 | - s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive, s); | |
800 | + s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive, | |
801 | + ne2000_can_receive, s); | |
795 | 802 | |
796 | 803 | snprintf(s->vc->info_str, sizeof(s->vc->info_str), |
797 | 804 | "ne2000 pci macaddr=%02x:%02x:%02x:%02x:%02x:%02x", | ... | ... |
hw/smc91c111.c
... | ... | @@ -593,6 +593,17 @@ static uint32_t smc91c111_readl(void *opaque, target_phys_addr_t offset) |
593 | 593 | return val; |
594 | 594 | } |
595 | 595 | |
596 | +static int smc91c111_can_receive(void *opaque) | |
597 | +{ | |
598 | + smc91c111_state *s = (smc91c111_state *)opaque; | |
599 | + | |
600 | + if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST)) | |
601 | + return 1; | |
602 | + if (s->allocated == (1 << NUM_PACKETS) - 1) | |
603 | + return 0; | |
604 | + return 1; | |
605 | +} | |
606 | + | |
596 | 607 | static void smc91c111_receive(void *opaque, const uint8_t *buf, int size) |
597 | 608 | { |
598 | 609 | smc91c111_state *s = (smc91c111_state *)opaque; |
... | ... | @@ -697,6 +708,7 @@ void smc91c111_init(NICInfo *nd, uint32_t base, void *pic, int irq) |
697 | 708 | |
698 | 709 | smc91c111_reset(s); |
699 | 710 | |
700 | - s->vc = qemu_new_vlan_client(nd->vlan, smc91c111_receive, s); | |
711 | + s->vc = qemu_new_vlan_client(nd->vlan, smc91c111_receive, | |
712 | + smc91c111_can_receive, s); | |
701 | 713 | /* ??? Save/restore. */ |
702 | 714 | } | ... | ... |
vl.c
... | ... | @@ -1842,13 +1842,16 @@ VLANState *qemu_find_vlan(int id) |
1842 | 1842 | } |
1843 | 1843 | |
1844 | 1844 | VLANClientState *qemu_new_vlan_client(VLANState *vlan, |
1845 | - IOReadHandler *fd_read, void *opaque) | |
1845 | + IOReadHandler *fd_read, | |
1846 | + IOCanRWHandler *fd_can_read, | |
1847 | + void *opaque) | |
1846 | 1848 | { |
1847 | 1849 | VLANClientState *vc, **pvc; |
1848 | 1850 | vc = qemu_mallocz(sizeof(VLANClientState)); |
1849 | 1851 | if (!vc) |
1850 | 1852 | return NULL; |
1851 | 1853 | vc->fd_read = fd_read; |
1854 | + vc->fd_can_read = fd_can_read; | |
1852 | 1855 | vc->opaque = opaque; |
1853 | 1856 | vc->vlan = vlan; |
1854 | 1857 | |
... | ... | @@ -1860,6 +1863,20 @@ VLANClientState *qemu_new_vlan_client(VLANState *vlan, |
1860 | 1863 | return vc; |
1861 | 1864 | } |
1862 | 1865 | |
1866 | +int qemu_can_send_packet(VLANClientState *vc1) | |
1867 | +{ | |
1868 | + VLANState *vlan = vc1->vlan; | |
1869 | + VLANClientState *vc; | |
1870 | + | |
1871 | + for(vc = vlan->first_client; vc != NULL; vc = vc->next) { | |
1872 | + if (vc != vc1) { | |
1873 | + if (vc->fd_can_read && !vc->fd_can_read(vc->opaque)) | |
1874 | + return 0; | |
1875 | + } | |
1876 | + } | |
1877 | + return 1; | |
1878 | +} | |
1879 | + | |
1863 | 1880 | void qemu_send_packet(VLANClientState *vc1, const uint8_t *buf, int size) |
1864 | 1881 | { |
1865 | 1882 | VLANState *vlan = vc1->vlan; |
... | ... | @@ -1885,7 +1902,7 @@ static VLANClientState *slirp_vc; |
1885 | 1902 | |
1886 | 1903 | int slirp_can_output(void) |
1887 | 1904 | { |
1888 | - return 1; | |
1905 | + return qemu_can_send_packet(slirp_vc); | |
1889 | 1906 | } |
1890 | 1907 | |
1891 | 1908 | void slirp_output(const uint8_t *pkt, int pkt_len) |
... | ... | @@ -1913,7 +1930,7 @@ static int net_slirp_init(VLANState *vlan) |
1913 | 1930 | slirp_init(); |
1914 | 1931 | } |
1915 | 1932 | slirp_vc = qemu_new_vlan_client(vlan, |
1916 | - slirp_receive, NULL); | |
1933 | + slirp_receive, NULL, NULL); | |
1917 | 1934 | snprintf(slirp_vc->info_str, sizeof(slirp_vc->info_str), "user redirector"); |
1918 | 1935 | return 0; |
1919 | 1936 | } |
... | ... | @@ -2098,7 +2115,7 @@ static TAPState *net_tap_fd_init(VLANState *vlan, int fd) |
2098 | 2115 | if (!s) |
2099 | 2116 | return NULL; |
2100 | 2117 | s->fd = fd; |
2101 | - s->vc = qemu_new_vlan_client(vlan, tap_receive, s); | |
2118 | + s->vc = qemu_new_vlan_client(vlan, tap_receive, NULL, s); | |
2102 | 2119 | qemu_set_fd_handler(s->fd, tap_send, NULL, s); |
2103 | 2120 | snprintf(s->vc->info_str, sizeof(s->vc->info_str), "tap: fd=%d", fd); |
2104 | 2121 | return s; |
... | ... | @@ -2412,7 +2429,7 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, int fd, |
2412 | 2429 | return NULL; |
2413 | 2430 | s->fd = fd; |
2414 | 2431 | |
2415 | - s->vc = qemu_new_vlan_client(vlan, net_socket_receive_dgram, s); | |
2432 | + s->vc = qemu_new_vlan_client(vlan, net_socket_receive_dgram, NULL, s); | |
2416 | 2433 | qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s); |
2417 | 2434 | |
2418 | 2435 | /* mcast: save bound address as dst */ |
... | ... | @@ -2440,7 +2457,7 @@ static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, int fd, |
2440 | 2457 | return NULL; |
2441 | 2458 | s->fd = fd; |
2442 | 2459 | s->vc = qemu_new_vlan_client(vlan, |
2443 | - net_socket_receive, s); | |
2460 | + net_socket_receive, NULL, s); | |
2444 | 2461 | snprintf(s->vc->info_str, sizeof(s->vc->info_str), |
2445 | 2462 | "socket: fd=%d", fd); |
2446 | 2463 | if (is_connected) { | ... | ... |
vl.h
... | ... | @@ -279,6 +279,9 @@ typedef struct VLANClientState VLANClientState; |
279 | 279 | |
280 | 280 | struct VLANClientState { |
281 | 281 | IOReadHandler *fd_read; |
282 | + /* Packets may still be sent if this returns zero. It's used to | |
283 | + rate-limit the slirp code. */ | |
284 | + IOCanRWHandler *fd_can_read; | |
282 | 285 | void *opaque; |
283 | 286 | struct VLANClientState *next; |
284 | 287 | struct VLANState *vlan; |
... | ... | @@ -293,8 +296,12 @@ typedef struct VLANState { |
293 | 296 | |
294 | 297 | VLANState *qemu_find_vlan(int id); |
295 | 298 | VLANClientState *qemu_new_vlan_client(VLANState *vlan, |
296 | - IOReadHandler *fd_read, void *opaque); | |
299 | + IOReadHandler *fd_read, | |
300 | + IOCanRWHandler *fd_can_read, | |
301 | + void *opaque); | |
302 | +int qemu_can_send_packet(VLANClientState *vc); | |
297 | 303 | void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size); |
304 | +void qemu_handler_true(void *opaque); | |
298 | 305 | |
299 | 306 | void do_info_network(void); |
300 | 307 | ... | ... |