diff options
author | Sami Tolvanen <samitolvanen@google.com> | 2016-06-03 14:06:14 -0700 |
---|---|---|
committer | Mattias Nissler <mnissler@google.com> | 2016-07-20 16:18:34 +0200 |
commit | ef5deaaf00a763bc88c4897b888cf5c6146deaf8 (patch) | |
tree | 126753d8a84d1643b2cf34fe4e7be56aeb2c0673 | |
parent | 2e15952a83595336cbab6178307e27b33341bbf0 (diff) | |
download | v4.4-ef5deaaf00a763bc88c4897b888cf5c6146deaf8.tar.gz |
ANDROID: dm verity fec: limit error correction recursion
If verity tree itself is sufficiently corrupted in addition to data
blocks, it's possible for error correction to end up in a deep recursive
error correction loop that eventually causes a kernel panic as follows:
[ 14.728962] [<ffffffc0008c1a14>] verity_fec_decode+0xa8/0x138
[ 14.734691] [<ffffffc0008c3ee0>] verity_verify_level+0x11c/0x180
[ 14.740681] [<ffffffc0008c482c>] verity_hash_for_block+0x88/0xe0
[ 14.746671] [<ffffffc0008c1508>] fec_decode_rsb+0x318/0x75c
[ 14.752226] [<ffffffc0008c1a14>] verity_fec_decode+0xa8/0x138
[ 14.757956] [<ffffffc0008c3ee0>] verity_verify_level+0x11c/0x180
[ 14.763944] [<ffffffc0008c482c>] verity_hash_for_block+0x88/0xe0
This change limits the recursion to a reasonable level during a single
I/O operation.
Contains subsequent fix:
Sami Tolvanen <samitolvanen@google.com>:
ANDROID: dm verity fec: initialize recursion level
Signed-off-by: Sami Tolvanen <samitolvanen@google.com>
Bug: 28943429
Patchset: dm-verity
Signed-off-by: Mattias Nissler <mnissler@google.com>
Change-Id: I42d0871f9deb401e05e5985117735dc1f68c5c38
-rw-r--r-- | drivers/md/dm-verity-fec.c | 12 | ||||
-rw-r--r-- | drivers/md/dm-verity-fec.h | 4 |
2 files changed, 15 insertions, 1 deletions
diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c index d77560b79f56..d1a87bf7583d 100644 --- a/drivers/md/dm-verity-fec.c +++ b/drivers/md/dm-verity-fec.c @@ -442,6 +442,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; @@ -475,7 +482,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) @@ -485,6 +492,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; } @@ -525,6 +534,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 8c4bee052a73..b8e21cef3ad1 100644 --- a/drivers/md/dm-verity-fec.h +++ b/drivers/md/dm-verity-fec.h @@ -28,6 +28,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" @@ -61,6 +64,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 |