Skip to content

Commit 9039d98

Browse files
committed
iwlwifi: fw: harden page loading code
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]>
1 parent 1e5b775 commit 9039d98

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
@@ -163,7 +165,7 @@ static int iwl_alloc_fw_paging_mem(struct iwl_fw_runtime *fwrt,
163165
static int iwl_fill_paging_mem(struct iwl_fw_runtime *fwrt,
164166
const struct fw_img *image)
165167
{
166-
int sec_idx, idx;
168+
int sec_idx, idx, ret;
167169
u32 offset = 0;
168170

169171
/*
@@ -190,17 +192,23 @@ static int iwl_fill_paging_mem(struct iwl_fw_runtime *fwrt,
190192
*/
191193
if (sec_idx >= image->num_sec - 1) {
192194
IWL_ERR(fwrt, "Paging: Missing CSS and/or paging sections\n");
193-
iwl_free_fw_paging(fwrt);
194-
return -EINVAL;
195+
ret = -EINVAL;
196+
goto err;
195197
}
196198

197199
/* copy the CSS block to the dram */
198200
IWL_DEBUG_FW(fwrt, "Paging: load paging CSS to FW, sec = %d\n",
199201
sec_idx);
200202

203+
if (image->sec[sec_idx].len > fwrt->fw_paging_db[0].fw_paging_size) {
204+
IWL_ERR(fwrt, "CSS block is larger than paging size\n");
205+
ret = -EINVAL;
206+
goto err;
207+
}
208+
201209
memcpy(page_address(fwrt->fw_paging_db[0].fw_paging_block),
202210
image->sec[sec_idx].data,
203-
fwrt->fw_paging_db[0].fw_paging_size);
211+
image->sec[sec_idx].len);
204212
dma_sync_single_for_device(fwrt->trans->dev,
205213
fwrt->fw_paging_db[0].fw_paging_phys,
206214
fwrt->fw_paging_db[0].fw_paging_size,
@@ -221,6 +229,14 @@ static int iwl_fill_paging_mem(struct iwl_fw_runtime *fwrt,
221229
for (idx = 1; idx < fwrt->num_of_paging_blk; idx++) {
222230
struct iwl_fw_paging *block = &fwrt->fw_paging_db[idx];
223231

232+
if (block->fw_paging_size > image->sec[sec_idx].len - offset) {
233+
IWL_ERR(fwrt,
234+
"Paging: paging size is larger than remaining data in block %d\n",
235+
idx);
236+
ret = -EINVAL;
237+
goto err;
238+
}
239+
224240
memcpy(page_address(block->fw_paging_block),
225241
image->sec[sec_idx].data + offset,
226242
block->fw_paging_size);
@@ -231,19 +247,32 @@ static int iwl_fill_paging_mem(struct iwl_fw_runtime *fwrt,
231247

232248
IWL_DEBUG_FW(fwrt,
233249
"Paging: copied %d paging bytes to block %d\n",
234-
fwrt->fw_paging_db[idx].fw_paging_size,
235-
idx);
250+
block->fw_paging_size, idx);
236251

237-
offset += fwrt->fw_paging_db[idx].fw_paging_size;
252+
offset += block->fw_paging_size;
253+
254+
if (offset > image->sec[sec_idx].len) {
255+
IWL_ERR(fwrt,
256+
"Paging: offset goes over section size\n");
257+
ret = -EINVAL;
258+
goto err;
259+
}
238260
}
239261

240262
/* copy the last paging block */
241263
if (fwrt->num_of_pages_in_last_blk > 0) {
242264
struct iwl_fw_paging *block = &fwrt->fw_paging_db[idx];
243265

266+
if (image->sec[sec_idx].len - offset > block->fw_paging_size) {
267+
IWL_ERR(fwrt,
268+
"Paging: last block is larger than paging size\n");
269+
ret = -EINVAL;
270+
goto err;
271+
}
272+
244273
memcpy(page_address(block->fw_paging_block),
245274
image->sec[sec_idx].data + offset,
246-
FW_PAGING_SIZE * fwrt->num_of_pages_in_last_blk);
275+
image->sec[sec_idx].len - offset);
247276
dma_sync_single_for_device(fwrt->trans->dev,
248277
block->fw_paging_phys,
249278
block->fw_paging_size,
@@ -255,6 +284,10 @@ static int iwl_fill_paging_mem(struct iwl_fw_runtime *fwrt,
255284
}
256285

257286
return 0;
287+
288+
err:
289+
iwl_free_fw_paging(fwrt);
290+
return ret;
258291
}
259292

260293
static int iwl_save_fw_paging(struct iwl_fw_runtime *fwrt,

0 commit comments

Comments
 (0)