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")
This commit is contained in:
Thibaut VARÈNE 2020-05-16 17:12:06 +02:00 committed by Hauke Mehrtens
parent 78bebe680f
commit 2ea481193c

View File

@ -36,7 +36,7 @@
#include "routerboot.h" #include "routerboot.h"
#define RB_HARDCONFIG_VER "0.02" #define RB_HARDCONFIG_VER "0.03"
#define RB_HC_PR_PFX "[rb_hardconfig] " #define RB_HC_PR_PFX "[rb_hardconfig] "
/* ID values for hardware settings */ /* 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) void *outbuf, size_t *outlen)
{ {
u16 rle_ofs, rle_len; u16 rle_ofs, rle_len;
size_t templen; const u32 *needle;
u8 *tempbuf; u8 *tempbuf;
size_t templen, lzo_len;
int ret; int ret;
templen = inlen + sizeof(hc_lzor_prefix); lzo_len = inlen + sizeof(hc_lzor_prefix);
if (templen > *outlen) if (lzo_len > *outlen)
return -EFBIG; return -EFBIG;
/* Temporary buffer same size as the outbuf */ /* Temporary buffer same size as the outbuf */
tempbuf = kmalloc(*outlen, GFP_KERNEL); templen = *outlen;
tempbuf = kmalloc(templen, GFP_KERNEL);
if (!outbuf) if (!outbuf)
return -ENOMEM; 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, hc_lzor_prefix, sizeof(hc_lzor_prefix));
memcpy(outbuf + sizeof(hc_lzor_prefix), inbuf, inlen); memcpy(outbuf + sizeof(hc_lzor_prefix), inbuf, inlen);
/* LZO-decompress templen bytes of outbuf into the tempbuf */ /* LZO-decompress lzo_len bytes of outbuf into the tempbuf */
ret = lzo1x_decompress_safe(outbuf, templen, tempbuf, outlen); ret = lzo1x_decompress_safe(outbuf, lzo_len, tempbuf, &templen);
if (ret) { if (ret) {
pr_debug(RB_HC_PR_PFX "LZO decompression error (%d)\n", ret); if (LZO_E_INPUT_NOT_CONSUMED == ret) {
goto fail; /*
* 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 * Post decompression we have a blob (possibly byproduct of the lzo
* dictionary). We need to find RB_MAGIC_ERD. The magic number seems to * dictionary). We need to find RB_MAGIC_ERD. The magic number seems to
* be 32bit-aligned in the decompression output. * be 32bit-aligned in the decompression output.
*/ */
needle = (const u32 *)tempbuf;
while (RB_MAGIC_ERD != *(u32 *)tempbuf) { while (RB_MAGIC_ERD != *needle++) {
tempbuf += 4; if ((u8 *)needle >= tempbuf+templen) {
templen -= 4; pr_debug(RB_HC_PR_PFX "LZOR: ERD magic not found\n");
} goto fail;
}
};
templen -= (u8 *)needle - tempbuf;
/* Past magic. Look for tag node */ /* 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) { 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; goto fail;
} }
if (rle_len > templen) { 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; goto fail;
} }
/* RLE-decode tempbuf back into the outbuf */ /* RLE-decode tempbuf from needle back into the outbuf */
ret = routerboot_rle_decode(tempbuf+rle_ofs, rle_len, outbuf, outlen); ret = routerboot_rle_decode((u8 *)needle+rle_ofs, rle_len, outbuf, outlen);
if (ret) 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: fail:
kfree(tempbuf); kfree(tempbuf);