aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/rtas_flash.c
diff options
context:
space:
mode:
authorVasant Hegde <hegdevasant@linux.vnet.ibm.com>2013-04-28 14:43:56 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-04-30 01:59:28 -0400
commitfb4696c39573ea97d0aeb94fdcdbccba4607b49f (patch)
tree574bf566d452789b23927bf341ee3cb6fe90c655 /arch/powerpc/kernel/rtas_flash.c
parent9f3a90e89d2503ce4c40159526e446f1fca92f10 (diff)
powerpc/rtas_flash: Fix bad memory access
We use kmem_cache_alloc() to allocate memory to hold the new firmware which will be flashed. kmem_cache_alloc() calls rtas_block_ctor() to set memory to NULL. But these constructor is called only for newly allocated slabs. If we run below command multiple time without rebooting, allocator may allocate memory from the area which was free'd by kmem_cache_free and it will not call constructor. In this situation we may hit kernel oops. dd if=<fw image> of=/proc/ppc64/rtas/firmware_flash bs=4096 oops message: ------------- [ 1602.399755] Oops: Kernel access of bad area, sig: 11 [#1] [ 1602.399772] SMP NR_CPUS=1024 NUMA pSeries [ 1602.399779] Modules linked in: rtas_flash nfsd lockd auth_rpcgss nfs_acl sunrpc fuse loop dm_mod sg ipv6 ses enclosure ehea ehci_pci ohci_hcd ehci_hcd usbcore sd_mod usb_common crc_t10dif scsi_dh_alua scsi_dh_emc scsi_dh_hp_sw scsi_dh_rdac scsi_dh ipr libata scsi_mod [ 1602.399817] NIP: d00000000a170b9c LR: d00000000a170b64 CTR: c00000000079cd58 [ 1602.399823] REGS: c0000003b9937930 TRAP: 0300 Not tainted (3.9.0-rc4-0.27-ppc64) [ 1602.399828] MSR: 8000000000009032 <SF,EE,ME,IR,DR,RI> CR: 22000428 XER: 20000000 [ 1602.399841] SOFTE: 1 [ 1602.399844] CFAR: c000000000005f24 [ 1602.399848] DAR: 8c2625a820631fef, DSISR: 40000000 [ 1602.399852] TASK = c0000003b4520760[3655] 'dd' THREAD: c0000003b9934000 CPU: 3 GPR00: 8c2625a820631fe7 c0000003b9937bb0 d00000000a179f28 d00000000a171f08 GPR04: 0000000010040000 0000000000001000 c0000003b9937df0 c0000003b5fb2080 GPR08: c0000003b58f7200 d00000000a179f28 c0000003b40058d4 c00000000079cd58 GPR12: d00000000a171450 c000000007f40900 0000000000000005 0000000010178d20 GPR16: 00000000100cb9d8 000000000000001d 0000000000000000 000000001003ffff GPR20: 0000000000000001 0000000000000000 00003fffa0b50d30 000000001001f010 GPR24: 0000000010020888 0000000010040000 d00000000a171f08 d00000000a172808 GPR28: 0000000000001000 0000000010040000 c0000003b4005880 8c2625a820631fe7 [ 1602.399924] NIP [d00000000a170b9c] .rtas_flash_write+0x7c/0x1e8 [rtas_flash] [ 1602.399930] LR [d00000000a170b64] .rtas_flash_write+0x44/0x1e8 [rtas_flash] [ 1602.399934] Call Trace: [ 1602.399939] [c0000003b9937bb0] [d00000000a170b64] .rtas_flash_write+0x44/0x1e8 [rtas_flash] (unreliable) [ 1602.399948] [c0000003b9937c60] [c000000000282830] .proc_reg_write+0x90/0xe0 [ 1602.399955] [c0000003b9937ce0] [c0000000001ff374] .vfs_write+0x114/0x238 [ 1602.399961] [c0000003b9937d80] [c0000000001ff5d8] .SyS_write+0x70/0xe8 [ 1602.399968] [c0000003b9937e30] [c000000000009cdc] syscall_exit+0x0/0xa0 [ 1602.399973] Instruction dump: [ 1602.399977] eb698010 801b0028 2f80dcd6 419e00a4 2fbc0000 419e009c ebfb0030 2fbf0000 [ 1602.399989] 409e0010 480000d8 60000000 7c1f0378 <e81f0008> 2fa00000 409efff4 e81f0000 [ 1602.400012] ---[ end trace b4136d115dc31dac ]--- [ 1602.402178] [ 1602.402185] Sending IPI to other CPUs [ 1602.403329] IPI complete This patch uses kmem_cache_zalloc() instead of kmem_cache_alloc() to allocate memory, which makes sure memory is set to 0 before using. Also removes rtas_block_ctor(), which is no longer required. Signed-off-by: Vasant Hegde <hegdevasant@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel/rtas_flash.c')
-rw-r--r--arch/powerpc/kernel/rtas_flash.c14
1 files changed, 4 insertions, 10 deletions
diff --git a/arch/powerpc/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c
index a3e4034b6843..243e184cbe45 100644
--- a/arch/powerpc/kernel/rtas_flash.c
+++ b/arch/powerpc/kernel/rtas_flash.c
@@ -286,12 +286,6 @@ static ssize_t rtas_flash_read(struct file *file, char __user *buf,
286 return simple_read_from_buffer(buf, count, ppos, msg, strlen(msg)); 286 return simple_read_from_buffer(buf, count, ppos, msg, strlen(msg));
287} 287}
288 288
289/* constructor for flash_block_cache */
290void rtas_block_ctor(void *ptr)
291{
292 memset(ptr, 0, RTAS_BLK_SIZE);
293}
294
295/* We could be much more efficient here. But to keep this function 289/* We could be much more efficient here. But to keep this function
296 * simple we allocate a page to the block list no matter how small the 290 * simple we allocate a page to the block list no matter how small the
297 * count is. If the system is low on memory it will be just as well 291 * count is. If the system is low on memory it will be just as well
@@ -316,7 +310,7 @@ static ssize_t rtas_flash_write(struct file *file, const char __user *buffer,
316 * proc file 310 * proc file
317 */ 311 */
318 if (uf->flist == NULL) { 312 if (uf->flist == NULL) {
319 uf->flist = kmem_cache_alloc(flash_block_cache, GFP_KERNEL); 313 uf->flist = kmem_cache_zalloc(flash_block_cache, GFP_KERNEL);
320 if (!uf->flist) 314 if (!uf->flist)
321 return -ENOMEM; 315 return -ENOMEM;
322 } 316 }
@@ -327,7 +321,7 @@ static ssize_t rtas_flash_write(struct file *file, const char __user *buffer,
327 next_free = fl->num_blocks; 321 next_free = fl->num_blocks;
328 if (next_free == FLASH_BLOCKS_PER_NODE) { 322 if (next_free == FLASH_BLOCKS_PER_NODE) {
329 /* Need to allocate another block_list */ 323 /* Need to allocate another block_list */
330 fl->next = kmem_cache_alloc(flash_block_cache, GFP_KERNEL); 324 fl->next = kmem_cache_zalloc(flash_block_cache, GFP_KERNEL);
331 if (!fl->next) 325 if (!fl->next)
332 return -ENOMEM; 326 return -ENOMEM;
333 fl = fl->next; 327 fl = fl->next;
@@ -336,7 +330,7 @@ static ssize_t rtas_flash_write(struct file *file, const char __user *buffer,
336 330
337 if (count > RTAS_BLK_SIZE) 331 if (count > RTAS_BLK_SIZE)
338 count = RTAS_BLK_SIZE; 332 count = RTAS_BLK_SIZE;
339 p = kmem_cache_alloc(flash_block_cache, GFP_KERNEL); 333 p = kmem_cache_zalloc(flash_block_cache, GFP_KERNEL);
340 if (!p) 334 if (!p)
341 return -ENOMEM; 335 return -ENOMEM;
342 336
@@ -786,7 +780,7 @@ static int __init rtas_flash_init(void)
786 780
787 flash_block_cache = kmem_cache_create("rtas_flash_cache", 781 flash_block_cache = kmem_cache_create("rtas_flash_cache",
788 RTAS_BLK_SIZE, RTAS_BLK_SIZE, 0, 782 RTAS_BLK_SIZE, RTAS_BLK_SIZE, 0,
789 rtas_block_ctor); 783 NULL);
790 if (!flash_block_cache) { 784 if (!flash_block_cache) {
791 printk(KERN_ERR "%s: failed to create block cache\n", 785 printk(KERN_ERR "%s: failed to create block cache\n",
792 __func__); 786 __func__);