diff options
author | Mikulas Patocka <mpatocka@redhat.com> | 2013-10-21 12:59:30 +0100 |
---|---|---|
committer | Willy Tarreau <w@1wt.eu> | 2014-05-19 07:54:31 +0200 |
commit | 1b3b362f84f5f2dd62d180447ba1a1681f5d993a (patch) | |
tree | d9e2346803c089256aadc1f5ffc9e3d5cf088a54 | |
parent | 74fbc288d30a6da65187bded5834f36097fd738e (diff) | |
download | lwn-1b3b362f84f5f2dd62d180447ba1a1681f5d993a.tar.gz lwn-1b3b362f84f5f2dd62d180447ba1a1681f5d993a.zip |
dm snapshot: fix data corruption
CVE-2013-4299
BugLink: http://bugs.launchpad.net/bugs/1241769
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: stable@vger.kernel.org
Cc: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
(back ported from commit e9c6a182649f4259db704ae15a91ac820e63b0ca)
Signed-off-by: Luis Henriques <luis.henriques@canonical.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
Signed-off-by: Willy Tarreau <w@1wt.eu>
-rw-r--r-- | drivers/md/dm-snap-persistent.c | 18 |
1 files changed, 12 insertions, 6 deletions
diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c index 0c746420c008..97c3f0651c41 100644 --- a/drivers/md/dm-snap-persistent.c +++ b/drivers/md/dm-snap-persistent.c @@ -252,6 +252,14 @@ static chunk_t area_location(struct pstore *ps, chunk_t area) return 1 + ((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) == 1) + ps->next_free++; +} + /* * Read or write a metadata area. Remembering to skip the first * chunk which holds the header. @@ -481,6 +489,8 @@ static int read_exceptions(struct pstore *ps, ps->current_area--; + skip_metadata(ps); + return 0; } @@ -587,8 +597,6 @@ static int persistent_prepare_exception(struct dm_exception_store *store, struct dm_snap_exception *e) { struct pstore *ps = get_info(store); - uint32_t stride; - chunk_t next_free; sector_t size = get_dev_size(store->cow->bdev); /* Is there enough room ? */ @@ -601,10 +609,8 @@ static int persistent_prepare_exception(struct dm_exception_store *store, * 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; |