| Summary: | qemu-kvm: Infinite loop in gem_receive() | ||||||
|---|---|---|---|---|---|---|---|
| Product: | [Other] Security Response | Reporter: | Adam Mariš <amaris> | ||||
| Component: | vulnerability | Assignee: | Red Hat Product Security <security-response-team> | ||||
| Status: | CLOSED NOTABUG | QA Contact: | |||||
| Severity: | medium | Docs Contact: | |||||
| Priority: | medium | ||||||
| Version: | unspecified | CC: | abaron, ailan, alonbl, aortega, apevec, areis, ayoung, bmcclain, chrisw, dallan, dblechte, drjones, eedri, gklein, gkotton, imammedo, jen, jschluet, knoel, lhh, lpeer, markmc, mgoldboi, michal.skrivanek, mkenneth, mrezanin, mst, pbonzini, ppandit, rbalakri, rbryant, rkrcmar, sclewis, security-response-team, sherold, srevivo, tdecacqu, vkuznets, ykaul, ylavi | ||||
| Target Milestone: | --- | Keywords: | Security | ||||
| Target Release: | --- | ||||||
| Hardware: | All | ||||||
| OS: | Linux | ||||||
| Whiteboard: | |||||||
| Fixed In Version: | Doc Type: | Bug Fix | |||||
| Doc Text: | Story Points: | --- | |||||
| Clone Of: | Environment: | ||||||
| Last Closed: | 2016-09-21 06:17:45 UTC | Type: | --- | ||||
| Regression: | --- | Mount Type: | --- | ||||
| Documentation: | --- | CRM: | |||||
| Verified Versions: | Category: | --- | |||||
| oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |||||
| Cloudforms Team: | --- | Target Upstream Version: | |||||
| Bug Depends On: | |||||||
| Bug Blocks: | 1326713 | ||||||
| Attachments: |
|
||||||
Acknowledgments: Name: Li Qiang (Qihoo 360 Inc.) Created attachment 1146825 [details]
Crash report
Upstream fix: ------------- -> git.qemu.org/?p=qemu.git;a=commit;h=f265ae8c79ce8c194de481e9def1daa3a80dbb96 |
An infinite loop vulnerability was found in gem_receive(). Vulnerable code: static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) { ... rxbufsize = ((s->regs[GEM_DMACFG] & GEM_DMACFG_RBUFSZ_M) >> // here set the rxbufsize=0 GEM_DMACFG_RBUFSZ_S) * GEM_DMACFG_RBUFSZ_MUL; bytes_to_copy = size; ... DB_PRINT("config bufsize: %d packet size: %ld\n", rxbufsize, size); while (bytes_to_copy) { // the bytes_to_copy never be changed /* Do nothing if receive is not enabled. */ if (!gem_can_receive(nc)) { assert(!first_desc); return -1; } DB_PRINT("copy %d bytes to 0x%x\n", MIN(bytes_to_copy, rxbufsize), rx_desc_get_buffer(s->rx_desc)); /* Copy packet data to emulated DMA buffer */ cpu_physical_memory_write(rx_desc_get_buffer(s->rx_desc) + rxbuf_offset, rxbuf_ptr, MIN(bytes_to_copy, rxbufsize)); rxbuf_ptr += MIN(bytes_to_copy, rxbufsize); bytes_to_copy -= MIN(bytes_to_copy, rxbufsize); // the bytes_to_copy never change ... /* Descriptor write-back. */ cpu_physical_memory_write(s->rx_desc_addr, (uint8_t *)s->rx_desc, sizeof(s->rx_desc)); /* Next descriptor */ if (rx_desc_get_wrap(s->rx_desc)) { DB_PRINT("wrapping RX descriptor list\n"); s->rx_desc_addr = s->regs[GEM_RXQBASE]; } else { DB_PRINT("incrementing RX descriptor list\n"); s->rx_desc_addr += 8; // provide a lot of rx_desc_addr so let this run correctly } gem_get_rx_desc(s); } ... return size; } By setting rxbufsize to 0 (via setting s->regs[GEM_DMACFG]=0), the while condition bytes_to_copy will never change. Although gem_can_receive() has got check for s->rx_desc, by raising s->rx_desc_addr the statement will be executed everytime, causing an infinite loop.