Skip to content

Commit b3cb7a8

Browse files
cailkuba-moo
authored andcommitted
net: atlantic: eliminate double free in error handling logic
Driver has a logic leak in ring data allocation/free, where aq_ring_free could be called multiple times on same ring, if system is under stress and got memory allocation error. Ring pointer was used as an indicator of failure, but this is not correct since only ring data is allocated/deallocated. Ring itself is an array member. Changing ring allocation functions to return error code directly. This simplifies error handling and eliminates aq_ring_free on higher layer. Signed-off-by: Igor Russkikh <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 1891cfe commit b3cb7a8

File tree

4 files changed

+47
-87
lines changed

4 files changed

+47
-87
lines changed

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

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -953,38 +953,30 @@ int aq_ptp_ring_alloc(struct aq_nic_s *aq_nic)
953953
{
954954
struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
955955
unsigned int tx_ring_idx, rx_ring_idx;
956-
struct aq_ring_s *hwts;
957-
struct aq_ring_s *ring;
958956
int err;
959957

960958
if (!aq_ptp)
961959
return 0;
962960

963961
tx_ring_idx = aq_ptp_ring_idx(aq_nic->aq_nic_cfg.tc_mode);
964962

965-
ring = aq_ring_tx_alloc(&aq_ptp->ptp_tx, aq_nic,
966-
tx_ring_idx, &aq_nic->aq_nic_cfg);
967-
if (!ring) {
968-
err = -ENOMEM;
963+
err = aq_ring_tx_alloc(&aq_ptp->ptp_tx, aq_nic,
964+
tx_ring_idx, &aq_nic->aq_nic_cfg);
965+
if (err)
969966
goto err_exit;
970-
}
971967

972968
rx_ring_idx = aq_ptp_ring_idx(aq_nic->aq_nic_cfg.tc_mode);
973969

974-
ring = aq_ring_rx_alloc(&aq_ptp->ptp_rx, aq_nic,
975-
rx_ring_idx, &aq_nic->aq_nic_cfg);
976-
if (!ring) {
977-
err = -ENOMEM;
970+
err = aq_ring_rx_alloc(&aq_ptp->ptp_rx, aq_nic,
971+
rx_ring_idx, &aq_nic->aq_nic_cfg);
972+
if (err)
978973
goto err_exit_ptp_tx;
979-
}
980974

981-
hwts = aq_ring_hwts_rx_alloc(&aq_ptp->hwts_rx, aq_nic, PTP_HWST_RING_IDX,
982-
aq_nic->aq_nic_cfg.rxds,
983-
aq_nic->aq_nic_cfg.aq_hw_caps->rxd_size);
984-
if (!hwts) {
985-
err = -ENOMEM;
975+
err = aq_ring_hwts_rx_alloc(&aq_ptp->hwts_rx, aq_nic, PTP_HWST_RING_IDX,
976+
aq_nic->aq_nic_cfg.rxds,
977+
aq_nic->aq_nic_cfg.aq_hw_caps->rxd_size);
978+
if (err)
986979
goto err_exit_ptp_rx;
987-
}
988980

989981
err = aq_ptp_skb_ring_init(&aq_ptp->skb_ring, aq_nic->aq_nic_cfg.rxds);
990982
if (err != 0) {

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

Lines changed: 16 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@ static int aq_get_rxpages(struct aq_ring_s *self, struct aq_ring_buff_s *rxbuf)
132132
return 0;
133133
}
134134

135-
static struct aq_ring_s *aq_ring_alloc(struct aq_ring_s *self,
136-
struct aq_nic_s *aq_nic)
135+
static int aq_ring_alloc(struct aq_ring_s *self,
136+
struct aq_nic_s *aq_nic)
137137
{
138138
int err = 0;
139139

@@ -156,46 +156,29 @@ static struct aq_ring_s *aq_ring_alloc(struct aq_ring_s *self,
156156
err_exit:
157157
if (err < 0) {
158158
aq_ring_free(self);
159-
self = NULL;
160159
}
161160

162-
return self;
161+
return err;
163162
}
164163

165-
struct aq_ring_s *aq_ring_tx_alloc(struct aq_ring_s *self,
166-
struct aq_nic_s *aq_nic,
167-
unsigned int idx,
168-
struct aq_nic_cfg_s *aq_nic_cfg)
164+
int aq_ring_tx_alloc(struct aq_ring_s *self,
165+
struct aq_nic_s *aq_nic,
166+
unsigned int idx,
167+
struct aq_nic_cfg_s *aq_nic_cfg)
169168
{
170-
int err = 0;
171-
172169
self->aq_nic = aq_nic;
173170
self->idx = idx;
174171
self->size = aq_nic_cfg->txds;
175172
self->dx_size = aq_nic_cfg->aq_hw_caps->txd_size;
176173

177-
self = aq_ring_alloc(self, aq_nic);
178-
if (!self) {
179-
err = -ENOMEM;
180-
goto err_exit;
181-
}
182-
183-
err_exit:
184-
if (err < 0) {
185-
aq_ring_free(self);
186-
self = NULL;
187-
}
188-
189-
return self;
174+
return aq_ring_alloc(self, aq_nic);
190175
}
191176

192-
struct aq_ring_s *aq_ring_rx_alloc(struct aq_ring_s *self,
193-
struct aq_nic_s *aq_nic,
194-
unsigned int idx,
195-
struct aq_nic_cfg_s *aq_nic_cfg)
177+
int aq_ring_rx_alloc(struct aq_ring_s *self,
178+
struct aq_nic_s *aq_nic,
179+
unsigned int idx,
180+
struct aq_nic_cfg_s *aq_nic_cfg)
196181
{
197-
int err = 0;
198-
199182
self->aq_nic = aq_nic;
200183
self->idx = idx;
201184
self->size = aq_nic_cfg->rxds;
@@ -217,22 +200,10 @@ struct aq_ring_s *aq_ring_rx_alloc(struct aq_ring_s *self,
217200
self->tail_size = 0;
218201
}
219202

220-
self = aq_ring_alloc(self, aq_nic);
221-
if (!self) {
222-
err = -ENOMEM;
223-
goto err_exit;
224-
}
225-
226-
err_exit:
227-
if (err < 0) {
228-
aq_ring_free(self);
229-
self = NULL;
230-
}
231-
232-
return self;
203+
return aq_ring_alloc(self, aq_nic);
233204
}
234205

235-
struct aq_ring_s *
206+
int
236207
aq_ring_hwts_rx_alloc(struct aq_ring_s *self, struct aq_nic_s *aq_nic,
237208
unsigned int idx, unsigned int size, unsigned int dx_size)
238209
{
@@ -250,10 +221,10 @@ aq_ring_hwts_rx_alloc(struct aq_ring_s *self, struct aq_nic_s *aq_nic,
250221
GFP_KERNEL);
251222
if (!self->dx_ring) {
252223
aq_ring_free(self);
253-
return NULL;
224+
return -ENOMEM;
254225
}
255226

256-
return self;
227+
return 0;
257228
}
258229

259230
int aq_ring_init(struct aq_ring_s *self, const enum atl_ring_type ring_type)

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

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -183,14 +183,14 @@ static inline unsigned int aq_ring_avail_dx(struct aq_ring_s *self)
183183
self->sw_head - self->sw_tail - 1);
184184
}
185185

186-
struct aq_ring_s *aq_ring_tx_alloc(struct aq_ring_s *self,
187-
struct aq_nic_s *aq_nic,
188-
unsigned int idx,
189-
struct aq_nic_cfg_s *aq_nic_cfg);
190-
struct aq_ring_s *aq_ring_rx_alloc(struct aq_ring_s *self,
191-
struct aq_nic_s *aq_nic,
192-
unsigned int idx,
193-
struct aq_nic_cfg_s *aq_nic_cfg);
186+
int aq_ring_tx_alloc(struct aq_ring_s *self,
187+
struct aq_nic_s *aq_nic,
188+
unsigned int idx,
189+
struct aq_nic_cfg_s *aq_nic_cfg);
190+
int aq_ring_rx_alloc(struct aq_ring_s *self,
191+
struct aq_nic_s *aq_nic,
192+
unsigned int idx,
193+
struct aq_nic_cfg_s *aq_nic_cfg);
194194

195195
int aq_ring_init(struct aq_ring_s *self, const enum atl_ring_type ring_type);
196196
void aq_ring_rx_deinit(struct aq_ring_s *self);
@@ -207,9 +207,9 @@ int aq_ring_rx_clean(struct aq_ring_s *self,
207207
int budget);
208208
int aq_ring_rx_fill(struct aq_ring_s *self);
209209

210-
struct aq_ring_s *aq_ring_hwts_rx_alloc(struct aq_ring_s *self,
211-
struct aq_nic_s *aq_nic, unsigned int idx,
212-
unsigned int size, unsigned int dx_size);
210+
int aq_ring_hwts_rx_alloc(struct aq_ring_s *self,
211+
struct aq_nic_s *aq_nic, unsigned int idx,
212+
unsigned int size, unsigned int dx_size);
213213
void aq_ring_hwts_rx_clean(struct aq_ring_s *self, struct aq_nic_s *aq_nic);
214214

215215
unsigned int aq_ring_fill_stats_data(struct aq_ring_s *self, u64 *data);

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

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -136,35 +136,32 @@ int aq_vec_ring_alloc(struct aq_vec_s *self, struct aq_nic_s *aq_nic,
136136
const unsigned int idx_ring = AQ_NIC_CFG_TCVEC2RING(aq_nic_cfg,
137137
i, idx);
138138

139-
ring = aq_ring_tx_alloc(&self->ring[i][AQ_VEC_TX_ID], aq_nic,
140-
idx_ring, aq_nic_cfg);
141-
if (!ring) {
142-
err = -ENOMEM;
139+
ring = &self->ring[i][AQ_VEC_TX_ID];
140+
err = aq_ring_tx_alloc(ring, aq_nic, idx_ring, aq_nic_cfg);
141+
if (err)
143142
goto err_exit;
144-
}
145143

146144
++self->tx_rings;
147145

148146
aq_nic_set_tx_ring(aq_nic, idx_ring, ring);
149147

150-
if (xdp_rxq_info_reg(&self->ring[i][AQ_VEC_RX_ID].xdp_rxq,
148+
ring = &self->ring[i][AQ_VEC_RX_ID];
149+
if (xdp_rxq_info_reg(&ring->xdp_rxq,
151150
aq_nic->ndev, idx,
152151
self->napi.napi_id) < 0) {
153152
err = -ENOMEM;
154153
goto err_exit;
155154
}
156-
if (xdp_rxq_info_reg_mem_model(&self->ring[i][AQ_VEC_RX_ID].xdp_rxq,
155+
if (xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
157156
MEM_TYPE_PAGE_SHARED, NULL) < 0) {
158-
xdp_rxq_info_unreg(&self->ring[i][AQ_VEC_RX_ID].xdp_rxq);
157+
xdp_rxq_info_unreg(&ring->xdp_rxq);
159158
err = -ENOMEM;
160159
goto err_exit;
161160
}
162161

163-
ring = aq_ring_rx_alloc(&self->ring[i][AQ_VEC_RX_ID], aq_nic,
164-
idx_ring, aq_nic_cfg);
165-
if (!ring) {
166-
xdp_rxq_info_unreg(&self->ring[i][AQ_VEC_RX_ID].xdp_rxq);
167-
err = -ENOMEM;
162+
err = aq_ring_rx_alloc(ring, aq_nic, idx_ring, aq_nic_cfg);
163+
if (err) {
164+
xdp_rxq_info_unreg(&ring->xdp_rxq);
168165
goto err_exit;
169166
}
170167

0 commit comments

Comments
 (0)