Commit f1a880a9 authored by Sami Tolvanen's avatar Sami Tolvanen Committed by Mike Snitzer

dm verity fec: limit error correction recursion

If the hash tree itself is sufficiently corrupt in addition to data blocks,
it's possible for error correction to end up in a deep recursive loop,
which eventually causes a kernel panic.  This change limits the
recursion to a reasonable level during a single I/O operation.

Fixes: a739ff3f ("dm verity: add support for forward error correction")
Signed-off-by: default avatarSami Tolvanen <samitolvanen@google.com>
Signed-off-by: default avatarMike Snitzer <snitzer@redhat.com>
Cc: stable@vger.kernel.org # v4.5+
parent 4495c08e
...@@ -439,6 +439,13 @@ int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io, ...@@ -439,6 +439,13 @@ int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io,
if (!verity_fec_is_enabled(v)) if (!verity_fec_is_enabled(v))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (fio->level >= DM_VERITY_FEC_MAX_RECURSION) {
DMWARN_LIMIT("%s: FEC: recursion too deep", v->data_dev->name);
return -EIO;
}
fio->level++;
if (type == DM_VERITY_BLOCK_TYPE_METADATA) if (type == DM_VERITY_BLOCK_TYPE_METADATA)
block += v->data_blocks; block += v->data_blocks;
...@@ -470,7 +477,7 @@ int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io, ...@@ -470,7 +477,7 @@ int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io,
if (r < 0) { if (r < 0) {
r = fec_decode_rsb(v, io, fio, rsb, offset, true); r = fec_decode_rsb(v, io, fio, rsb, offset, true);
if (r < 0) if (r < 0)
return r; goto done;
} }
if (dest) if (dest)
...@@ -480,6 +487,8 @@ int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io, ...@@ -480,6 +487,8 @@ int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io,
r = verity_for_bv_block(v, io, iter, fec_bv_copy); r = verity_for_bv_block(v, io, iter, fec_bv_copy);
} }
done:
fio->level--;
return r; return r;
} }
...@@ -520,6 +529,7 @@ void verity_fec_init_io(struct dm_verity_io *io) ...@@ -520,6 +529,7 @@ void verity_fec_init_io(struct dm_verity_io *io)
memset(fio->bufs, 0, sizeof(fio->bufs)); memset(fio->bufs, 0, sizeof(fio->bufs));
fio->nbufs = 0; fio->nbufs = 0;
fio->output = NULL; fio->output = NULL;
fio->level = 0;
} }
/* /*
......
...@@ -27,6 +27,9 @@ ...@@ -27,6 +27,9 @@
#define DM_VERITY_FEC_BUF_MAX \ #define DM_VERITY_FEC_BUF_MAX \
(1 << (PAGE_SHIFT - DM_VERITY_FEC_BUF_RS_BITS)) (1 << (PAGE_SHIFT - DM_VERITY_FEC_BUF_RS_BITS))
/* maximum recursion level for verity_fec_decode */
#define DM_VERITY_FEC_MAX_RECURSION 4
#define DM_VERITY_OPT_FEC_DEV "use_fec_from_device" #define DM_VERITY_OPT_FEC_DEV "use_fec_from_device"
#define DM_VERITY_OPT_FEC_BLOCKS "fec_blocks" #define DM_VERITY_OPT_FEC_BLOCKS "fec_blocks"
#define DM_VERITY_OPT_FEC_START "fec_start" #define DM_VERITY_OPT_FEC_START "fec_start"
...@@ -58,6 +61,7 @@ struct dm_verity_fec_io { ...@@ -58,6 +61,7 @@ struct dm_verity_fec_io {
unsigned nbufs; /* number of buffers allocated */ unsigned nbufs; /* number of buffers allocated */
u8 *output; /* buffer for corrected output */ u8 *output; /* buffer for corrected output */
size_t output_pos; size_t output_pos;
unsigned level; /* recursion level */
}; };
#ifdef CONFIG_DM_VERITY_FEC #ifdef CONFIG_DM_VERITY_FEC
......
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