]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
dm verity fec: limit error correction recursion
authorSami Tolvanen <samitolvanen@google.com>
Wed, 15 Mar 2017 22:12:23 +0000 (15:12 -0700)
committerMike Snitzer <snitzer@redhat.com>
Thu, 16 Mar 2017 13:37:31 +0000 (09:37 -0400)
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+
drivers/md/dm-verity-fec.c
drivers/md/dm-verity-fec.h

index 0f0eb8a3d922a212583ba491f3899a69a2b91bd6..c3cc04d89524c6263d316aeec1611f70eccad0e1 100644 (file)
@@ -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;
 }
 
 /*
index 7fa0298b995e9e3f1ac25c2356c758fad8b65d34..bb31ce87a933b80d11140f31607f804ff81d209a 100644 (file)
@@ -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