Skip to content

Commit b8511db

Browse files
lucacoelhogregkh
authored andcommitted
iwlwifi: fw: harden page loading code
commit 9039d98 upstream. The page loading code trusts the data provided in the firmware images a bit too much and may cause a buffer overflow or copy unknown data if the block sizes don't match what we expect. To prevent potential problems, harden the code by checking if the sizes we are copying are what we expect. Cc: [email protected] Signed-off-by: Luca Coelho <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 2d58a9a commit b8511db

File tree

1 file changed

+41
-8
lines changed
  • drivers/net/wireless/intel/iwlwifi/fw

1 file changed

+41
-8
lines changed

drivers/net/wireless/intel/iwlwifi/fw/paging.c

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
99
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
1010
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
11+
* Copyright(c) 2018 Intel Corporation
1112
*
1213
* This program is free software; you can redistribute it and/or modify
1314
* it under the terms of version 2 of the GNU General Public License as
@@ -30,6 +31,7 @@
3031
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
3132
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
3233
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
34+
* Copyright(c) 2018 Intel Corporation
3335
* All rights reserved.
3436
*
3537
* Redistribution and use in source and binary forms, with or without
@@ -174,7 +176,7 @@ static int iwl_alloc_fw_paging_mem(struct iwl_fw_runtime *fwrt,
174176
static int iwl_fill_paging_mem(struct iwl_fw_runtime *fwrt,
175177
const struct fw_img *image)
176178
{
177-
int sec_idx, idx;
179+
int sec_idx, idx, ret;
178180
u32 offset = 0;
179181

180182
/*
@@ -201,17 +203,23 @@ static int iwl_fill_paging_mem(struct iwl_fw_runtime *fwrt,
201203
*/
202204
if (sec_idx >= image->num_sec - 1) {
203205
IWL_ERR(fwrt, "Paging: Missing CSS and/or paging sections\n");
204-
iwl_free_fw_paging(fwrt);
205-
return -EINVAL;
206+
ret = -EINVAL;
207+
goto err;
206208
}
207209

208210
/* copy the CSS block to the dram */
209211
IWL_DEBUG_FW(fwrt, "Paging: load paging CSS to FW, sec = %d\n",
210212
sec_idx);
211213

214+
if (image->sec[sec_idx].len > fwrt->fw_paging_db[0].fw_paging_size) {
215+
IWL_ERR(fwrt, "CSS block is larger than paging size\n");
216+
ret = -EINVAL;
217+
goto err;
218+
}
219+
212220
memcpy(page_address(fwrt->fw_paging_db[0].fw_paging_block),
213221
image->sec[sec_idx].data,
214-
fwrt->fw_paging_db[0].fw_paging_size);
222+
image->sec[sec_idx].len);
215223
dma_sync_single_for_device(fwrt->trans->dev,
216224
fwrt->fw_paging_db[0].fw_paging_phys,
217225
fwrt->fw_paging_db[0].fw_paging_size,
@@ -232,6 +240,14 @@ static int iwl_fill_paging_mem(struct iwl_fw_runtime *fwrt,
232240
for (idx = 1; idx < fwrt->num_of_paging_blk; idx++) {
233241
struct iwl_fw_paging *block = &fwrt->fw_paging_db[idx];
234242

243+
if (block->fw_paging_size > image->sec[sec_idx].len - offset) {
244+
IWL_ERR(fwrt,
245+
"Paging: paging size is larger than remaining data in block %d\n",
246+
idx);
247+
ret = -EINVAL;
248+
goto err;
249+
}
250+
235251
memcpy(page_address(block->fw_paging_block),
236252
image->sec[sec_idx].data + offset,
237253
block->fw_paging_size);
@@ -242,19 +258,32 @@ static int iwl_fill_paging_mem(struct iwl_fw_runtime *fwrt,
242258

243259
IWL_DEBUG_FW(fwrt,
244260
"Paging: copied %d paging bytes to block %d\n",
245-
fwrt->fw_paging_db[idx].fw_paging_size,
246-
idx);
261+
block->fw_paging_size, idx);
262+
263+
offset += block->fw_paging_size;
247264

248-
offset += fwrt->fw_paging_db[idx].fw_paging_size;
265+
if (offset > image->sec[sec_idx].len) {
266+
IWL_ERR(fwrt,
267+
"Paging: offset goes over section size\n");
268+
ret = -EINVAL;
269+
goto err;
270+
}
249271
}
250272

251273
/* copy the last paging block */
252274
if (fwrt->num_of_pages_in_last_blk > 0) {
253275
struct iwl_fw_paging *block = &fwrt->fw_paging_db[idx];
254276

277+
if (image->sec[sec_idx].len - offset > block->fw_paging_size) {
278+
IWL_ERR(fwrt,
279+
"Paging: last block is larger than paging size\n");
280+
ret = -EINVAL;
281+
goto err;
282+
}
283+
255284
memcpy(page_address(block->fw_paging_block),
256285
image->sec[sec_idx].data + offset,
257-
FW_PAGING_SIZE * fwrt->num_of_pages_in_last_blk);
286+
image->sec[sec_idx].len - offset);
258287
dma_sync_single_for_device(fwrt->trans->dev,
259288
block->fw_paging_phys,
260289
block->fw_paging_size,
@@ -266,6 +295,10 @@ static int iwl_fill_paging_mem(struct iwl_fw_runtime *fwrt,
266295
}
267296

268297
return 0;
298+
299+
err:
300+
iwl_free_fw_paging(fwrt);
301+
return ret;
269302
}
270303

271304
static int iwl_save_fw_paging(struct iwl_fw_runtime *fwrt,

0 commit comments

Comments
 (0)