From 2ea481193c1654c9cb42aa0331cdbc4570783e26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibaut=20VAR=C3=88NE?= Date: Sat, 16 May 2020 17:12:06 +0200 Subject: [PATCH] generic: platform/mikrotik: fix LZOR support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 31e99fe3da which introduced this code was unfortunately untested. This commit fixes a number of issues and works around the fact that in this particular scheme, the LZO payload may be padded at the end which will trigger a harmless lzo decompression error. This commit also disambiguates the debug printks. Tested-by: Robert Marko Signed-off-by: Thibaut VARĂˆNE Fixes: 31e99fe3da ("generic: platform/mikrotik: support LZOR encoding") --- .../drivers/platform/mikrotik/rb_hardconfig.c | 57 ++++++++++++------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.c b/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.c index 26218d6a7d..93c731a5f0 100644 --- a/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.c +++ b/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.c @@ -36,7 +36,7 @@ #include "routerboot.h" -#define RB_HARDCONFIG_VER "0.02" +#define RB_HARDCONFIG_VER "0.03" #define RB_HC_PR_PFX "[rb_hardconfig] " /* ID values for hardware settings */ @@ -484,16 +484,18 @@ static int hc_wlan_data_unpack_lzor(const u8 *inbuf, size_t inlen, void *outbuf, size_t *outlen) { u16 rle_ofs, rle_len; - size_t templen; + const u32 *needle; u8 *tempbuf; + size_t templen, lzo_len; int ret; - templen = inlen + sizeof(hc_lzor_prefix); - if (templen > *outlen) + lzo_len = inlen + sizeof(hc_lzor_prefix); + if (lzo_len > *outlen) return -EFBIG; /* Temporary buffer same size as the outbuf */ - tempbuf = kmalloc(*outlen, GFP_KERNEL); + templen = *outlen; + tempbuf = kmalloc(templen, GFP_KERNEL); if (!outbuf) return -ENOMEM; @@ -501,41 +503,54 @@ static int hc_wlan_data_unpack_lzor(const u8 *inbuf, size_t inlen, memcpy(outbuf, hc_lzor_prefix, sizeof(hc_lzor_prefix)); memcpy(outbuf + sizeof(hc_lzor_prefix), inbuf, inlen); - /* LZO-decompress templen bytes of outbuf into the tempbuf */ - ret = lzo1x_decompress_safe(outbuf, templen, tempbuf, outlen); + /* LZO-decompress lzo_len bytes of outbuf into the tempbuf */ + ret = lzo1x_decompress_safe(outbuf, lzo_len, tempbuf, &templen); if (ret) { - pr_debug(RB_HC_PR_PFX "LZO decompression error (%d)\n", ret); - goto fail; + if (LZO_E_INPUT_NOT_CONSUMED == ret) { + /* + * It is assumed that because the LZO payload is embedded + * in a "root" RB_ID_WLAN_DATA tag, the tag length is aligned + * and the payload is padded at the end, which triggers a + * spurious error which we ignore here. + */ + pr_debug(RB_HC_PR_PFX "LZOR: LZO EOF before buffer end - this may be harmless\n"); + } else { + pr_debug(RB_HC_PR_PFX "LZOR: LZO decompression error (%d)\n", ret); + goto fail; + } } - templen = *outlen; /* * Post decompression we have a blob (possibly byproduct of the lzo * dictionary). We need to find RB_MAGIC_ERD. The magic number seems to * be 32bit-aligned in the decompression output. */ - - while (RB_MAGIC_ERD != *(u32 *)tempbuf) { - tempbuf += 4; - templen -= 4; - } + needle = (const u32 *)tempbuf; + while (RB_MAGIC_ERD != *needle++) { + if ((u8 *)needle >= tempbuf+templen) { + pr_debug(RB_HC_PR_PFX "LZOR: ERD magic not found\n"); + goto fail; + } + }; + templen -= (u8 *)needle - tempbuf; /* Past magic. Look for tag node */ - ret = routerboot_tag_find(tempbuf, templen, 0x1, &rle_ofs, &rle_len); + ret = routerboot_tag_find((u8 *)needle, templen, 0x1, &rle_ofs, &rle_len); if (ret) { - pr_debug(RB_HC_PR_PFX "RLE data not found\n"); + pr_debug(RB_HC_PR_PFX "LZOR: RLE data not found\n"); goto fail; } if (rle_len > templen) { - pr_debug(RB_HC_PR_PFX "Invalid RLE data length\n"); + pr_debug(RB_HC_PR_PFX "LZOR: Invalid RLE data length\n"); + ret = -EINVAL; goto fail; } - /* RLE-decode tempbuf back into the outbuf */ - ret = routerboot_rle_decode(tempbuf+rle_ofs, rle_len, outbuf, outlen); + /* RLE-decode tempbuf from needle back into the outbuf */ + ret = routerboot_rle_decode((u8 *)needle+rle_ofs, rle_len, outbuf, outlen); if (ret) - pr_debug(RB_HC_PR_PFX "RLE decoding error (%d)\n", ret); + pr_debug(RB_HC_PR_PFX "LZOR: RLE decoding error (%d)\n", ret); fail: kfree(tempbuf);