diff options
author | Thibaut VARÈNE <hacks@slashdirt.org> | 2020-05-16 17:12:06 +0200 |
---|---|---|
committer | Hauke Mehrtens <hauke@hauke-m.de> | 2020-05-16 20:32:20 +0200 |
commit | 85e04e9f46bf68a8a35e2578ea4083cbf44f12f6 (patch) | |
tree | 04b3c0cecd15b0299b3d59841a0f096da744713a /target/linux/generic | |
parent | 4cd9ae41c5f7fd4de6d9a2970f8243c9555428a7 (diff) | |
download | upstream-85e04e9f46bf68a8a35e2578ea4083cbf44f12f6.tar.gz upstream-85e04e9f46bf68a8a35e2578ea4083cbf44f12f6.tar.bz2 upstream-85e04e9f46bf68a8a35e2578ea4083cbf44f12f6.zip |
generic: platform/mikrotik: fix LZOR support
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 <robimarko@gmail.com>
Signed-off-by: Thibaut VARÈNE <hacks@slashdirt.org>
Fixes: 31e99fe3da ("generic: platform/mikrotik: support LZOR encoding")
(cherry picked from commit 2ea481193c1654c9cb42aa0331cdbc4570783e26)
Diffstat (limited to 'target/linux/generic')
-rw-r--r-- | target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.c | 57 |
1 files 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 ab78037a03..e5257b9212 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 */ @@ -483,16 +483,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; @@ -500,41 +502,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); |