89 lines
2.8 KiB
Diff
89 lines
2.8 KiB
Diff
From e9c6a182649f4259db704ae15a91ac820e63b0ca Mon Sep 17 00:00:00 2001
|
|
From: Mikulas Patocka <mpatocka@redhat.com>
|
|
Date: Wed, 16 Oct 2013 03:17:47 +0100
|
|
Subject: dm snapshot: fix data corruption
|
|
|
|
From: Mikulas Patocka <mpatocka@redhat.com>
|
|
|
|
commit e9c6a182649f4259db704ae15a91ac820e63b0ca upstream.
|
|
|
|
This patch fixes a particular type of data corruption that has been
|
|
encountered when loading a snapshot's metadata from disk.
|
|
|
|
When we allocate a new chunk in persistent_prepare, we increment
|
|
ps->next_free and we make sure that it doesn't point to a metadata area
|
|
by further incrementing it if necessary.
|
|
|
|
When we load metadata from disk on device activation, ps->next_free is
|
|
positioned after the last used data chunk. However, if this last used
|
|
data chunk is followed by a metadata area, ps->next_free is positioned
|
|
erroneously to the metadata area. A newly-allocated chunk is placed at
|
|
the same location as the metadata area, resulting in data or metadata
|
|
corruption.
|
|
|
|
This patch changes the code so that ps->next_free skips the metadata
|
|
area when metadata are loaded in function read_exceptions.
|
|
|
|
The patch also moves a piece of code from persistent_prepare_exception
|
|
to a separate function skip_metadata to avoid code duplication.
|
|
|
|
CVE-2013-4299
|
|
|
|
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
|
|
Cc: Mike Snitzer <snitzer@redhat.com>
|
|
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
|
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
|
|
|
---
|
|
drivers/md/dm-snap-persistent.c | 18 ++++++++++++------
|
|
1 file changed, 12 insertions(+), 6 deletions(-)
|
|
|
|
--- a/drivers/md/dm-snap-persistent.c
|
|
+++ b/drivers/md/dm-snap-persistent.c
|
|
@@ -269,6 +269,14 @@ static chunk_t area_location(struct psto
|
|
return NUM_SNAPSHOT_HDR_CHUNKS + ((ps->exceptions_per_area + 1) * area);
|
|
}
|
|
|
|
+static void skip_metadata(struct pstore *ps)
|
|
+{
|
|
+ uint32_t stride = ps->exceptions_per_area + 1;
|
|
+ chunk_t next_free = ps->next_free;
|
|
+ if (sector_div(next_free, stride) == NUM_SNAPSHOT_HDR_CHUNKS)
|
|
+ ps->next_free++;
|
|
+}
|
|
+
|
|
/*
|
|
* Read or write a metadata area. Remembering to skip the first
|
|
* chunk which holds the header.
|
|
@@ -502,6 +510,8 @@ static int read_exceptions(struct pstore
|
|
|
|
ps->current_area--;
|
|
|
|
+ skip_metadata(ps);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -616,8 +626,6 @@ static int persistent_prepare_exception(
|
|
struct dm_exception *e)
|
|
{
|
|
struct pstore *ps = get_info(store);
|
|
- uint32_t stride;
|
|
- chunk_t next_free;
|
|
sector_t size = get_dev_size(dm_snap_cow(store->snap)->bdev);
|
|
|
|
/* Is there enough room ? */
|
|
@@ -630,10 +638,8 @@ static int persistent_prepare_exception(
|
|
* Move onto the next free pending, making sure to take
|
|
* into account the location of the metadata chunks.
|
|
*/
|
|
- stride = (ps->exceptions_per_area + 1);
|
|
- next_free = ++ps->next_free;
|
|
- if (sector_div(next_free, stride) == 1)
|
|
- ps->next_free++;
|
|
+ ps->next_free++;
|
|
+ skip_metadata(ps);
|
|
|
|
atomic_inc(&ps->pending_count);
|
|
return 0;
|