| From 6b239cab7a48cf6dfa82218f909a45d57a530f4e Mon Sep 17 00:00:00 2001 |
| From: Sami Tolvanen <samitolvanen@google.com> |
| Date: Wed, 15 Mar 2017 15:12:23 -0700 |
| Subject: [PATCH] dm verity fec: limit error correction recursion |
| |
| commit f1a880a93baaadb14c10a348fd199f1cdb6bcccd upstream. |
| |
| 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: a739ff3f543a ("dm verity: add support for forward error correction") |
| Signed-off-by: Sami Tolvanen <samitolvanen@google.com> |
| Signed-off-by: Mike Snitzer <snitzer@redhat.com> |
| Cc: stable@vger.kernel.org # v4.5+ |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c |
| index 0f0eb8a3d922..c3cc04d89524 100644 |
| --- a/drivers/md/dm-verity-fec.c |
| +++ b/drivers/md/dm-verity-fec.c |
| @@ -439,6 +439,13 @@ int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io, |
| if (!verity_fec_is_enabled(v)) |
| 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) |
| block += v->data_blocks; |
| |
| @@ -470,7 +477,7 @@ int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io, |
| if (r < 0) { |
| r = fec_decode_rsb(v, io, fio, rsb, offset, true); |
| if (r < 0) |
| - return r; |
| + goto done; |
| } |
| |
| if (dest) |
| @@ -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); |
| } |
| |
| +done: |
| + fio->level--; |
| return r; |
| } |
| |
| @@ -520,6 +529,7 @@ void verity_fec_init_io(struct dm_verity_io *io) |
| memset(fio->bufs, 0, sizeof(fio->bufs)); |
| fio->nbufs = 0; |
| fio->output = NULL; |
| + fio->level = 0; |
| } |
| |
| /* |
| diff --git a/drivers/md/dm-verity-fec.h b/drivers/md/dm-verity-fec.h |
| index 7fa0298b995e..bb31ce87a933 100644 |
| --- a/drivers/md/dm-verity-fec.h |
| +++ b/drivers/md/dm-verity-fec.h |
| @@ -27,6 +27,9 @@ |
| #define DM_VERITY_FEC_BUF_MAX \ |
| (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_BLOCKS "fec_blocks" |
| #define DM_VERITY_OPT_FEC_START "fec_start" |
| @@ -58,6 +61,7 @@ struct dm_verity_fec_io { |
| unsigned nbufs; /* number of buffers allocated */ |
| u8 *output; /* buffer for corrected output */ |
| size_t output_pos; |
| + unsigned level; /* recursion level */ |
| }; |
| |
| #ifdef CONFIG_DM_VERITY_FEC |
| -- |
| 2.12.0 |
| |