Commit 1a214ee6 authored by David Woodhouse's avatar David Woodhouse

Fix use-after-free bug in MTD partitioning code.

Define callback wrapper function mtd_erase_callback() to handle 
partition offsets during the callback, rather than attempting to 
fix them up in the freed erase_info structure after the callback 
has already happened.
parent 4ab06c9a
# $Id: Kconfig,v 1.5 2004/06/04 15:59:32 gleixner Exp $
# $Id: Kconfig,v 1.6 2004/08/09 13:19:42 dwmw2 Exp $
menu "Memory Technology Devices (MTD)"
......@@ -28,7 +28,7 @@ config MTD_DEBUG_VERBOSE
Determines the verbosity level of the MTD debugging messages.
config MTD_PARTITIONS
tristate "MTD partitioning support"
bool "MTD partitioning support"
depends on MTD
help
If you have a device which needs to divide its flash chip(s) up
......
#
# Makefile for the memory technology device drivers.
#
# $Id: Makefile.common,v 1.3 2004/07/12 16:07:30 dwmw2 Exp $
# $Id: Makefile.common,v 1.4 2004/08/09 13:19:42 dwmw2 Exp $
# Core functionality.
obj-$(CONFIG_MTD) += mtdcore.o
mtd-y := mtdcore.o
mtd-$(CONFIG_MTD_PARTITIONS) += mtdpart.o
obj-$(CONFIG_MTD) += $(mtd-y)
obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o
obj-$(CONFIG_MTD_PARTITIONS) += mtdpart.o
obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
......
......@@ -3,7 +3,7 @@
*
* Author: Jonas Holmberg <jonas.holmberg@axis.com>
*
* $Id: amd_flash.c,v 1.24 2004/07/12 13:34:30 dwmw2 Exp $
* $Id: amd_flash.c,v 1.25 2004/08/09 13:19:43 dwmw2 Exp $
*
* Copyright (c) 2001 Axis Communications AB
*
......@@ -1307,9 +1307,7 @@ static int amd_flash_erase(struct mtd_info *mtd, struct erase_info *instr)
}
instr->state = MTD_ERASE_DONE;
if (instr->callback) {
instr->callback(instr);
}
mtd_erase_callback(instr);
return 0;
}
......
......@@ -4,7 +4,7 @@
*
* (C) 2000 Red Hat. GPL'd
*
* $Id: cfi_cmdset_0001.c,v 1.153 2004/07/12 21:52:20 dwmw2 Exp $
* $Id: cfi_cmdset_0001.c,v 1.154 2004/08/09 13:19:43 dwmw2 Exp $
*
*
* 10/10/2000 Nicolas Pitre <nico@cam.org>
......@@ -1554,8 +1554,7 @@ int cfi_intelext_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
return ret;
instr->state = MTD_ERASE_DONE;
if (instr->callback)
instr->callback(instr);
mtd_erase_callback(instr);
return 0;
}
......
......@@ -13,7 +13,7 @@
*
* This code is GPL
*
* $Id: cfi_cmdset_0002.c,v 1.103 2004/07/14 16:24:03 dwmw2 Exp $
* $Id: cfi_cmdset_0002.c,v 1.106 2004/08/09 14:02:32 dwmw2 Exp $
*
*/
......@@ -1420,8 +1420,7 @@ int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
return ret;
instr->state = MTD_ERASE_DONE;
if (instr->callback)
instr->callback(instr);
mtd_erase_callback(instr);
return 0;
}
......@@ -1444,8 +1443,7 @@ static int cfi_amdstd_erase_chip(struct mtd_info *mtd, struct erase_info *instr)
return ret;
instr->state = MTD_ERASE_DONE;
if (instr->callback)
instr->callback(instr);
mtd_erase_callback(instr);
return 0;
}
......
......@@ -4,7 +4,7 @@
*
* (C) 2000 Red Hat. GPL'd
*
* $Id: cfi_cmdset_0020.c,v 1.14 2004/07/20 02:44:25 dwmw2 Exp $
* $Id: cfi_cmdset_0020.c,v 1.15 2004/08/09 13:19:43 dwmw2 Exp $
*
* 10/10/2000 Nicolas Pitre <nico@cam.org>
* - completely revamped method functions so they are aware and
......@@ -966,8 +966,7 @@ int cfi_staa_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
}
instr->state = MTD_ERASE_DONE;
if (instr->callback)
instr->callback(instr);
mtd_erase_callback(instr);
return 0;
}
......
......@@ -11,7 +11,7 @@
* not going to guess how to send commands to them, plus I expect they will
* all speak CFI..
*
* $Id: jedec.c,v 1.20 2004/07/12 14:03:01 dwmw2 Exp $
* $Id: jedec.c,v 1.21 2004/08/09 13:19:43 dwmw2 Exp $
*/
#include <linux/init.h>
......@@ -780,8 +780,7 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr)
//printk("done\n");
instr->state = MTD_ERASE_DONE;
if (instr->callback)
instr->callback(instr);
mtd_erase_callback(instr);
return 0;
#undef flread
......
/*
* Common code to handle map devices which are simple RAM
* (C) 2000 Red Hat. GPL'd.
* $Id: map_ram.c,v 1.19 2004/07/12 21:58:44 dwmw2 Exp $
* $Id: map_ram.c,v 1.20 2004/08/09 13:19:43 dwmw2 Exp $
*/
#include <linux/module.h>
......@@ -114,8 +114,7 @@ static int mapram_erase (struct mtd_info *mtd, struct erase_info *instr)
instr->state = MTD_ERASE_DONE;
if (instr->callback)
instr->callback(instr);
mtd_erase_callback(instr);
return 0;
}
......
......@@ -4,7 +4,7 @@
* Copyright 2000,2001 David A. Schleef <ds@schleef.org>
* 2000,2001 Lineo, Inc.
*
* $Id: sharp.c,v 1.13 2004/07/12 14:06:34 dwmw2 Exp $
* $Id: sharp.c,v 1.14 2004/08/09 13:19:43 dwmw2 Exp $
*
* Devices supported:
* LH28F016SCT Symmetrical block flash memory, 2Mx8
......@@ -425,8 +425,7 @@ static int sharp_erase(struct mtd_info *mtd, struct erase_info *instr)
}
instr->state = MTD_ERASE_DONE;
if(instr->callback)
instr->callback(instr);
mtd_erase_callback(instr);
return 0;
}
......
/*
* $Id: blkmtd-25.c,v 1.6 2004/07/15 15:09:15 dwmw2 Exp $
* $Id: blkmtd.c,v 1.23 2004/08/09 14:03:19 dwmw2 Exp $
*
* blkmtd.c - use a block device as a fake MTD
*
......@@ -39,7 +39,7 @@
/* Default erase size in K, always make it a multiple of PAGE_SIZE */
#define CONFIG_MTD_BLKDEV_ERASESIZE (128 << 10) /* 128KiB */
#define VERSION "$Revision: 1.6 $"
#define VERSION "$Revision: 1.23 $"
/* Info for the block device */
struct blkmtd_dev {
......@@ -435,9 +435,7 @@ static int blkmtd_erase(struct mtd_info *mtd, struct erase_info *instr)
}
DEBUG(3, "blkmtd: erase: checking callback\n");
if (instr->callback) {
(*(instr->callback))(instr);
}
mtd_erase_callback(instr);
DEBUG(2, "blkmtd: erase: finished (err = %d)\n", err);
return err;
}
......
......@@ -4,7 +4,7 @@
* (c) 1999 Machine Vision Holdings, Inc.
* (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
*
* $Id: doc2000.c,v 1.60 2004/04/07 08:30:04 gleixner Exp $
* $Id: doc2000.c,v 1.62 2004/08/09 14:04:02 dwmw2 Exp $
*/
#include <linux/kernel.h>
......@@ -1277,8 +1277,7 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *instr)
instr->state = MTD_ERASE_DONE;
callback:
if (instr->callback)
instr->callback(instr);
mtd_erase_callback(instr);
up(&this->lock);
return 0;
......
......@@ -4,7 +4,7 @@
* (c) 1999 Machine Vision Holdings, Inc.
* (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
*
* $Id: doc2001.c,v 1.42 2004/04/04 12:36:45 gleixner Exp $
* $Id: doc2001.c,v 1.44 2004/08/09 14:04:24 dwmw2 Exp $
*/
#include <linux/kernel.h>
......@@ -845,8 +845,7 @@ int doc_erase (struct mtd_info *mtd, struct erase_info *instr)
instr->state = MTD_ERASE_DONE;
dummy = ReadDOC(docptr, LastDataRead);
if (instr->callback)
instr->callback(instr);
mtd_erase_callback(instr);
return 0;
}
......
......@@ -6,7 +6,7 @@
* (c) 1999 Machine Vision Holdings, Inc.
* (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
*
* $Id: doc2001plus.c,v 1.8 2004/04/04 12:36:45 gleixner Exp $
* $Id: doc2001plus.c,v 1.9 2004/08/09 13:19:44 dwmw2 Exp $
*
* Released under GPL
*/
......@@ -1111,8 +1111,7 @@ int doc_erase(struct mtd_info *mtd, struct erase_info *instr)
/* Disable flash internally */
WriteDOC(0, docptr, Mplus_FlashSelect);
if (instr->callback)
instr->callback(instr);
mtd_erase_callback(instr);
return 0;
}
......
......@@ -2,7 +2,7 @@
/*
* MTD driver for the 28F160F3 Flash Memory (non-CFI) on LART.
*
* $Id: lart.c,v 1.6 2004/07/14 17:21:38 dwmw2 Exp $
* $Id: lart.c,v 1.7 2004/08/09 13:19:44 dwmw2 Exp $
*
* Author: Abraham vd Merwe <abraham@2d3d.co.za>
*
......@@ -433,7 +433,7 @@ static int flash_erase (struct mtd_info *mtd,struct erase_info *instr)
}
instr->state = MTD_ERASE_DONE;
if (instr->callback) instr->callback (instr);
mtd_erase_callback(instr);
return (0);
}
......
/*
* mtdram - a test mtd device
* $Id: mtdram.c,v 1.32 2003/05/21 15:15:07 dwmw2 Exp $
* $Id: mtdram.c,v 1.33 2004/08/09 13:19:44 dwmw2 Exp $
* Author: Alexander Larsson <alex@cendio.se>
*
* Copyright (c) 1999 Alexander Larsson <alex@cendio.se>
......@@ -57,9 +57,8 @@ ram_erase(struct mtd_info *mtd, struct erase_info *instr)
memset((char *)mtd->priv + instr->addr, 0xff, instr->len);
instr->state = MTD_ERASE_DONE;
mtd_erase_callback(instr);
if (instr->callback)
(*(instr->callback))(instr);
return 0;
}
......
/**
*
* $Id: phram.c,v 1.1 2003/08/21 17:52:30 joern Exp $
* $Id: phram.c,v 1.2 2004/08/09 13:19:44 dwmw2 Exp $
*
* Copyright (c) Jochen Schaeuble <psionic@psionic.de>
* 07/2003 rewritten by Joern Engel <joern@wh.fh-wedel.de>
......@@ -55,10 +55,7 @@ int phram_erase(struct mtd_info *mtd, struct erase_info *instr)
instr->state = MTD_ERASE_DONE;
if (instr->callback)
(*(instr->callback))(instr);
else
kfree(instr);
mtd_erase_callback(instr);
return 0;
}
......
/*
* $Id: pmc551.c,v 1.27 2004/07/20 02:44:26 dwmw2 Exp $
* $Id: pmc551.c,v 1.28 2004/08/09 13:19:44 dwmw2 Exp $
*
* PMC551 PCI Mezzanine Ram Device
*
......@@ -169,9 +169,7 @@ static int pmc551_erase (struct mtd_info *mtd, struct erase_info *instr)
printk(KERN_DEBUG "pmc551_erase() done\n");
#endif
if (instr->callback) {
(*(instr->callback))(instr);
}
mtd_erase_callback(instr);
return 0;
}
......
/*======================================================================
$Id: slram.c,v 1.30 2003/05/20 21:03:08 dwmw2 Exp $
$Id: slram.c,v 1.31 2004/08/09 13:19:44 dwmw2 Exp $
This driver provides a method to access memory not used by the kernel
itself (i.e. if the kernel commandline mem=xxx is used). To actually
......@@ -98,12 +98,7 @@ int slram_erase(struct mtd_info *mtd, struct erase_info *instr)
instr->state = MTD_ERASE_DONE;
if (instr->callback) {
(*(instr->callback))(instr);
}
else {
kfree(instr);
}
mtd_erase_callback(instr);
return(0);
}
......
/*
* $Id: mtdchar.c,v 1.62 2004/07/14 13:20:42 dwmw2 Exp $
* $Id: mtdchar.c,v 1.64 2004/08/09 13:59:46 dwmw2 Exp $
*
* Character-device access to raw MTD devices.
*
......@@ -262,7 +262,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count
IOCTL calls for getting device parameters.
======================================================================*/
static void mtd_erase_callback (struct erase_info *instr)
static void mtdchar_erase_callback (struct erase_info *instr)
{
wake_up((wait_queue_head_t *)instr->priv);
}
......@@ -336,7 +336,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
return -EFAULT;
}
erase->mtd = mtd;
erase->callback = mtd_erase_callback;
erase->callback = mtdchar_erase_callback;
erase->priv = (unsigned long)&waitq;
/*
......@@ -511,7 +511,6 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
}
default:
DEBUG(MTD_DEBUG_LEVEL0, "Invalid ioctl %x (MEMGETINFO = %lx)\n", cmd, (unsigned long)MEMGETINFO);
ret = -ENOTTY;
}
......
......@@ -5,7 +5,7 @@
*
* This code is GPL
*
* $Id: mtdpart.c,v 1.46 2004/07/12 13:28:07 dwmw2 Exp $
* $Id: mtdpart.c,v 1.49 2004/08/10 13:41:27 dwmw2 Exp $
*
* 02-21-2002 Thomas Gleixner <gleixner@autronix.de>
* added support for read_oob, write_oob
......@@ -246,11 +246,22 @@ static int part_erase (struct mtd_info *mtd, struct erase_info *instr)
return -EINVAL;
instr->addr += part->offset;
ret = part->master->erase(part->master, instr);
if (instr->fail_addr != 0xffffffff)
instr->fail_addr -= part->offset;
return ret;
}
void mtd_erase_callback(struct erase_info *instr)
{
if (instr->mtd->erase == part_erase) {
struct mtd_part *part = PART(instr->mtd);
if (instr->fail_addr != 0xffffffff)
instr->fail_addr -= part->offset;
instr->addr -= part->offset;
}
if (instr->callback)
instr->callback(instr);
}
static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
{
struct mtd_part *part = PART(mtd);
......
......@@ -37,7 +37,7 @@
* The AG-AND chips have nice features for speed improvement,
* which are not supported yet. Read / program 4 pages in one go.
*
* $Id: nand_base.c,v 1.113 2004/07/14 16:31:31 gleixner Exp $
* $Id: nand_base.c,v 1.115 2004/08/09 13:19:45 dwmw2 Exp $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
......@@ -58,7 +58,7 @@
#include <linux/bitops.h>
#include <asm/io.h>
#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
#ifdef CONFIG_MTD_PARTITIONS
#include <linux/mtd/partitions.h>
#endif
......@@ -1284,12 +1284,12 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
nand_release_chip(mtd);
/*
* Return success, if no ECC failures, else -EIO
* Return success, if no ECC failures, else -EBADMSG
* fs driver will take care of that, because
* retlen == desired len and result == -EIO
* retlen == desired len and result == -EBADMSG
*/
*retlen = read;
return ecc_failed ? -EIO : 0;
return ecc_failed ? -EBADMSG : 0;
}
/**
......@@ -2108,8 +2108,8 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb
ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
/* Do call back function */
if (!ret && instr->callback)
instr->callback (instr);
if (!ret)
mtd_erase_callback(instr);
/* Deselect and wake up anyone waiting on the device */
nand_release_chip(mtd);
......@@ -2555,11 +2555,11 @@ void nand_release (struct mtd_info *mtd)
{
struct nand_chip *this = mtd->priv;
#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
/* Unregister partitions */
#ifdef CONFIG_MTD_PARTITIONS
/* Deregister partitions */
del_mtd_partitions (mtd);
#endif
/* Unregister the device */
/* Deregister the device */
del_mtd_device (mtd);
/* Free bad block table memory, if allocated */
......
/*
* $Id: mtd.h,v 1.54 2004/07/15 01:13:12 dwmw2 Exp $
* $Id: mtd.h,v 1.56 2004/08/09 18:46:04 dmarlin Exp $
*
* Copyright (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> et al.
*
......@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/uio.h>
#include <linux/mtd/compatmac.h>
#include <mtd/mtd-abi.h>
#define MTD_CHAR_MAJOR 90
......@@ -192,6 +193,17 @@ int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs,
#define MTD_WRITEOOB(mtd, args...) (*(mtd->write_oob))(mtd, args)
#define MTD_SYNC(mtd) do { if (mtd->sync) (*(mtd->sync))(mtd); } while (0)
#ifdef CONFIG_MTD_PARTITIONS
void mtd_erase_callback(struct erase_info *instr);
#else
static inline void mtd_erase_callback(struct erase_info *instr)
{
if (instr->callback)
instr->callback(instr);
}
#endif
/*
* Debugging macro and defines
*/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment