aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2018-10-11 07:06:17 -0400
committerBoris Brezillon <boris.brezillon@bootlin.com>2018-10-12 03:17:46 -0400
commitf0fe77f601c3d6a821198f88f7adb0a05b8fe03e (patch)
tree39bf89a0fa0faad1bfc759e5bf3cd4ef4765ca0d
parent0238df646e6224016a45505d2c111a24669ebe21 (diff)
lib/bch: fix possible stack overrun
The previous patch introduced very large kernel stack usage and a Makefile change to hide the warning about it. From what I can tell, a number of things went wrong here: - The BCH_MAX_T constant was set to the maximum value for 'n', not the maximum for 't', which is much smaller. - The stack usage is actually larger than the entire kernel stack on some architectures that can use 4KB stacks (m68k, sh, c6x), which leads to an immediate overrun. - The justification in the patch description claimed that nothing changed, however that is not the case even without the two points above: the configuration is machine specific, and most boards never use the maximum BCH_ECC_WORDS() length but instead have something much smaller. That maximum would only apply to machines that use both the maximum block size and the maximum ECC strength. The largest value for 't' that I could find is '32', which in turn leads to a 60 byte array instead of 2048 bytes. Making it '64' for future extension seems also worthwhile, with 120 bytes for the array. Anything larger won't fit into the OOB area on NAND flash. With that changed, the warning can be enabled again. Only linux-4.19+ contains the breakage, so this is only needed as a stable backport if it does not make it into the release. Fixes: 02361bc77888 ("lib/bch: Remove VLA usage") Reported-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Cc: stable@vger.kernel.org Signed-off-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
-rw-r--r--lib/Makefile1
-rw-r--r--lib/bch.c17
2 files changed, 13 insertions, 5 deletions
diff --git a/lib/Makefile b/lib/Makefile
index ca3f7ebb900d..423876446810 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -119,7 +119,6 @@ obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate/
119obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate/ 119obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate/
120obj-$(CONFIG_REED_SOLOMON) += reed_solomon/ 120obj-$(CONFIG_REED_SOLOMON) += reed_solomon/
121obj-$(CONFIG_BCH) += bch.o 121obj-$(CONFIG_BCH) += bch.o
122CFLAGS_bch.o := $(call cc-option,-Wframe-larger-than=4500)
123obj-$(CONFIG_LZO_COMPRESS) += lzo/ 122obj-$(CONFIG_LZO_COMPRESS) += lzo/
124obj-$(CONFIG_LZO_DECOMPRESS) += lzo/ 123obj-$(CONFIG_LZO_DECOMPRESS) += lzo/
125obj-$(CONFIG_LZ4_COMPRESS) += lz4/ 124obj-$(CONFIG_LZ4_COMPRESS) += lz4/
diff --git a/lib/bch.c b/lib/bch.c
index 7b0f2006698b..5db6d3a4c8a6 100644
--- a/lib/bch.c
+++ b/lib/bch.c
@@ -79,20 +79,19 @@
79#define GF_T(_p) (CONFIG_BCH_CONST_T) 79#define GF_T(_p) (CONFIG_BCH_CONST_T)
80#define GF_N(_p) ((1 << (CONFIG_BCH_CONST_M))-1) 80#define GF_N(_p) ((1 << (CONFIG_BCH_CONST_M))-1)
81#define BCH_MAX_M (CONFIG_BCH_CONST_M) 81#define BCH_MAX_M (CONFIG_BCH_CONST_M)
82#define BCH_MAX_T (CONFIG_BCH_CONST_T)
82#else 83#else
83#define GF_M(_p) ((_p)->m) 84#define GF_M(_p) ((_p)->m)
84#define GF_T(_p) ((_p)->t) 85#define GF_T(_p) ((_p)->t)
85#define GF_N(_p) ((_p)->n) 86#define GF_N(_p) ((_p)->n)
86#define BCH_MAX_M 15 87#define BCH_MAX_M 15 /* 2KB */
88#define BCH_MAX_T 64 /* 64 bit correction */
87#endif 89#endif
88 90
89#define BCH_MAX_T (((1 << BCH_MAX_M) - 1) / BCH_MAX_M)
90
91#define BCH_ECC_WORDS(_p) DIV_ROUND_UP(GF_M(_p)*GF_T(_p), 32) 91#define BCH_ECC_WORDS(_p) DIV_ROUND_UP(GF_M(_p)*GF_T(_p), 32)
92#define BCH_ECC_BYTES(_p) DIV_ROUND_UP(GF_M(_p)*GF_T(_p), 8) 92#define BCH_ECC_BYTES(_p) DIV_ROUND_UP(GF_M(_p)*GF_T(_p), 8)
93 93
94#define BCH_ECC_MAX_WORDS DIV_ROUND_UP(BCH_MAX_M * BCH_MAX_T, 32) 94#define BCH_ECC_MAX_WORDS DIV_ROUND_UP(BCH_MAX_M * BCH_MAX_T, 32)
95#define BCH_ECC_MAX_BYTES DIV_ROUND_UP(BCH_MAX_M * BCH_MAX_T, 8)
96 95
97#ifndef dbg 96#ifndef dbg
98#define dbg(_fmt, args...) do {} while (0) 97#define dbg(_fmt, args...) do {} while (0)
@@ -202,6 +201,9 @@ void encode_bch(struct bch_control *bch, const uint8_t *data,
202 const uint32_t * const tab3 = tab2 + 256*(l+1); 201 const uint32_t * const tab3 = tab2 + 256*(l+1);
203 const uint32_t *pdata, *p0, *p1, *p2, *p3; 202 const uint32_t *pdata, *p0, *p1, *p2, *p3;
204 203
204 if (WARN_ON(r_bytes > sizeof(r)))
205 return;
206
205 if (ecc) { 207 if (ecc) {
206 /* load ecc parity bytes into internal 32-bit buffer */ 208 /* load ecc parity bytes into internal 32-bit buffer */
207 load_ecc8(bch, bch->ecc_buf, ecc); 209 load_ecc8(bch, bch->ecc_buf, ecc);
@@ -1285,6 +1287,13 @@ struct bch_control *init_bch(int m, int t, unsigned int prim_poly)
1285 */ 1287 */
1286 goto fail; 1288 goto fail;
1287 1289
1290 if (t > BCH_MAX_T)
1291 /*
1292 * we can support larger than 64 bits if necessary, at the
1293 * cost of higher stack usage.
1294 */
1295 goto fail;
1296
1288 /* sanity checks */ 1297 /* sanity checks */
1289 if ((t < 1) || (m*t >= ((1 << m)-1))) 1298 if ((t < 1) || (m*t >= ((1 << m)-1)))
1290 /* invalid t value */ 1299 /* invalid t value */