Disclosure
| Date | Detail |
|---|---|
05/21/2018 |
reported to Samsung |
07/27/2018 |
vulnerabilities confirmed and assigned SVE-2018-11784, rated Low |
07/29/2018 |
assigned CVE-2018-14745 |
---------- |
Awaiting publication of CVE description |
Affected Product
Samsung Galaxy S6 (SM-G920F), Firmware Version G920FXXU5EQH7
Vulnerabilities
A potential buffer overflow in driver/net/wireless/bcmdhd4538/dhd_msgbuf.c:4212.
4194 /* Assumes only one index is updated ata time */
4195 static void *BCMFASTPATH
4196 prot_get_ring_space(msgbuf_ring_t *ring, uint16 nitems, uint16 * alloced)
4197 {
4198 void *ret_ptr = NULL;
4199 uint16 ring_avail_cnt;
4200
4201 ASSERT(nitems <= RING_MAX_ITEM(ring));
4202
4203 ring_avail_cnt = CHECK_WRITE_SPACE(RING_READ_PTR(ring), RING_WRITE_PTR(ring),
4204 RING_MAX_ITEM(ring));
4205
4206 if (ring_avail_cnt == 0) {
4207 return NULL;
4208 }
4209 *alloced = MIN(nitems, ring_avail_cnt);
4210
4211 /* Return next available space */
4212 ret_ptr = (char*)HOST_RING_BASE(ring) + (RING_WRITE_PTR(ring) * RING_LEN_ITEMS(ring));
4213
4214 /* Update write pointer */
4215 if ((RING_WRITE_PTR(ring) + *alloced) == RING_MAX_ITEM(ring))
4216 RING_WRITE_PTR(ring) = 0;
4217 else if ((RING_WRITE_PTR(ring) + *alloced) < RING_MAX_ITEM(ring))
4218 RING_WRITE_PTR(ring) += *alloced;
4219 else {
4220 /* Should never hit this */
4221 ASSERT(0);
4222 return NULL;
4223 }
4224
4225 return ret_ptr;
4226 }
Analysis
In line driver/net/wireless/bcmdhd4538/dhd_msgbuf.c:4203 the number of available write items in the ringbuffer ring_avail_cnt is calculated based on a value controlled by the attacker on the WiFi SOC.
The value of ring_avail_count is calculated by a macro defined in driver/net/wireless/bcmdhd4538/include/bcmpcie.h:226.
199 #define NTXPACTIVE(r, w, d) (((r) <= (w)) ? ((w)-(r)) : ((d)-(r)+(w)))
...
223 #define WRITE_SPACE_AVAIL_CONTINUOUS(r, w, d) ((w >= r) ? (d - w) : (r - w))
224 #define WRITE_SPACE_AVAIL(r, w, d) (d - (NTXPACTIVE(r, w, d)) - 1)
225 #define CHECK_WRITE_SPACE(r, w, d) \
226 MIN(WRITE_SPACE_AVAIL(r, w, d), WRITE_SPACE_AVAIL_CONTINUOUS(r, w, d))
In line driver/net/wireless/bcmdhd4538/dhd_msgbuf.c:3833 the function prot_get_ring_space is invoked, which initializes the ringbuffer read pointer value by reading from memory that can be modified by the attacker on WiFi SoC in line driver/net/wireless/bcmdhd4538/dhd_pcie.c:2369.
3818 static void * BCMFASTPATH
3819 dhd_alloc_ring_space(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint16 nitems, uint16 * alloced)
3820 {
3821 void * ret_buf;
3822 uint16 r_index = 0;
3823
3824 /* Alloc space for nitems in the ring */
3825 ret_buf = prot_get_ring_space(ring, nitems, alloced);
3826
3827 if (ret_buf == NULL) {
3828 /* if alloc failed , invalidate cached read ptr */
3829 if (DMA_INDX_ENAB(dhd->dma_d2h_ring_upd_support)) {
3830 r_index = dhd_get_dmaed_index(dhd, H2D_DMA_READINDX, ring->idx);
3831 ring->ringstate->r_offset = r_index;
3832 } else
3833 dhd_bus_cmn_readshared(dhd->bus, &(RING_READ_PTR(ring)),
3834 RING_READ_PTR, ring->idx);
3835
3836 /* Try allocating once more */
3837 ret_buf = prot_get_ring_space(ring, nitems, alloced);
3838
3839 if (ret_buf == NULL) {
3840 DHD_INFO(("RING space not available on ring %s for %d items \n",
3841 ring->name, nitems));
3842 DHD_INFO(("write %d read %d \n\n", RING_WRITE_PTR(ring),
3843 RING_READ_PTR(ring)));
3844 return NULL;
3845 }
3846 }
3847
3848 /* Return alloced space */
3849 return ret_buf;
3850 }
2354 void
2355 dhd_bus_cmn_readshared(dhd_bus_t *bus, void* data, uint8 type, uint16 ringid)
2356 {
2357 pciedev_shared_t *sh;
2358 ulong tcm_offset;
2359
2360 sh = (pciedev_shared_t*)bus->shared_addr;
2361
2362 switch (type) {
2363 case RING_WRITE_PTR :
2364 tcm_offset = bus->ring_sh[ringid].ring_state_w;
2365 *(uint16*)data = LTOH16(dhdpcie_bus_rtcm16(bus, tcm_offset));
2366 break;
2367 case RING_READ_PTR :
2368 tcm_offset = bus->ring_sh[ringid].ring_state_r;
2369 *(uint16*)data = LTOH16(dhdpcie_bus_rtcm16(bus, tcm_offset));
2370 break;
2371 case TOTAL_LFRAG_PACKET_CNT :
2372 *(uint16*)data = LTOH16(dhdpcie_bus_rtcm16(bus,
2373 (ulong) &sh->total_lfrag_pkt_cnt));
2374 break;
2375 case HTOD_MB_DATA:
2376 *(uint32*)data = LTOH32(dhdpcie_bus_rtcm32(bus, bus->h2d_mb_data_ptr_addr));
2377 break;
2378 case DTOH_MB_DATA:
2379 *(uint32*)data = LTOH32(dhdpcie_bus_rtcm32(bus, bus->d2h_mb_data_ptr_addr));
2380 break;
2381 case MAX_HOST_RXBUFS :
2382 *(uint16*)data = LTOH16(dhdpcie_bus_rtcm16(bus,
2383 (ulong) &sh->max_host_rxbufs));
2384 break;
2385 default :
2386 break;
2387 }
2388 }
Therefore, In line driver/net/wireless/bcmdhd4538/dhd_msgbuf.c:4203 the attacker controls the value of RING_READ_PTR(ring).
By choosing a value much higher that RING_WRITE_PTR(ring) for RING_READ_PTR(ring) the macro CHECK_WRITE_SPACE will evaluate MIN(d - d + r - w - 1, r - w) or simply r - w, which might exceed the actually available ringbuffer space.
Kernel-Trace
The bug was discovered based on the warning generated by the ASSERT statement in driver/net/wireless/bcmdhd4538/dhd_msgbuf.c:4221, which is shown at the end of the kernel trace below.
...
[ 103.120949] [0: kworker/0:3: 4824] usb: android_work config= (null),connected=1,sw_connected=0
[ 103.120969] I[0: kworker/0:3: 4824] usb: set_config_number single config num=0
[ 103.120980] I[0: kworker/0:3: 4824] usb: config_buf f->adb
[ 103.120994] I[0: kworker/0:3: 4824] usb: set_interface_count next_interface_id=1
[ 103.121066] I[0: kworker/0:3: 4824] usb: set_config_number single config num=0
[ 103.121076] I[0: kworker/0:3: 4824] usb: config_buf f->adb
[ 103.121086] I[0: kworker/0:3: 4824] usb: set_interface_count next_interface_id=1
[ 103.121501] [0: kworker/0:3: 4824] usb: android_work sent uevent USB_STATE=CONNECTED
[ 103.121997] I[0: swapper/0: 0] android_usb gadget: high-speed config #1: android
[ 103.122020] I[0: swapper/0: 0] usb: set_config e adb[0]
[ 103.122083] I[0: swapper/0: 0] usb: SET_CON
[ 103.122095] I[0: swapper/0: 0] usb: set_config_number single config num=0
[ 103.122177] [0: kworker/0:3: 4824] usb: android_work config=ffffffc0014cf508,connected=1,sw_connected=1
[ 103.122319] [0: kworker/0:3: 4824] usb: android_work sent uevent USB_STATE=CONFIGURED
[ 103.151044] [0: kworker/0:3: 4824] [Time-to-FULL] 0(secs), 0(mins)
[ 103.151315] [0: kworker/0:3: 4824] [Time-to-EMPTY] 368634(secs), 6143(mins)
[ 103.183440] [0: thread_hotplug: 1881] frequency info : 600000, prev_cmd 4, exe_cmd 1
[ 103.183489] [0: thread_hotplug: 1881] lcd is on : 0, low power mode = 0, dm_hotplug disable = 0
[ 103.183515] [0: thread_hotplug: 1881] cluster1 cores hotplug out : 0
[ 103.186031] [3: migration/3: 23] IRQ151 no longer affine to CPU3
[ 103.187658] [0: thread_hotplug: 1881] CPU3: shutdown
[ 103.189707] [0: thread_hotplug: 1881] MobiCore mcd: <- core_num=0x00000000, active_cpu=0x00000002
[ 103.189836] [2: mc_fastcall: 1585] MobiCore mcd: CoreSwap ok 2 -> 0
[ 103.191276] [2: migration/2: 18] IRQ150 no longer affine to CPU2
[ 103.192863] [0: thread_hotplug: 1881] CPU2: shutdown
[ 103.198361] [1: migration/1: 13] IRQ149 no longer affine to CPU1
[ 103.199880] [0: thread_hotplug: 1881] CPU1: shutdown
[ 103.210177] [0: kworker/0:3: 4824] [FG] 0080h,ffa5h,7f80h,ff01h,1900h,11abh,63edh,5767h,1acdh,d798h,00a6h,0135h,004eh,5da0h,65f4h,1204h,11b6h,ffffh,3380h,5c00h,046ah,0148h,1a9ah,010fh,1439h,d72dh,290fh,d992h,41b8h,0314h,0578h,11b7h,0000h,20b0h,2000h,1327h,1400h,2305h,1a75h,7f6ch,2472h,cea4h,203bh,09d0h,e3e1h,290eh,0400h,0000h,4d07h,45c1h,1603h,02d7h,0000h,11aeh,ebc8h,05e0h,0035h,1a45h,7d54h,f9fbh,1680h,1408h,5484h,e000h,0000h,b00dh,1005h,0000h,d881h,07ddh,521dh,ffdah,5e15h,2271h,1204h,0000h,0adfh,0ad7h,107eh,0000h,0000h,0000h,7f80h,0000h,0000h,0005h,0073h,0a53h,0000h,006bh,090ch,0050h,00efh,0204h,051ah,0000h,03ddh,100fh,0c0eh,0c0dh,0c0ch,0c0bh,0c0ah,0c09h,0c08h,a516h,4350h,0010h,004eh,ffffh,65edh,11b6h,07f3h,2472h,0012h,0012h,0012h,0002h,1204h,0000h,4c30h,0004h,4240h,0000h,4000h,0000h,7d00h,0620h,0000h,0000h,0000h,0000h,22cfh,0000h,0000h,f55eh,3fb6h,5a8bh,ff5fh,d84fh,002fh,2910h,d798h,5da4h,
[ 103.210483] [0: kworker/0:3: 4824] max77843_fg_read_current: current=-72
[ 103.210973] [0: kworker/0:3: 4824] max77843_fg_read_avg_current: avg_current=46
[ 103.211943] [0: kworker/0:3: 4824] max77843_fg_write_temp: temperature to (268, 0x1acd)
[ 103.212398] [0: kworker/0:3: 4824] max77843_fg_check_qrtable: QRTABLE20_REG(0x1603), QRTABLE30_REG(0x1005)
[ 103.216370] [0: kworker/0:3: 4824] max77843_fg_read_current: current=-72
[ 103.216789] [0: kworker/0:3: 4824] max77843_fg_read_vcell: VCELL(4311), data(0xd798)
[ 103.216808] [0: kworker/0:3: 4824] max77843_fg_read_avg_current: avg_current=46
[ 103.217041] [0: kworker/0:3: 4824] max77843_get_fuelgauge_soc: soc(999), low_batt_alarm(0)
[ 103.217064] [0: kworker/0:3: 4824] sec_bat_get_property cable type = 4 sleep_mode = 0
[ 103.217262] [0: kworker/0:3: 4824] max77843_chg_get_property : set-current(460mA), current now(300mA)
[ 103.217459] [0: kworker/0:3: 4824] max77843_fg_get_scaled_capacity : CABLE TYPE(4) INPUT CURRENT(300) CHARGINGE MODE(CC Mode)
[ 103.217478] [0: kworker/0:3: 4824] max77843_fg_get_scaled_capacity: capacity_max (989)
[ 103.217692] [0: kworker/0:3: 4824] max77843_fg_get_scaled_capacity: scaled capacity (101.0)
[ 103.217712] [0: kworker/0:3: 4824] max77843_fg_get_atomic_capacity : NOW(100), OLD(100)
[ 103.217749] [0: kworker/0:3: 4824] sec-battery battery.53: sec_bat_get_battery_info:Vnow(4311mV),Inow(-72mA),Isysnow(-1mA),Imax(300mA),SOC(100%),Tbat(268),Tchg(293),Twpc(0),is_hc_usb(0)
[ 103.217774] [0: kworker/0:3: 4824] sec-battery battery.53: Connected,Vavg(4303mV),Vocv(4326mV),Tamb(268),Iavg(46mA),Isysavg(-1mA),Iadc(0)
[ 103.218153] [0: kworker/0:3: 4824] sec-battery battery.53: sec_bat_cisd_check: [CISD] iavg: 46, incur: 300, chgcur: 450,
[ 103.218153] [0: kworker/0:3: 4824] lcd_off_T: 0, cc_T: 0, passed_T: 81, full_T: 0, chg_end_T: 0, cisd: 0x0
[ 103.218189] [0: kworker/0:3: 4824] sec-battery battery.53: sec_bat_cisd_check: cisd - clear EFG
[ 103.218218] [0: kworker/0:3: 4824] sec-battery battery.53: sec_bat_cisd_check: [CISD] iavg: 46, incur: 300, chgcur: 450,
[ 103.218218] [0: kworker/0:3: 4824] lcd_off_T: 0, cc_T: 0, passed_T: 81, full_T: 0, chg_end_T: 0, recnt: 0, cisd: 0x0
[ 103.218646] [0: kworker/0:3: 4824] cisd - stt:0, cp:2265/0, cpmm:65535/2265/0, dcpt:0, ovc:0, rct:2147483647
[ 103.218670] [0: kworker/0:3: 4824] cisd_debug: 0, 0, 65535, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2147483647, 1
[ 103.218870] [0: kworker/0:3: 4824] calc_ttf: cc_time: 36
[ 103.218891] [0: kworker/0:3: 4824] calc_ttf: cap: 2588, soc: 999, T: 36, now: -72, avg: 46, cv soc: 1000, i: 85, val: 250, CC Mode
[ 103.218913] [0: kworker/0:3: 4824] sec-battery battery.53: sec_bat_calc_time_to_full: T: 60 sec, passed time: 81
[ 103.219395] [0: kworker/0:3: 4824] max77843_get_charging_health: reg_data(0x3)
[ 103.219594] [0: kworker/0:3: 4824] sec_bat_get_property cable type = 4 sleep_mode = 0
[ 103.219612] [0: kworker/0:3: 4824] max77843_get_vbus_state: VBUS is valid. CHGIN < CHGIN_OVLO
[ 103.219974] [0: kworker/0:3: 4824] max77843_get_charging_health: vbus_state : 0x3, chg_dtls : 0x1
[ 103.220006] [0: kworker/0:3: 4824] sec-battery battery.53: sec_bat_monitor_work: Status(Charging), mode(Normal), Health(Good), Cable(4,1), level(100%), HV(NONE), Cycle(-1)
[ 103.220029] [0: kworker/0:3: 4824] power_supply battery: power_supply_changed
[ 103.220127] [0: kworker/0:3: 4824] max77843_chg_get_property: slow-charging mode
[ 103.220156] [0: kworker/0:3: 4824] sec_bat_get_property cable type = 4 sleep_mode = 0
[ 103.220187] [0: kworker/0:3: 4824] sec_bat_get_property cable type = 4
[ 103.223610] [0: healthd: 3000] healthd: max77843-charger: Unknown power supply type
[ 103.224019] [0: healthd: 3000] max77843_get_float_voltage: battery cv voltage 0x1d, chg_float_voltage = 4375mV
[ 105.493519] [0: thread_hotplug: 1881] frequency info : 1400000, prev_cmd 1, exe_cmd 4
[ 105.493545] [0: thread_hotplug: 1881] lcd is on : 0, low power mode = 1, dm_hotplug disable = 0
[ 105.493556] [0: thread_hotplug: 1881] cluster1 cores hotplug out : 0
[ 105.493870] [1: swapper/1: 0] CPU1: Booted secondary processor
[ 105.495465] [2: swapper/2: 0] CPU2: Booted secondary processor
[ 105.496625] [0: thread_hotplug: 1881] MobiCore mcd: <- core_num=0x00000002, active_cpu=0x00000000
[ 105.496719] [0: mc_fastcall: 1585] MobiCore mcd: CoreSwap ok 0 -> 2
[ 105.497165] [3: swapper/3: 0] CPU3: Booted secondary processor
[ 105.511390] I[0: swapper/0: 0] "0": file "dhd_msgbuf.c", line 4221
[ 105.511603] I[0: swapper/0: 0] "0": file "dhd_msgbuf.c", line 4221
[ 105.511615] I[0: swapper/0: 0] dhd_prot_rxbufpost:2074: Rxbufpost Msgbuf Not available
[ 105.593591] [0: thread_hotplug: 1881] frequency info : 400000, prev_cmd 4, exe_cmd 1
[ 105.593682] [0: thread_hotplug: 1881] lcd is on : 0, low power mode = 0, dm_hotplug disable = 0
[ 105.593720] [0: thread_hotplug: 1881] cluster1 cores hotplug out : 0
[ 105.598033] [3: migration/3: 23] IRQ151 no longer affine to CPU3
[ 105.600690] [0: thread_hotplug: 1881] CPU3: shutdown
[ 105.604615] [0: thread_hotplug: 1881] MobiCore mcd: <- core_num=0x00000000, active_cpu=0x00000002
[ 105.604822] [2: mc_fastcall: 1585] MobiCore mcd: CoreSwap ok 2 -> 0
[ 105.609966] [2: migration/2: 18] IRQ150 no longer affine to CPU2
[ 105.612619] [0: thread_hotplug: 1881] CPU2: shutdown
[ 105.620694] [1: migration/1: 13] IRQ149 no longer affine to CPU1
[ 105.623578] [0: thread_hotplug: 1881] CPU1: shutdown
[ 106.637930] I[0: swapper/0: 0] "0": file "dhd_msgbuf.c", line 4221
[ 106.638215] I[0: swapper/0: 0] "0": file "dhd_msgbuf.c", line 4221
[ 106.638256] I[0: swapper/0: 0] dhd_prot_rxbufpost:2074: Rxbufpost Msgbuf Not available
[ 107.515009] I[0: swapper/0: 0] "0": file "dhd_msgbuf.c", line 4221
[ 107.515290] I[0: swapper/0: 0] "0": file "dhd_msgbuf.c", line 4221
[ 107.515332] I[0: swapper/0: 0] dhd_prot_rxbufpost:2074: Rxbufpost Msgbuf Not available
[ 108.512249] I[0: swapper/0: 0] "0": file "dhd_msgbuf.c", line 4221
[ 108.512527] I[0: swapper/0: 0] "0": file "dhd_msgbuf.c", line 4221
[ 108.512569] I[0: swapper/0: 0] dhd_prot_rxbufpost:2074: Rxbufpost Msgbuf Not available
[ 109.523213] I[0: swapper/0: 0] "0": file "dhd_msgbuf.c", line 4221
[ 109.523491] I[0: swapper/0: 0] "0": file "dhd_msgbuf.c", line 4221
[ 109.523787] I[0: swapper/0: 0] dhd_prot_rxbufpost:2074: Rxbufpost Msgbuf Not available
[ 110.094278] [0: kworker/u16:6: 3406] vfsspi_work_func_debug ldo:3, sleep:0, irq:0, tz:1, type:viper, cnt_irq:0, adm: 0
[ 110.516988] I[0: swapper/0: 0] "0": file "dhd_msgbuf.c", line 4221
[ 110.517267] I[0: swapper/0: 0] "0": file "dhd_msgbuf.c", line 4221
[ 110.517309] I[0: swapper/0: 0] dhd_prot_rxbufpost:2074: Rxbufpost Msgbuf Not available
In-Depth Analysis
Exploiting the out of bound ringbuffer pointer
The out of bound ringbuffer pointer calculated in prot_get_ring_space can potentially lead to an out-of bound memory access in the function dhd_prot_rxbufpost, which calls the function dhd_alloc_ring_space at (1) in order to obtain a ringbuffer pointer which can hold count elements.
/* Post count no of rx buffers down to dongle */
static int BCMFASTPATH
dhd_prot_rxbufpost(dhd_pub_t *dhd, uint16 count)
{
...
DHD_GENERAL_LOCK(dhd, flags);
/* Claim space for 'count' no of messages */
// (1) get ring buffer pointer for <count> new entries
msg_start = (void *)dhd_alloc_ring_space(dhd, ring, count, &alloced);
DHD_GENERAL_UNLOCK(dhd, flags);
if (msg_start == NULL) {
DHD_INFO(("%s:%d: Rxbufpost Msgbuf Not available\n", __FUNCTION__, __LINE__));
return -1;
}
/* if msg_start != NULL, we should have alloced space for atleast 1 item */
ASSERT(alloced > 0);
rxbuf_post_tmp = (uint8*)msg_start;
/* loop through each message */
for (i = 0; i < alloced; i++) {
rxbuf_post = (host_rxbuf_post_t *)rxbuf_post_tmp;
...
/* Move rxbuf_post_tmp to next item */
rxbuf_post_tmp = rxbuf_post_tmp + RING_LEN_ITEMS(ring);
}
...
return alloced;
}
The function dhd_alloc_ring_space in turn updates the attacker controlled value of RING_READ_PTR(ring) at (2) and invokes prot_get_ring_space at (3).
static void * BCMFASTPATH
dhd_alloc_ring_space(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint16 nitems, uint16 * alloced)
{
void * ret_buf;
uint16 r_index = 0;
/* Alloc space for nitems in the ring */
ret_buf = prot_get_ring_space(ring, nitems, alloced);
if (ret_buf == NULL) {
/* if alloc failed , invalidate cached read ptr */
if (DMA_INDX_ENAB(dhd->dma_d2h_ring_upd_support)) {
r_index = dhd_get_dmaed_index(dhd, H2D_DMA_READINDX, ring->idx);
ring->ringstate->r_offset = r_index;
} else
// (2) RING_READ_PTR(ring) is updated here
dhd_bus_cmn_readshared(dhd->bus, &(RING_READ_PTR(ring)),
RING_READ_PTR, ring->idx);
/* Try allocating once more */
// (3) invokation of prot_get_ring_space
ret_buf = prot_get_ring_space(ring, nitems, alloced);
if (ret_buf == NULL) {
DHD_INFO(("RING space not available on ring %s for %d items \n",
ring->name, nitems));
DHD_INFO(("write %d read %d \n\n", RING_WRITE_PTR(ring),
RING_READ_PTR(ring)));
return NULL;
}
}
/* Return alloced space */
return ret_buf;
}
Since the attacker controls the value of ring_avail_cnt in prot_get_ring_space at (4), the value of *alloced calculated at (5) can be equal to nitems even though there are less then nitems free entries left in the ringbuffer. Further, the comparison at (6) can cause an integer overflow if (RING_WRITE_PTR(ring) + *alloced) is greater then 0xffff.
/* Assumes only one index is updated ata time */
static void *BCMFASTPATH
prot_get_ring_space(msgbuf_ring_t *ring, uint16 nitems, uint16 * alloced)
{
void *ret_ptr = NULL;
uint16 ring_avail_cnt;
ASSERT(nitems <= RING_MAX_ITEM(ring));
// (4) ring_avail_cnt is under attacker control
ring_avail_cnt = CHECK_WRITE_SPACE(RING_READ_PTR(ring), RING_WRITE_PTR(ring),
RING_MAX_ITEM(ring));
if (ring_avail_cnt == 0) {
return NULL;
}
// (5) alloced will be equal to nitems
*alloced = MIN(nitems, ring_avail_cnt);
/* Return next available space */
ret_ptr = (char*)HOST_RING_BASE(ring) + (RING_WRITE_PTR(ring) * RING_LEN_ITEMS(ring));
/* Update write pointer */
if ((RING_WRITE_PTR(ring) + *alloced) == RING_MAX_ITEM(ring))
RING_WRITE_PTR(ring) = 0;
// (6) integer overflow for values of *alloced > 0xffff - RING_WRITE_PTR(ring) + 1
else if ((RING_WRITE_PTR(ring) + *alloced) < RING_MAX_ITEM(ring))
RING_WRITE_PTR(ring) += *alloced;
else {
/* Should never hit this */
ASSERT(0);
return NULL;
}
return ret_ptr;
}