Skip to content

Commit 2423b0d

Browse files
committed
Merge branch 'atlantic-fixes'
Grant Grundler says: ==================== net: atlantic: more fuzzing fixes It essentially describes four problems: 1) validate rxd_wb->next_desc_ptr before populating buff->next 2) "frag[0] not initialized" case in aq_ring_rx_clean() 3) limit iterations handling fragments in aq_ring_rx_clean() 4) validate hw_head_ in hw_atl_b0_hw_ring_tx_head_update() (1) was fixed by Zekun Shen <bruceshenzk@gmail.com> around the same time with "atlantic: Fix buff_ring OOB in aq_ring_rx_clean" (SHA1 5f50153). I've added one "clean up" contribution: "net: atlantic: reduce scope of is_rsc_complete" I tested the "original" patches using chromeos-v5.4 kernel branch: https://chromium-review.googlesource.com/q/hashtag:pcinet-atlantic-2022q1+(status:open%20OR%20status:merged) I've forward ported those patches to 5.18-rc2 and compiled them but am unable to test them on 5.18-rc2 kernel (logistics problems). Credit largely goes to ChromeOS Fuzzing team members: Aashay Shringarpure, Yi Chou, Shervin Oloumi V2 changes: o drop first patch - was already fixed upstream differently o reduce (4) "validate hw_head_" to simple bounds checking. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents 0807ce0 + 2120b7f commit 2423b0d

2 files changed

Lines changed: 18 additions & 9 deletions

File tree

drivers/net/ethernet/aquantia/atlantic/aq_ring.c

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,6 @@ int aq_ring_rx_clean(struct aq_ring_s *self,
346346
int budget)
347347
{
348348
struct net_device *ndev = aq_nic_get_ndev(self->aq_nic);
349-
bool is_rsc_completed = true;
350349
int err = 0;
351350

352351
for (; (self->sw_head != self->hw_head) && budget;
@@ -364,31 +363,35 @@ int aq_ring_rx_clean(struct aq_ring_s *self,
364363
continue;
365364

366365
if (!buff->is_eop) {
366+
unsigned int frag_cnt = 0U;
367367
buff_ = buff;
368368
do {
369+
bool is_rsc_completed = true;
370+
369371
if (buff_->next >= self->size) {
370372
err = -EIO;
371373
goto err_exit;
372374
}
375+
376+
frag_cnt++;
373377
next_ = buff_->next,
374378
buff_ = &self->buff_ring[next_];
375379
is_rsc_completed =
376380
aq_ring_dx_in_range(self->sw_head,
377381
next_,
378382
self->hw_head);
379383

380-
if (unlikely(!is_rsc_completed))
381-
break;
384+
if (unlikely(!is_rsc_completed) ||
385+
frag_cnt > MAX_SKB_FRAGS) {
386+
err = 0;
387+
goto err_exit;
388+
}
382389

383390
buff->is_error |= buff_->is_error;
384391
buff->is_cso_err |= buff_->is_cso_err;
385392

386393
} while (!buff_->is_eop);
387394

388-
if (!is_rsc_completed) {
389-
err = 0;
390-
goto err_exit;
391-
}
392395
if (buff->is_error ||
393396
(buff->is_lro && buff->is_cso_err)) {
394397
buff_ = buff;
@@ -446,7 +449,7 @@ int aq_ring_rx_clean(struct aq_ring_s *self,
446449
ALIGN(hdr_len, sizeof(long)));
447450

448451
if (buff->len - hdr_len > 0) {
449-
skb_add_rx_frag(skb, 0, buff->rxdata.page,
452+
skb_add_rx_frag(skb, i++, buff->rxdata.page,
450453
buff->rxdata.pg_off + hdr_len,
451454
buff->len - hdr_len,
452455
AQ_CFG_RX_FRAME_MAX);
@@ -455,7 +458,6 @@ int aq_ring_rx_clean(struct aq_ring_s *self,
455458

456459
if (!buff->is_eop) {
457460
buff_ = buff;
458-
i = 1U;
459461
do {
460462
next_ = buff_->next;
461463
buff_ = &self->buff_ring[next_];

drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,13 @@ int hw_atl_b0_hw_ring_tx_head_update(struct aq_hw_s *self,
889889
err = -ENXIO;
890890
goto err_exit;
891891
}
892+
893+
/* Validate that the new hw_head_ is reasonable. */
894+
if (hw_head_ >= ring->size) {
895+
err = -ENXIO;
896+
goto err_exit;
897+
}
898+
892899
ring->hw_head = hw_head_;
893900
err = aq_hw_err_from_flags(self);
894901

0 commit comments

Comments
 (0)