diff options
Diffstat (limited to 'package')
17 files changed, 1097 insertions, 1 deletions
diff --git a/package/libs/libubox/Makefile b/package/libs/libubox/Makefile index a0e75f936c..f5a1f12f22 100644 --- a/package/libs/libubox/Makefile +++ b/package/libs/libubox/Makefile @@ -1,7 +1,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=libubox -PKG_RELEASE=2 +PKG_RELEASE=3 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=$(PROJECT_GIT)/project/libubox.git diff --git a/package/libs/libubox/patches/0001-blobmsg_json-fix-possible-uninitialized-struct-membe.patch b/package/libs/libubox/patches/0001-blobmsg_json-fix-possible-uninitialized-struct-membe.patch new file mode 100644 index 0000000000..bb0138f2d4 --- /dev/null +++ b/package/libs/libubox/patches/0001-blobmsg_json-fix-possible-uninitialized-struct-membe.patch @@ -0,0 +1,39 @@ +From 2acfe84e4c871fb994c38c9f2508eb9ebd296b74 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz> +Date: Tue, 19 Nov 2019 17:34:25 +0100 +Subject: blobmsg_json: fix possible uninitialized struct member +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +clang-10 analyzer reports following: + + blobmsg_json.c:285:2: warning: The expression is an uninitialized value. The computed value will also be garbage + s->indent_level++; + ^~~~~~~~~~~~~~~~~ + +Signed-off-by: Petr Štetiar <ynezz@true.cz> +--- + blobmsg_json.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/blobmsg_json.c ++++ b/blobmsg_json.c +@@ -316,7 +316,7 @@ static void setup_strbuf(struct strbuf * + + char *blobmsg_format_json_with_cb(struct blob_attr *attr, bool list, blobmsg_json_format_t cb, void *priv, int indent) + { +- struct strbuf s; ++ struct strbuf s = {0}; + bool array; + char *ret; + +@@ -350,7 +350,7 @@ char *blobmsg_format_json_with_cb(struct + + char *blobmsg_format_json_value_with_cb(struct blob_attr *attr, blobmsg_json_format_t cb, void *priv, int indent) + { +- struct strbuf s; ++ struct strbuf s = {0}; + char *ret; + + setup_strbuf(&s, attr, cb, priv, indent); diff --git a/package/libs/libubox/patches/0002-jshn-fix-off-by-one-in-jshn_parse_file.patch b/package/libs/libubox/patches/0002-jshn-fix-off-by-one-in-jshn_parse_file.patch new file mode 100644 index 0000000000..17a045f261 --- /dev/null +++ b/package/libs/libubox/patches/0002-jshn-fix-off-by-one-in-jshn_parse_file.patch @@ -0,0 +1,39 @@ +From f27853d71a2cb99ec5de3881716a14611ada307c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz> +Date: Sat, 23 Nov 2019 22:48:25 +0100 +Subject: jshn: fix off by one in jshn_parse_file +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fixes following error: + + Invalid read of size 1 + at 0x4C32D04: strlen + by 0x5043367: json_tokener_parse_ex + by 0x5045316: json_tokener_parse_verbose + by 0x504537D: json_tokener_parse + by 0x401AB1: jshn_parse (jshn.c:179) + by 0x40190D: jshn_parse_file (jshn.c:370) + by 0x40190D: main (jshn.c:434) + Address 0x5848c4c is 0 bytes after a block of size 1,036 alloc'd + at 0x4C2FB0F: malloc + by 0x4018E2: jshn_parse_file (jshn.c:357) + by 0x4018E2: main (jshn.c:434) + +Signed-off-by: Petr Štetiar <ynezz@true.cz> +--- + jshn.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/jshn.c ++++ b/jshn.c +@@ -384,7 +384,7 @@ int main(int argc, char **argv) + close(fd); + return 3; + } +- if (!(fbuf = malloc(sb.st_size))) { ++ if (!(fbuf = calloc(1, sb.st_size+1))) { + fprintf(stderr, "Error allocating memory for %s\n", optarg); + close(fd); + return 3; diff --git a/package/libs/libubox/patches/0003-blob-refactor-attr-parsing-into-separate-function.patch b/package/libs/libubox/patches/0003-blob-refactor-attr-parsing-into-separate-function.patch new file mode 100644 index 0000000000..81bffa587a --- /dev/null +++ b/package/libs/libubox/patches/0003-blob-refactor-attr-parsing-into-separate-function.patch @@ -0,0 +1,97 @@ +From af2a074160e32692b570f8a3562b4370d38f34e7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz> +Date: Mon, 9 Dec 2019 13:53:27 +0100 +Subject: blob: refactor attr parsing into separate function +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Making blob_parse easier to review. + +Signed-off-by: Petr Štetiar <ynezz@true.cz> +--- + blob.c | 61 +++++++++++++++++++++++++++++++++------------------------- + 1 file changed, 35 insertions(+), 26 deletions(-) + +--- a/blob.c ++++ b/blob.c +@@ -217,44 +217,53 @@ blob_check_type(const void *ptr, unsigne + return true; + } + +-int +-blob_parse(struct blob_attr *attr, struct blob_attr **data, const struct blob_attr_info *info, int max) ++static int ++blob_parse_attr(struct blob_attr *attr, struct blob_attr **data, const struct blob_attr_info *info, int max) + { +- struct blob_attr *pos; + int found = 0; +- int rem; ++ int id = blob_id(attr); ++ size_t len = blob_len(attr); + +- memset(data, 0, sizeof(struct blob_attr *) * max); +- blob_for_each_attr(pos, attr, rem) { +- int id = blob_id(pos); +- int len = blob_len(pos); ++ if (id >= max) ++ return 0; + +- if (id >= max) +- continue; ++ if (info) { ++ int type = info[id].type; + +- if (info) { +- int type = info[id].type; ++ if (type < BLOB_ATTR_LAST) { ++ if (!blob_check_type(blob_data(attr), len, type)) ++ return 0; ++ } + +- if (type < BLOB_ATTR_LAST) { +- if (!blob_check_type(blob_data(pos), len, type)) +- continue; +- } ++ if (info[id].minlen && len < info[id].minlen) ++ return 0; + +- if (info[id].minlen && len < info[id].minlen) +- continue; ++ if (info[id].maxlen && len > info[id].maxlen) ++ return 0; + +- if (info[id].maxlen && len > info[id].maxlen) +- continue; ++ if (info[id].validate && !info[id].validate(&info[id], attr)) ++ return 0; ++ } + +- if (info[id].validate && !info[id].validate(&info[id], pos)) +- continue; +- } ++ if (!data[id]) ++ found++; + +- if (!data[id]) +- found++; ++ data[id] = attr; ++ return found; ++} + +- data[id] = pos; ++int ++blob_parse(struct blob_attr *attr, struct blob_attr **data, const struct blob_attr_info *info, int max) ++{ ++ struct blob_attr *pos; ++ int found = 0; ++ size_t rem; ++ ++ memset(data, 0, sizeof(struct blob_attr *) * max); ++ blob_for_each_attr(pos, attr, rem) { ++ found += blob_parse_attr(pos, data, info, max); + } ++ + return found; + } + diff --git a/package/libs/libubox/patches/0004-blob-introduce-blob_parse_untrusted.patch b/package/libs/libubox/patches/0004-blob-introduce-blob_parse_untrusted.patch new file mode 100644 index 0000000000..b624db2cfe --- /dev/null +++ b/package/libs/libubox/patches/0004-blob-introduce-blob_parse_untrusted.patch @@ -0,0 +1,78 @@ +From b6a0a070f2e14808e835c2fcfa3820a55041902f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz> +Date: Mon, 9 Dec 2019 14:11:45 +0100 +Subject: blob: introduce blob_parse_untrusted +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +blob_parse can be only used on trusted input as it has no possibility to +check the length of the provided input buffer, which might lead to +undefined behaviour and/or crashes when supplied with malformed, +corrupted or otherwise specially crafted input. + +So this introduces blob_parse_untrusted variant which expects additional +input buffer length argument and thus should be able to process also +inputs from untrusted sources. + +Signed-off-by: Petr Štetiar <ynezz@true.cz> +--- + blob.c | 24 ++++++++++++++++++++++++ + blob.h | 7 +++++++ + 2 files changed, 31 insertions(+) + +--- a/blob.c ++++ b/blob.c +@@ -253,6 +253,30 @@ blob_parse_attr(struct blob_attr *attr, + } + + int ++blob_parse_untrusted(struct blob_attr *attr, size_t attr_len, struct blob_attr **data, const struct blob_attr_info *info, int max) ++{ ++ struct blob_attr *pos; ++ size_t len = 0; ++ int found = 0; ++ size_t rem; ++ ++ if (!attr || attr_len < sizeof(struct blob_attr)) ++ return 0; ++ ++ len = blob_raw_len(attr); ++ if (len != attr_len) ++ return 0; ++ ++ memset(data, 0, sizeof(struct blob_attr *) * max); ++ blob_for_each_attr_len(pos, attr, len, rem) { ++ found += blob_parse_attr(pos, rem, data, info, max); ++ } ++ ++ return found; ++} ++ ++/* use only on trusted input, otherwise consider blob_parse_untrusted */ ++int + blob_parse(struct blob_attr *attr, struct blob_attr **data, const struct blob_attr_info *info, int max) + { + struct blob_attr *pos; +--- a/blob.h ++++ b/blob.h +@@ -199,6 +199,7 @@ extern void blob_nest_end(struct blob_bu + extern struct blob_attr *blob_put(struct blob_buf *buf, int id, const void *ptr, unsigned int len); + extern bool blob_check_type(const void *ptr, unsigned int len, int type); + extern int blob_parse(struct blob_attr *attr, struct blob_attr **data, const struct blob_attr_info *info, int max); ++extern int blob_parse_untrusted(struct blob_attr *attr, size_t attr_len, struct blob_attr **data, const struct blob_attr_info *info, int max); + extern struct blob_attr *blob_memdup(struct blob_attr *attr); + extern struct blob_attr *blob_put_raw(struct blob_buf *buf, const void *ptr, unsigned int len); + +@@ -254,5 +255,11 @@ blob_put_u64(struct blob_buf *buf, int i + (blob_pad_len(pos) >= sizeof(struct blob_attr)); \ + rem -= blob_pad_len(pos), pos = blob_next(pos)) + ++#define blob_for_each_attr_len(pos, attr, attr_len, rem) \ ++ for (rem = attr ? blob_len(attr) : 0, \ ++ pos = (struct blob_attr *) (attr ? blob_data(attr) : NULL); \ ++ rem >= sizeof(struct blob_attr) && rem < attr_len && (blob_pad_len(pos) <= rem) && \ ++ (blob_pad_len(pos) >= sizeof(struct blob_attr)); \ ++ rem -= blob_pad_len(pos), pos = blob_next(pos)) + + #endif diff --git a/package/libs/libubox/patches/0005-blob-fix-OOB-access-in-blob_check_type.patch b/package/libs/libubox/patches/0005-blob-fix-OOB-access-in-blob_check_type.patch new file mode 100644 index 0000000000..e3d84c0279 --- /dev/null +++ b/package/libs/libubox/patches/0005-blob-fix-OOB-access-in-blob_check_type.patch @@ -0,0 +1,78 @@ +From 7425d421340594f50c717ff7129b6ee71280a447 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz> +Date: Mon, 9 Dec 2019 15:27:16 +0100 +Subject: blob: fix OOB access in blob_check_type +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Found by fuzzer: + + ERROR: AddressSanitizer: SEGV on unknown address 0x602100000455 + The signal is caused by a READ memory access. + #0 in blob_check_type blob.c:214:43 + #1 in blob_parse_attr blob.c:234:9 + #2 in blob_parse_untrusted blob.c:272:12 + #3 in fuzz_blob_parse tests/fuzzer/test-blob-parse-fuzzer.c:34:2 + #4 in LLVMFuzzerTestOneInput tests/fuzzer/test-blob-parse-fuzzer.c:39:2 + +Caused by following line: + + if (type == BLOB_ATTR_STRING && data[len - 1] != 0) + +where len was pointing outside of the data buffer. + +Signed-off-by: Petr Štetiar <ynezz@true.cz> +--- + blob.c | 23 ++++++++++++++++++----- + 1 file changed, 18 insertions(+), 5 deletions(-) + +--- a/blob.c ++++ b/blob.c +@@ -218,20 +218,33 @@ blob_check_type(const void *ptr, unsigne + } + + static int +-blob_parse_attr(struct blob_attr *attr, struct blob_attr **data, const struct blob_attr_info *info, int max) ++blob_parse_attr(struct blob_attr *attr, size_t attr_len, struct blob_attr **data, const struct blob_attr_info *info, int max) + { ++ int id; ++ size_t len; + int found = 0; +- int id = blob_id(attr); +- size_t len = blob_len(attr); ++ size_t data_len; + ++ if (!attr || attr_len < sizeof(struct blob_attr)) ++ return 0; ++ ++ id = blob_id(attr); + if (id >= max) + return 0; + ++ len = blob_raw_len(attr); ++ if (len > attr_len || len < sizeof(struct blob_attr)) ++ return 0; ++ ++ data_len = blob_len(attr); ++ if (data_len > len) ++ return 0; ++ + if (info) { + int type = info[id].type; + + if (type < BLOB_ATTR_LAST) { +- if (!blob_check_type(blob_data(attr), len, type)) ++ if (!blob_check_type(blob_data(attr), data_len, type)) + return 0; + } + +@@ -285,7 +298,7 @@ blob_parse(struct blob_attr *attr, struc + + memset(data, 0, sizeof(struct blob_attr *) * max); + blob_for_each_attr(pos, attr, rem) { +- found += blob_parse_attr(pos, data, info, max); ++ found += blob_parse_attr(pos, rem, data, info, max); + } + + return found; diff --git a/package/libs/libubox/patches/0006-blobmsg-fix-heap-buffer-overflow-in-blobmsg_parse.patch b/package/libs/libubox/patches/0006-blobmsg-fix-heap-buffer-overflow-in-blobmsg_parse.patch new file mode 100644 index 0000000000..37be1bb5ad --- /dev/null +++ b/package/libs/libubox/patches/0006-blobmsg-fix-heap-buffer-overflow-in-blobmsg_parse.patch @@ -0,0 +1,32 @@ +From 0773eef13674964d890420673d2501342979d8bf Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz> +Date: Tue, 10 Dec 2019 12:02:40 +0100 +Subject: blobmsg: fix heap buffer overflow in blobmsg_parse +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fixes following error found by the fuzzer: + + ==29774==ERROR: AddressSanitizer: heap-buffer-overflow + READ of size 1 at 0x6020004f1c56 thread T0 + #0 strcmp sanitizer_common_interceptors.inc:442:3 + #1 blobmsg_parse blobmsg.c:168:8 + +Signed-off-by: Petr Štetiar <ynezz@true.cz> +--- + blobmsg.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/blobmsg.c ++++ b/blobmsg.c +@@ -52,6 +52,9 @@ bool blobmsg_check_attr(const struct blo + + id = blob_id(attr); + len = blobmsg_data_len(attr); ++ if (len > blob_raw_len(attr)) ++ return false; ++ + data = blobmsg_data(attr); + + if (id > BLOBMSG_TYPE_LAST) diff --git a/package/libs/libubox/patches/0007-Ensure-blob_attr-length-check-does-not-perform-out-o.patch b/package/libs/libubox/patches/0007-Ensure-blob_attr-length-check-does-not-perform-out-o.patch new file mode 100644 index 0000000000..d17e27cbfc --- /dev/null +++ b/package/libs/libubox/patches/0007-Ensure-blob_attr-length-check-does-not-perform-out-o.patch @@ -0,0 +1,51 @@ +From cec3ed2550073abbfe0f1f6131c44f90c9d05aa8 Mon Sep 17 00:00:00 2001 +From: Tobias Schramm <tobleminer@gmail.com> +Date: Wed, 28 Nov 2018 13:39:29 +0100 +Subject: Ensure blob_attr length check does not perform out of bounds reads +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Before there might have been as little as one single byte left which +would result in 3 bytes of blob_attr->id_len being out of bounds. + +Acked-by: Yousong Zhou <yszhou4tech@gmail.com> +Signed-off-by: Tobias Schramm <tobleminer@gmail.com> +[line wrapped < 72 chars] +Signed-off-by: Petr Štetiar <ynezz@true.cz> +--- + blob.h | 4 ++-- + blobmsg.h | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +--- a/blob.h ++++ b/blob.h +@@ -243,7 +243,7 @@ blob_put_u64(struct blob_buf *buf, int i + + #define __blob_for_each_attr(pos, attr, rem) \ + for (pos = (struct blob_attr *) attr; \ +- rem > 0 && (blob_pad_len(pos) <= rem) && \ ++ rem >= sizeof(struct blob_attr) && (blob_pad_len(pos) <= rem) && \ + (blob_pad_len(pos) >= sizeof(struct blob_attr)); \ + rem -= blob_pad_len(pos), pos = blob_next(pos)) + +@@ -251,7 +251,7 @@ blob_put_u64(struct blob_buf *buf, int i + #define blob_for_each_attr(pos, attr, rem) \ + for (rem = attr ? blob_len(attr) : 0, \ + pos = (struct blob_attr *) (attr ? blob_data(attr) : NULL); \ +- rem > 0 && (blob_pad_len(pos) <= rem) && \ ++ rem >= sizeof(struct blob_attr) && (blob_pad_len(pos) <= rem) && \ + (blob_pad_len(pos) >= sizeof(struct blob_attr)); \ + rem -= blob_pad_len(pos), pos = blob_next(pos)) + +--- a/blobmsg.h ++++ b/blobmsg.h +@@ -266,7 +266,7 @@ int blobmsg_printf(struct blob_buf *buf, + #define blobmsg_for_each_attr(pos, attr, rem) \ + for (rem = attr ? blobmsg_data_len(attr) : 0, \ + pos = (struct blob_attr *) (attr ? blobmsg_data(attr) : NULL); \ +- rem > 0 && (blob_pad_len(pos) <= rem) && \ ++ rem >= sizeof(struct blob_attr) && (blob_pad_len(pos) <= rem) && \ + (blob_pad_len(pos) >= sizeof(struct blob_attr)); \ + rem -= blob_pad_len(pos), pos = blob_next(pos)) + diff --git a/package/libs/libubox/patches/0008-Replace-use-of-blobmsg_check_attr-by-blobmsg_check_a.patch b/package/libs/libubox/patches/0008-Replace-use-of-blobmsg_check_attr-by-blobmsg_check_a.patch new file mode 100644 index 0000000000..77de70afd0 --- /dev/null +++ b/package/libs/libubox/patches/0008-Replace-use-of-blobmsg_check_attr-by-blobmsg_check_a.patch @@ -0,0 +1,132 @@ +From 8b6a401638317906b6d9039417c1c19ea8cfeab0 Mon Sep 17 00:00:00 2001 +From: Tobias Schramm <tobleminer@gmail.com> +Date: Tue, 13 Nov 2018 04:16:12 +0100 +Subject: Replace use of blobmsg_check_attr by blobmsg_check_attr_len +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +blobmsg_check_attr_len adds a length limit specifying the max offset +from attr that can be read safely. + +Signed-off-by: Tobias Schramm <tobleminer@gmail.com> +[rebased and reworked, line wrapped commit message, _safe -> _len] +Signed-off-by: Petr Štetiar <ynezz@true.cz> +--- + blobmsg.c | 59 +++++++++++++++++++++++++++++++++++++++++++------------ + blobmsg.h | 2 ++ + 2 files changed, 48 insertions(+), 13 deletions(-) + +--- a/blobmsg.c ++++ b/blobmsg.c +@@ -33,37 +33,70 @@ blobmsg_namelen(const struct blobmsg_hdr + + bool blobmsg_check_attr(const struct blob_attr *attr, bool name) + { ++ return blobmsg_check_attr_len(attr, name, blob_raw_len(attr)); ++} ++ ++static bool blobmsg_check_name(const struct blob_attr *attr, size_t len, bool name) ++{ ++ char *limit = (char *) attr + len; + const struct blobmsg_hdr *hdr; +- const char *data; +- int id, len; + +- if (blob_len(attr) < sizeof(struct blobmsg_hdr)) ++ hdr = blob_data(attr); ++ if (name && !hdr->namelen) + return false; + +- hdr = (void *) attr->data; +- if (!hdr->namelen && name) ++ if ((char *) hdr->name + blobmsg_namelen(hdr) > limit) + return false; + +- if (blobmsg_namelen(hdr) > blob_len(attr) - sizeof(struct blobmsg_hdr)) ++ if (blobmsg_namelen(hdr) > (blob_len(attr) - sizeof(struct blobmsg_hdr))) + return false; + + if (hdr->name[blobmsg_namelen(hdr)] != 0) + return false; + +- id = blob_id(attr); +- len = blobmsg_data_len(attr); +- if (len > blob_raw_len(attr)) +- return false; ++ return true; ++} ++ ++static const char* blobmsg_check_data(const struct blob_attr *attr, size_t len, size_t *data_len) ++{ ++ char *limit = (char *) attr + len; ++ const char *data; ++ ++ *data_len = blobmsg_data_len(attr); ++ if (*data_len > blob_raw_len(attr)) ++ return NULL; + + data = blobmsg_data(attr); ++ if (data + *data_len > limit) ++ return NULL; + ++ return data; ++} ++ ++bool blobmsg_check_attr_len(const struct blob_attr *attr, bool name, size_t len) ++{ ++ const char *data; ++ size_t data_len; ++ int id; ++ ++ if (len < sizeof(struct blob_attr)) ++ return false; ++ ++ if (!blobmsg_check_name(attr, len, name)) ++ return false; ++ ++ id = blob_id(attr); + if (id > BLOBMSG_TYPE_LAST) + return false; + + if (!blob_type[id]) + return true; + +- return blob_check_type(data, len, blob_type[id]); ++ data = blobmsg_check_data(attr, len, &data_len); ++ if (!data) ++ return false; ++ ++ return blob_check_type(data, data_len, blob_type[id]); + } + + int blobmsg_check_array(const struct blob_attr *attr, int type) +@@ -114,7 +147,7 @@ int blobmsg_parse_array(const struct blo + blob_id(attr) != policy[i].type) + continue; + +- if (!blobmsg_check_attr(attr, false)) ++ if (!blobmsg_check_attr_len(attr, false, len)) + return -1; + + if (tb[i]) +@@ -161,7 +194,7 @@ int blobmsg_parse(const struct blobmsg_p + if (blobmsg_namelen(hdr) != pslen[i]) + continue; + +- if (!blobmsg_check_attr(attr, true)) ++ if (!blobmsg_check_attr_len(attr, true, len)) + return -1; + + if (tb[i]) +--- a/blobmsg.h ++++ b/blobmsg.h +@@ -107,6 +107,8 @@ static inline int blobmsg_len(const stru + bool blobmsg_check_attr(const struct blob_attr *attr, bool name); + bool blobmsg_check_attr_list(const struct blob_attr *attr, int type); + ++bool blobmsg_check_attr_len(const struct blob_attr *attr, bool name, size_t len); ++ + /* + * blobmsg_check_array: validate array/table and return size + * diff --git a/package/libs/libubox/patches/0009-blobmsg-add-_len-variants-for-all-attribute-checking.patch b/package/libs/libubox/patches/0009-blobmsg-add-_len-variants-for-all-attribute-checking.patch new file mode 100644 index 0000000000..7f90df1638 --- /dev/null +++ b/package/libs/libubox/patches/0009-blobmsg-add-_len-variants-for-all-attribute-checking.patch @@ -0,0 +1,157 @@ +From ad29d0304983e283d4aec4ee5462942eaf5c03ac Mon Sep 17 00:00:00 2001 +From: Tobias Schramm <tobleminer@gmail.com> +Date: Thu, 15 Nov 2018 03:42:48 +0100 +Subject: blobmsg: add _len variants for all attribute checking methods +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Introduce _len variants of blobmsg attribute checking functions which +aims to provide safer implementation as those functions should limit all +memory accesses performed on the blob to the range [attr, attr + len] +(upper bound non inclusive) and thus should be suited for checking of +untrusted blob attributes. + +While at it add some comments in order to make it clear. + +Signed-off-by: Tobias Schramm <tobleminer@gmail.com> +[_safe -> _len, blobmsg_check_array_len fix, commit subject/desc facelift] +Signed-off-by: Petr Štetiar <ynezz@true.cz> +--- + blobmsg.c | 21 ++++++++++++++++++--- + blobmsg.h | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 72 insertions(+), 4 deletions(-) + +--- a/blobmsg.c ++++ b/blobmsg.c +@@ -101,11 +101,21 @@ bool blobmsg_check_attr_len(const struct + + int blobmsg_check_array(const struct blob_attr *attr, int type) + { ++ return blobmsg_check_array_len(attr, type, blob_raw_len(attr)); ++} ++ ++int blobmsg_check_array_len(const struct blob_attr *attr, int type, size_t len) ++{ + struct blob_attr *cur; + bool name; +- int rem; + int size = 0; + ++ if (type > BLOBMSG_TYPE_LAST) ++ return -1; ++ ++ if (!blobmsg_check_attr_len(attr, false, len)) ++ return -1; ++ + switch (blobmsg_type(attr)) { + case BLOBMSG_TYPE_TABLE: + name = true; +@@ -117,11 +127,11 @@ int blobmsg_check_array(const struct blo + return -1; + } + +- blobmsg_for_each_attr(cur, attr, rem) { ++ __blobmsg_for_each_attr(cur, attr, len) { + if (type != BLOBMSG_TYPE_UNSPEC && blobmsg_type(cur) != type) + return -1; + +- if (!blobmsg_check_attr(cur, name)) ++ if (!blobmsg_check_attr_len(cur, name, len)) + return -1; + + size++; +@@ -135,6 +145,11 @@ bool blobmsg_check_attr_list(const struc + return blobmsg_check_array(attr, type) >= 0; + } + ++bool blobmsg_check_attr_list_len(const struct blob_attr *attr, int type, size_t len) ++{ ++ return blobmsg_check_array_len(attr, type, len) >= 0; ++} ++ + int blobmsg_parse_array(const struct blobmsg_policy *policy, int policy_len, + struct blob_attr **tb, void *data, unsigned int len) + { +--- a/blobmsg.h ++++ b/blobmsg.h +@@ -104,19 +104,66 @@ static inline int blobmsg_len(const stru + return blobmsg_data_len(attr); + } + ++/* ++ * blobmsg_check_attr: validate a list of attributes ++ * ++ * This method may be used with trusted data only. Providing ++ * malformed blobs will cause out of bounds memory access. ++ */ + bool blobmsg_check_attr(const struct blob_attr *attr, bool name); +-bool blobmsg_check_attr_list(const struct blob_attr *attr, int type); + ++/* ++ * blobmsg_check_attr_len: validate a list of attributes ++ * ++ * This method should be safer implementation of blobmsg_check_attr. ++ * It will limit all memory access performed on the blob to the ++ * range [attr, attr + len] (upper bound non inclusive) and is ++ * thus suited for checking of untrusted blob attributes. ++ */ + bool blobmsg_check_attr_len(const struct blob_attr *attr, bool name, size_t len); + + /* ++ * blobmsg_check_attr_list: validate a list of attributes ++ * ++ * This method may be used with trusted data only. Providing ++ * malformed blobs will cause out of bounds memory access. ++ */ ++bool blobmsg_check_attr_list(const struct blob_attr *attr, int type); ++ ++/* ++ * blobmsg_check_attr_list_len: validate a list of untrusted attributes ++ * ++ * This method should be safer implementation of blobmsg_check_attr_list. ++ * It will limit all memory access performed on the blob to the ++ * range [attr, attr + len] (upper bound non inclusive) and is ++ * thus suited for checking of untrusted blob attributes. ++ */ ++bool blobmsg_check_attr_list_len(const struct blob_attr *attr, int type, size_t len); ++ ++/* + * blobmsg_check_array: validate array/table and return size + * + * Checks if all elements of an array or table are valid and have + * the specified type. Returns the number of elements in the array ++ * ++ * This method may be used with trusted data only. Providing ++ * malformed blobs will cause out of bounds memory access. + */ + int blobmsg_check_array(const struct blob_attr *attr, int type); + ++/* ++ * blobmsg_check_array_len: validate untrusted array/table and return size ++ * ++ * Checks if all elements of an array or table are valid and have ++ * the specified type. Returns the number of elements in the array. ++ * ++ * This method should be safer implementation of blobmsg_check_array. ++ * It will limit all memory access performed on the blob to the ++ * range [attr, attr + len] (upper bound non inclusive) and is ++ * thus suited for checking of untrusted blob attributes. ++ */ ++int blobmsg_check_array_len(const struct blob_attr *attr, int type, size_t len); ++ + int blobmsg_parse(const struct blobmsg_policy *policy, int policy_len, + struct blob_attr **tb, void *data, unsigned int len); + int blobmsg_parse_array(const struct blobmsg_policy *policy, int policy_len, +@@ -271,5 +318,11 @@ int blobmsg_printf(struct blob_buf *buf, + rem >= sizeof(struct blob_attr) && (blob_pad_len(pos) <= rem) && \ + (blob_pad_len(pos) >= sizeof(struct blob_attr)); \ + rem -= blob_pad_len(pos), pos = blob_next(pos)) ++ ++#define __blobmsg_for_each_attr(pos, attr, rem) \ ++ for (pos = (struct blob_attr *) (attr ? blobmsg_data(attr) : NULL); \ ++ rem >= sizeof(struct blob_attr) && (blob_pad_len(pos) <= rem) && \ ++ (blob_pad_len(pos) >= sizeof(struct blob_attr)); \ ++ rem -= blob_pad_len(pos), pos = blob_next(pos)) + + #endif diff --git a/package/libs/libubox/patches/0010-blobmsg-fix-array-out-of-bounds-GCC-10-warning.patch b/package/libs/libubox/patches/0010-blobmsg-fix-array-out-of-bounds-GCC-10-warning.patch new file mode 100644 index 0000000000..61f73493df --- /dev/null +++ b/package/libs/libubox/patches/0010-blobmsg-fix-array-out-of-bounds-GCC-10-warning.patch @@ -0,0 +1,39 @@ +From 44d9e85ef058fbb9981d53218cafdc451afa5535 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz> +Date: Wed, 25 Dec 2019 10:27:59 +0100 +Subject: blobmsg: fix array out of bounds GCC 10 warning +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fixes following warning reported by GCC 10.0.0 20191203: + + blobmsg.c:234:2: error: 'strcpy' offset 6 from the object at 'attr' is out of the bounds of referenced subobject 'name' with type 'uint8_t[0]' {aka 'unsigned char[0]'} at offset 6 [-Werror=array-bounds] + 234 | strcpy((char *) hdr->name, (const char *)name); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + In file included from blobmsg.c:16: + blobmsg.h:42:10: note: subobject 'name' declared here + 42 | uint8_t name[]; + | ^~~~ + +Reported-by: Khem Raj <raj.khem@gmail.com> +Signed-off-by: Petr Štetiar <ynezz@true.cz> +--- + blobmsg.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/blobmsg.c ++++ b/blobmsg.c +@@ -246,7 +246,10 @@ blobmsg_new(struct blob_buf *buf, int ty + attr->id_len |= be32_to_cpu(BLOB_ATTR_EXTENDED); + hdr = blob_data(attr); + hdr->namelen = cpu_to_be16(namelen); +- strcpy((char *) hdr->name, (const char *)name); ++ ++ memcpy(hdr->name, name, namelen); ++ hdr->name[namelen] = '\0'; ++ + pad_end = *data = blobmsg_data(attr); + pad_start = (char *) &hdr->name[namelen]; + if (pad_start < pad_end) diff --git a/package/libs/libubox/patches/0011-blobmsg-fix-wrong-payload-len-passed-from-blobmsg_ch.patch b/package/libs/libubox/patches/0011-blobmsg-fix-wrong-payload-len-passed-from-blobmsg_ch.patch new file mode 100644 index 0000000000..2ebbfc6c47 --- /dev/null +++ b/package/libs/libubox/patches/0011-blobmsg-fix-wrong-payload-len-passed-from-blobmsg_ch.patch @@ -0,0 +1,38 @@ +From d0f05d5e6873b30315127d47abbf4ac9f3c8bfb7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz> +Date: Sat, 28 Dec 2019 19:00:39 +0100 +Subject: blobmsg: fix wrong payload len passed from blobmsg_check_array +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fix incorrect use of blob_raw_len() on passed blobmsg to +blobmsg_check_array_len() introduced in commit b0e21553ae8c ("blobmsg: +add _len variants for all attribute checking methods") by using correct +blobmsg_len(). + +This wrong (higher) length was then for example causing issues in +procd's instance_config_parse_command() where blobmsg_check_attr_list() +was failing sanity checking of service command, thus resulting in the +startup failures of some services like collectd, nlbwmon and samba4. + +Ref: http://lists.infradead.org/pipermail/openwrt-devel/2019-December/020840.html +Fixes: b0e21553ae8c ("blobmsg: add _len variants for all attribute checking methods") +Reported-by: Hannu Nyman <hannu.nyman@welho.com> +Tested-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk> +Signed-off-by: Petr Štetiar <ynezz@true.cz> +--- + blobmsg.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/blobmsg.c ++++ b/blobmsg.c +@@ -101,7 +101,7 @@ bool blobmsg_check_attr_len(const struct + + int blobmsg_check_array(const struct blob_attr *attr, int type) + { +- return blobmsg_check_array_len(attr, type, blob_raw_len(attr)); ++ return blobmsg_check_array_len(attr, type, blobmsg_len(attr)); + } + + int blobmsg_check_array_len(const struct blob_attr *attr, int type, size_t len) diff --git a/package/libs/libubox/patches/0012-jshn-prefer-snprintf-usage.patch b/package/libs/libubox/patches/0012-jshn-prefer-snprintf-usage.patch new file mode 100644 index 0000000000..e551fed7ea --- /dev/null +++ b/package/libs/libubox/patches/0012-jshn-prefer-snprintf-usage.patch @@ -0,0 +1,61 @@ +From 31778937b4153492955495e550435c8bbf7cfde8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz> +Date: Tue, 14 Jan 2020 08:55:34 +0100 +Subject: jshn: prefer snprintf usage +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Better safe than sorry. + +Reviewed-by: Jo-Philipp Wich <jo@mein.io> +Signed-off-by: Petr Štetiar <ynezz@true.cz> +--- + jshn.c | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +--- a/jshn.c ++++ b/jshn.c +@@ -68,7 +68,7 @@ static int add_json_array(struct array_l + int ret; + + for (i = 0, len = array_list_length(a); i < len; i++) { +- sprintf(seq, "%d", i); ++ snprintf(seq, sizeof(seq), "%d", i); + ret = add_json_element(seq, array_list_get_idx(a, i)); + if (ret) + return ret; +@@ -197,25 +197,27 @@ static char *getenv_avl(const char *key) + static char *get_keys(const char *prefix) + { + char *keys; ++ size_t len = var_prefix_len + strlen(prefix) + sizeof("K_") + 1; + +- keys = alloca(var_prefix_len + strlen(prefix) + sizeof("K_") + 1); +- sprintf(keys, "%sK_%s", var_prefix, prefix); ++ keys = alloca(len); ++ snprintf(keys, len, "%sK_%s", var_prefix, prefix); + return getenv_avl(keys); + } + + static void get_var(const char *prefix, const char **name, char **var, char **type) + { + char *tmpname, *varname; ++ size_t len = var_prefix_len + strlen(prefix) + 1 + strlen(*name) + 1 + sizeof("T_"); + +- tmpname = alloca(var_prefix_len + strlen(prefix) + 1 + strlen(*name) + 1 + sizeof("T_")); ++ tmpname = alloca(len); + +- sprintf(tmpname, "%s%s_%s", var_prefix, prefix, *name); ++ snprintf(tmpname, len, "%s%s_%s", var_prefix, prefix, *name); + *var = getenv_avl(tmpname); + +- sprintf(tmpname, "%sT_%s_%s", var_prefix, prefix, *name); ++ snprintf(tmpname, len, "%sT_%s_%s", var_prefix, prefix, *name); + *type = getenv_avl(tmpname); + +- sprintf(tmpname, "%sN_%s_%s", var_prefix, prefix, *name); ++ snprintf(tmpname, len, "%sN_%s_%s", var_prefix, prefix, *name); + varname = getenv_avl(tmpname); + if (varname) + *name = varname; diff --git a/package/libs/libubox/patches/0013-blobmsg-blobmsg_vprintf-prefer-vsnprintf.patch b/package/libs/libubox/patches/0013-blobmsg-blobmsg_vprintf-prefer-vsnprintf.patch new file mode 100644 index 0000000000..2ed0907b07 --- /dev/null +++ b/package/libs/libubox/patches/0013-blobmsg-blobmsg_vprintf-prefer-vsnprintf.patch @@ -0,0 +1,38 @@ +From 935bb933e4a74de7326a4373340fd50655712334 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz> +Date: Tue, 14 Jan 2020 08:57:05 +0100 +Subject: blobmsg: blobmsg_vprintf: prefer vsnprintf +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Better safe than sorry and while at it add handling of possible +*printf() failures. + +Reviewed-by: Jo-Philipp Wich <jo@mein.io> +Signed-off-by: Petr Štetiar <ynezz@true.cz> +--- + blobmsg.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +--- a/blobmsg.c ++++ b/blobmsg.c +@@ -296,10 +296,17 @@ blobmsg_vprintf(struct blob_buf *buf, co + len = vsnprintf(&cbuf, sizeof(cbuf), format, arg2); + va_end(arg2); + ++ if (len < 0) ++ return -1; ++ + sbuf = blobmsg_alloc_string_buffer(buf, name, len + 1); + if (!sbuf) + return -1; +- ret = vsprintf(sbuf, format, arg); ++ ++ ret = vsnprintf(sbuf, len + 1, format, arg); ++ if (ret < 0) ++ return -1; ++ + blobmsg_add_string_buffer(buf); + + return ret; diff --git a/package/libs/libubox/patches/0014-blobmsg_json-fix-int16-serialization.patch b/package/libs/libubox/patches/0014-blobmsg_json-fix-int16-serialization.patch new file mode 100644 index 0000000000..a79ce4adbc --- /dev/null +++ b/package/libs/libubox/patches/0014-blobmsg_json-fix-int16-serialization.patch @@ -0,0 +1,41 @@ +From 1cc755d7c3989b399bf0c60535a858d22819ca27 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz> +Date: Sun, 12 Jan 2020 22:40:18 +0100 +Subject: blobmsg_json: fix int16 serialization +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +int16 blobmsg type is currently being serialized as uint16_t due to +missing cast during JSON output. + +Following blobmsg content: + + bar-min: -32768 (i16) + bar-max: 32767 (i16) + +Produces following JSON: + + { "bar-min":32768,"bar-max":32767 } + +Whereas one would expect: + + { "bar-min":-32768,"bar-max":32767 } + +Reviewed-by: Jo-Philipp Wich <jo@mein.io> +Signed-off-by: Petr Štetiar <ynezz@true.cz> +--- + blobmsg_json.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/blobmsg_json.c ++++ b/blobmsg_json.c +@@ -250,7 +250,7 @@ static void blobmsg_format_element(struc + sprintf(buf, "%s", *(uint8_t *)data ? "true" : "false"); + break; + case BLOBMSG_TYPE_INT16: +- sprintf(buf, "%d", be16_to_cpu(*(uint16_t *)data)); ++ sprintf(buf, "%d", (int16_t) be16_to_cpu(*(uint16_t *)data)); + break; + case BLOBMSG_TYPE_INT32: + sprintf(buf, "%d", (int32_t) be32_to_cpu(*(uint32_t *)data)); diff --git a/package/libs/libubox/patches/0015-blobmsg_json-prefer-snprintf-usage.patch b/package/libs/libubox/patches/0015-blobmsg_json-prefer-snprintf-usage.patch new file mode 100644 index 0000000000..d5709a6e4f --- /dev/null +++ b/package/libs/libubox/patches/0015-blobmsg_json-prefer-snprintf-usage.patch @@ -0,0 +1,66 @@ +From 0e330ec3662795aea42ac36ecf7a9f32a249c36d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz> +Date: Tue, 14 Jan 2020 09:05:02 +0100 +Subject: blobmsg_json: prefer snprintf usage +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Better safe than sorry and while at it prefer use of PRId16 and PRId32 +formatting constants as well. + +Reviewed-by: Jo-Philipp Wich <jo@mein.io> +Signed-off-by: Petr Štetiar <ynezz@true.cz> +--- + blobmsg_json.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +--- a/blobmsg_json.c ++++ b/blobmsg_json.c +@@ -203,7 +203,7 @@ static void blobmsg_format_string(struct + buf[1] = escape; + + if (escape == 'u') { +- sprintf(buf + 4, "%02x", (unsigned char) *p); ++ snprintf(buf + 4, sizeof(buf) - 4, "%02x", (unsigned char) *p); + len = 6; + } else { + len = 2; +@@ -220,7 +220,7 @@ static void blobmsg_format_json_list(str + static void blobmsg_format_element(struct strbuf *s, struct blob_attr *attr, bool without_name, bool head) + { + const char *data_str; +- char buf[32]; ++ char buf[317]; + void *data; + int len; + +@@ -244,22 +244,22 @@ static void blobmsg_format_element(struc + data_str = buf; + switch(blob_id(attr)) { + case BLOBMSG_TYPE_UNSPEC: +- sprintf(buf, "null"); ++ snprintf(buf, sizeof(buf), "null"); + break; + case BLOBMSG_TYPE_BOOL: +- sprintf(buf, "%s", *(uint8_t *)data ? "true" : "false"); ++ snprintf(buf, sizeof(buf), "%s", *(uint8_t *)data ? "true" : "false"); + break; + case BLOBMSG_TYPE_INT16: +- sprintf(buf, "%d", (int16_t) be16_to_cpu(*(uint16_t *)data)); ++ snprintf(buf, sizeof(buf), "%" PRId16, (int16_t) be16_to_cpu(*(uint16_t *)data)); + break; + case BLOBMSG_TYPE_INT32: +- sprintf(buf, "%d", (int32_t) be32_to_cpu(*(uint32_t *)data)); ++ snprintf(buf, sizeof(buf), "%" PRId32, (int32_t) be32_to_cpu(*(uint32_t *)data)); + break; + case BLOBMSG_TYPE_INT64: +- sprintf(buf, "%" PRId64, (int64_t) be64_to_cpu(*(uint64_t *)data)); ++ snprintf(buf, sizeof(buf), "%" PRId64, (int64_t) be64_to_cpu(*(uint64_t *)data)); + break; + case BLOBMSG_TYPE_DOUBLE: +- sprintf(buf, "%lf", blobmsg_get_double(attr)); ++ snprintf(buf, sizeof(buf), "%lf", blobmsg_get_double(attr)); + break; + case BLOBMSG_TYPE_STRING: + blobmsg_format_string(s, data); diff --git a/package/libs/libubox/patches/0016-blobmsg-blobmsg_parse-and-blobmsg_parse_array-oob-re.patch b/package/libs/libubox/patches/0016-blobmsg-blobmsg_parse-and-blobmsg_parse_array-oob-re.patch new file mode 100644 index 0000000000..c5d6df58e9 --- /dev/null +++ b/package/libs/libubox/patches/0016-blobmsg-blobmsg_parse-and-blobmsg_parse_array-oob-re.patch @@ -0,0 +1,110 @@ +From 6289e2d29883d5d9510b6a15c18c597478967a42 Mon Sep 17 00:00:00 2001 +From: Juraj Vijtiuk <juraj.vijtiuk@sartura.hr> +Date: Sun, 12 Jan 2020 12:26:18 +0100 +Subject: blobmsg: blobmsg_parse and blobmsg_parse_array oob read fixes +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fix out of bounds read in blobmsg_parse and blobmsg_check_name. The +out of bounds read happens because blob_attr and blobmsg_hdr have +flexible array members, whose size is 0 in the corresponding sizeofs. +For example the __blob_for_each_attr macro checks whether rem >= +sizeof(struct blob_attr). However, what LibFuzzer discovered was, +if the input data was only 4 bytes, the data would be casted to blob_attr, +and later on blob_data(attr) would be called even though attr->data was empty. +The same issue could appear with data larger than 4 bytes, where data +wasn't empty, but contained only the start of the blobmsg_hdr struct, +and blobmsg_hdr name was empty. The bugs were discovered by fuzzing +blobmsg_parse and blobmsg_array_parse with LibFuzzer. + +CC: Luka Perkov <luka.perkov@sartura.hr> +Reviewed-by: Jo-Philipp Wich <jo@mein.io> +Signed-off-by: Juraj Vijtiuk <juraj.vijtiuk@sartura.hr> +[refactored some checks, added fuzz inputs, adjusted unit test results] +Signed-off-by: Petr Štetiar <ynezz@true.cz> +--- + blobmsg.c | 40 ++++++++++++++++++++++++++++++++-------- + 1 file changed, 32 insertions(+), 8 deletions(-) + +--- a/blobmsg.c ++++ b/blobmsg.c +@@ -36,16 +36,38 @@ bool blobmsg_check_attr(const struct blo + return blobmsg_check_attr_len(attr, name, blob_raw_len(attr)); + } + ++static const struct blobmsg_hdr* blobmsg_hdr_from_blob(const struct blob_attr *attr, size_t len) ++{ ++ if (len < sizeof(struct blob_attr) + sizeof(struct blobmsg_hdr)) ++ return NULL; ++ ++ return blob_data(attr); ++} ++ ++static bool blobmsg_hdr_valid_namelen(const struct blobmsg_hdr *hdr, size_t len) ++{ ++ if (len < sizeof(struct blob_attr) + sizeof(struct blobmsg_hdr) + blobmsg_namelen(hdr) + 1) ++ return false; ++ ++ return true; ++} ++ + static bool blobmsg_check_name(const struct blob_attr *attr, size_t len, bool name) + { + char *limit = (char *) attr + len; + const struct blobmsg_hdr *hdr; + +- hdr = blob_data(attr); ++ hdr = blobmsg_hdr_from_blob(attr, len); ++ if (!hdr) ++ return false; ++ + if (name && !hdr->namelen) + return false; + +- if ((char *) hdr->name + blobmsg_namelen(hdr) > limit) ++ if (name && !blobmsg_hdr_valid_namelen(hdr, len)) ++ return false; ++ ++ if ((char *) hdr->name + blobmsg_namelen(hdr) + 1 > limit) + return false; + + if (blobmsg_namelen(hdr) > (blob_len(attr) - sizeof(struct blobmsg_hdr))) +@@ -79,9 +101,6 @@ bool blobmsg_check_attr_len(const struct + size_t data_len; + int id; + +- if (len < sizeof(struct blob_attr)) +- return false; +- + if (!blobmsg_check_name(attr, len, name)) + return false; + +@@ -176,11 +195,10 @@ int blobmsg_parse_array(const struct blo + return 0; + } + +- + int blobmsg_parse(const struct blobmsg_policy *policy, int policy_len, + struct blob_attr **tb, void *data, unsigned int len) + { +- struct blobmsg_hdr *hdr; ++ const struct blobmsg_hdr *hdr; + struct blob_attr *attr; + uint8_t *pslen; + int i; +@@ -197,7 +215,13 @@ int blobmsg_parse(const struct blobmsg_p + } + + __blob_for_each_attr(attr, data, len) { +- hdr = blob_data(attr); ++ hdr = blobmsg_hdr_from_blob(attr, len); ++ if (!hdr) ++ return -1; ++ ++ if (!blobmsg_hdr_valid_namelen(hdr, len)) ++ return -1; ++ + for (i = 0; i < policy_len; i++) { + if (!policy[i].name) + continue; |