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 | ... | ... |