From 9ae2160701f3e17111208e613b161e606a9490a2 Mon Sep 17 00:00:00 2001 From: zhongxuan Date: Thu, 13 Jun 2024 13:16:42 +0000 Subject: [PATCH] sync 2203sp3 --- ...ty-and-adapt-get_integer-accordingly.patch | 58 +++ ...to-convert-an-unsigned-int-to-string.patch | 45 +++ ...idge-fix-potential-snprintf-overflow.patch | 40 +++ backport-f_flower-Treat-port-0-as-valid.patch | 121 +++++++ ...x-potential-snprintf-buffer-overflow.patch | 27 ++ ...-iplink-does-not-consume-all-options.patch | 48 +++ ...-ip-fix-memory-leak-in-ip-maddr-show.patch | 44 +++ ...nk_bridge-fix-incorrect-root-id-dump.patch | 34 ++ backport-iproute2-prevent-memory-leak.patch | 148 ++++++++ ...k-Fix-memory-leak-in-__rtnl_talk_iov.patch | 86 +++++ ...k-validate-nlmsg-header-length-first.patch | 39 ++ ...deref-of-null-in-print_json-function.patch | 32 ++ ...ng-netlink-payload-size-in-callbacks.patch | 47 +++ ...ocket-type-check-in-packet_show_line.patch | 37 ++ ...-port-from-int-to-long-inode-support.patch | 68 ++++ ...x-socket-ports-as-unsigned-int-inode.patch | 33 ++ ...c-ct-Fix-invalid-pointer-dereference.patch | 35 ++ backport-tc-remove-tcindex-classifier.patch | 336 ++++++++++++++++++ ...type-for-maj-to-avoid-overflow-issue.patch | 33 ++ ...ror-return-when-large-parent-id-used.patch | 35 ++ backport-utils-fix-get_integer-logic.patch | 33 ++ ...pare-state-offload-logic-to-set-mode.patch | 117 ++++++ iproute.spec | 73 +++- ...ipvlan_mode-enum-with-kernel-headers.patch | 26 ++ 24 files changed, 1592 insertions(+), 3 deletions(-) create mode 100644 backport-Add-get_long-utility-and-adapt-get_integer-accordingly.patch create mode 100644 backport-Add-utility-to-convert-an-unsigned-int-to-string.patch create mode 100644 backport-bridge-fix-potential-snprintf-overflow.patch create mode 100644 backport-f_flower-Treat-port-0-as-valid.patch create mode 100644 backport-ila-fix-potential-snprintf-buffer-overflow.patch create mode 100644 backport-ip-error-out-if-iplink-does-not-consume-all-options.patch create mode 100644 backport-ip-fix-memory-leak-in-ip-maddr-show.patch create mode 100644 backport-iplink_bridge-fix-incorrect-root-id-dump.patch create mode 100644 backport-iproute2-prevent-memory-leak.patch create mode 100644 backport-libnetlink-Fix-memory-leak-in-__rtnl_talk_iov.patch create mode 100644 backport-libnetlink-validate-nlmsg-header-length-first.patch create mode 100644 backport-lnstat-Fix-deref-of-null-in-print_json-function.patch create mode 100644 backport-mnl_utils-sanitize-incoming-netlink-payload-size-in-callbacks.patch create mode 100644 backport-ss-Fix-socket-type-check-in-packet_show_line.patch create mode 100644 backport-ss-change-aafilter-port-from-int-to-long-inode-support.patch create mode 100644 backport-ss-print-unix-socket-ports-as-unsigned-int-inode.patch create mode 100644 backport-tc-ct-Fix-invalid-pointer-dereference.patch create mode 100644 backport-tc-remove-tcindex-classifier.patch create mode 100644 backport-tc_util-Change-datatype-for-maj-to-avoid-overflow-issue.patch create mode 100644 backport-tc_util-Fix-no-error-return-when-large-parent-id-used.patch create mode 100644 backport-utils-fix-get_integer-logic.patch create mode 100644 backport-xfrm-prepare-state-offload-logic-to-set-mode.patch create mode 100644 sync-ipvlan_mode-enum-with-kernel-headers.patch diff --git a/backport-Add-get_long-utility-and-adapt-get_integer-accordingly.patch b/backport-Add-get_long-utility-and-adapt-get_integer-accordingly.patch new file mode 100644 index 0000000..aad55f7 --- /dev/null +++ b/backport-Add-get_long-utility-and-adapt-get_integer-accordingly.patch @@ -0,0 +1,58 @@ +From 3a463c152a9a5503f9c37362b63acd6f72ecba6c Mon Sep 17 00:00:00 2001 +From: Mathieu Schroeter +Date: Tue, 8 Aug 2023 23:42:55 +0200 +Subject: [PATCH] Add get_long utility and adapt get_integer accordingly + +Conflict:contaxt adapt in include/utiles.h due to ebe23249ce1eeedb3610890e4c0c0f52fb8341fe +Reference:https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit?id=3a463c152a9a5503f9c37362b63acd6f72ecba6c + +Signed-off-by: Mathieu Schroeter +Signed-off-by: David Ahern +--- + include/utils.h | 1 + + lib/utils.c | 13 ++++++++++++- + 2 files changed, 13 insertions(+), 1 deletion(-) + +diff --git a/include/utils.h b/include/utils.h +index 3159dbab1..cf11174d9 100644 +--- a/include/utils.h ++++ b/include/utils.h +@@ -142,6 +142,7 @@ int get_addr_rta(inet_prefix *dst, const struct rtattr *rta, int family); + + int read_prop(const char *dev, char *prop, long *value); + int get_hex(char c); ++int get_long(long *val, const char *arg, int base); + int get_integer(int *val, const char *arg, int base); + int get_unsigned(unsigned *val, const char *arg, int base); + int get_time_rtt(unsigned *val, const char *arg, int *raw); +diff --git a/lib/utils.c b/lib/utils.c +index b1f273054..68f443038 100644 +--- a/lib/utils.c ++++ b/lib/utils.c +@@ -108,7 +108,7 @@ static int get_hex(char c) + return -1; + } + +-int get_integer(int *val, const char *arg, int base) ++int get_long(long *val, const char *arg, int base) + { + long res; + char *ptr; +@@ -133,6 +133,17 @@ int get_integer(int *val, const char *arg, int base) + if ((res == LONG_MAX || res == LONG_MIN) && errno == ERANGE) + return -1; + ++ if (val) ++ *val = res; ++ return 0; ++} ++ ++int get_integer(int *val, const char *arg, int base) ++{ ++ long res; ++ ++ res = get_long(NULL, arg, base); ++ + /* Outside range of int */ + if (res < INT_MIN || res > INT_MAX) + return -1; diff --git a/backport-Add-utility-to-convert-an-unsigned-int-to-string.patch b/backport-Add-utility-to-convert-an-unsigned-int-to-string.patch new file mode 100644 index 0000000..9ad2776 --- /dev/null +++ b/backport-Add-utility-to-convert-an-unsigned-int-to-string.patch @@ -0,0 +1,45 @@ +From db7fb3f1965751444c3b743ba0253061fd7e3b44 Mon Sep 17 00:00:00 2001 +From: Mathieu Schroeter +Date: Tue, 8 Aug 2023 23:42:56 +0200 +Subject: [PATCH] Add utility to convert an unsigned int to string + +Conflict:contaxt adapt in include/utiles.h due to ebe23249ce1eeedb3610890e4c0c0f52fb8341fe +Reference:https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit?id=db7fb3f1965751444c3b743ba0253061fd7e3b44 + + +Signed-off-by: Mathieu Schroeter +Signed-off-by: David Ahern +--- + include/utils.h | 1 + + lib/utils.c | 6 ++++++ + 2 files changed, 7 insertions(+) + +diff --git a/include/utils.h b/include/utils.h +index cf11174d9..f26ed822f 100644 +--- a/include/utils.h ++++ b/include/utils.h +@@ -309,6 +309,7 @@ unsigned int print_name_and_link(const char *fmt, + int makeargs(char *line, char *argv[], int maxargs); + + char *int_to_str(int val, char *buf); ++char *uint_to_str(unsigned int val, char *buf); + int get_guid(__u64 *guid, const char *arg); + int get_real_family(int rtm_type, int rtm_family); + +diff --git a/lib/utils.c b/lib/utils.c +index 68f443038..efa01668d 100644 +--- a/lib/utils.c ++++ b/lib/utils.c +@@ -1409,6 +1409,12 @@ char *int_to_str(int val, char *buf) + return buf; + } + ++char *uint_to_str(unsigned int val, char *buf) ++{ ++ sprintf(buf, "%u", val); ++ return buf; ++} ++ + int get_guid(__u64 *guid, const char *arg) + { + unsigned long tmp; diff --git a/backport-bridge-fix-potential-snprintf-overflow.patch b/backport-bridge-fix-potential-snprintf-overflow.patch new file mode 100644 index 0000000..6e4a98f --- /dev/null +++ b/backport-bridge-fix-potential-snprintf-overflow.patch @@ -0,0 +1,40 @@ +From 4d80122ae82aea86cb740b5202f6c3fde6183538 Mon Sep 17 00:00:00 2001 +From: Stephen Hemminger +Date: Mon, 18 Sep 2023 11:34:42 -0700 +Subject: [PATCH] bridge: fix potential snprintf overflow + +There is a theoretical snprintf overflow in bridge slave bitmask +print code found by CodeQL scan. + +Signed-off-by: Stephen Hemminger +--- + ip/iplink_bridge_slave.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/ip/iplink_bridge_slave.c b/ip/iplink_bridge_slave.c +index dc73c8657..3821923b5 100644 +--- a/ip/iplink_bridge_slave.c ++++ b/ip/iplink_bridge_slave.c +@@ -100,13 +100,20 @@ static void _bitmask2str(__u16 bitmask, char *dst, size_t dst_size, + int len, i; + + for (i = 0, len = 0; bitmask; i++, bitmask >>= 1) { ++ int n; ++ + if (bitmask & 0x1) { + if (tbl[i]) +- len += snprintf(dst + len, dst_size - len, "%s,", ++ n = snprintf(dst + len, dst_size - len, "%s,", + tbl[i]); + else +- len += snprintf(dst + len, dst_size - len, "0x%x,", ++ n = snprintf(dst + len, dst_size - len, "0x%x,", + (1 << i)); ++ ++ if (n < 0 || n >= dst_size - len) ++ break; ++ ++ len += n; + } + } + diff --git a/backport-f_flower-Treat-port-0-as-valid.patch b/backport-f_flower-Treat-port-0-as-valid.patch new file mode 100644 index 0000000..8642def --- /dev/null +++ b/backport-f_flower-Treat-port-0-as-valid.patch @@ -0,0 +1,121 @@ +From 61695c493ec14a63740bbb81e0564f753bd054dd Mon Sep 17 00:00:00 2001 +From: Ido Schimmel +Date: Tue, 11 Jul 2023 09:59:03 +0300 +Subject: f_flower: Treat port 0 as valid + +Conflict:NA +Reference:https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit?id=61695c493ec14a63740bbb81e0564f753bd054dd + +It is not currently possible to add a filter matching on port 0 despite +it being a valid port number. This is caused by cited commit which +treats a value of 0 as an indication that the port was not specified. + +Instead of inferring that a port range was specified by checking that both +the minimum and the maximum ports are non-zero, simply add a boolean +argument to parse_range() and set it after parsing a port range. + +Before: + + # tc filter add dev swp1 ingress pref 1 proto ip flower ip_proto udp src_port 0 action pass + Illegal "src_port" + + # tc filter add dev swp1 ingress pref 2 proto ip flower ip_proto udp dst_port 0 action pass + Illegal "dst_port" + + # tc filter add dev swp1 ingress pref 3 proto ip flower ip_proto udp src_port 0-100 action pass + Illegal "src_port" + + # tc filter add dev swp1 ingress pref 4 proto ip flower ip_proto udp dst_port 0-100 action pass + Illegal "dst_port" + +After: + + # tc filter add dev swp1 ingress pref 1 proto ip flower ip_proto udp src_port 0 action pass + + # tc filter add dev swp1 ingress pref 2 proto ip flower ip_proto udp dst_port 0 action pass + + # tc filter add dev swp1 ingress pref 3 proto ip flower ip_proto udp src_port 0-100 action pass + + # tc filter add dev swp1 ingress pref 4 proto ip flower ip_proto udp dst_port 0-100 action pass + + # tc filter show dev swp1 ingress | grep _port + src_port 0 + dst_port 0 + src_port 0-100 + dst_port 0-100 + +Fixes: 767b6fd620dd ("tc: flower: fix port value truncation") +Signed-off-by: Ido Schimmel +Reviewed-by: Petr Machata +Reviewed-by: Simon Horman +Signed-off-by: Stephen Hemminger +--- + tc/f_flower.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/tc/f_flower.c b/tc/f_flower.c +index c71394f75..737df199a 100644 +--- a/tc/f_flower.c ++++ b/tc/f_flower.c +@@ -735,7 +735,7 @@ static int flower_port_range_attr_type(__u8 ip_proto, enum flower_endpoint type, + } + + /* parse range args in format 10-20 */ +-static int parse_range(char *str, __be16 *min, __be16 *max) ++static int parse_range(char *str, __be16 *min, __be16 *max, bool *p_is_range) + { + char *sep; + +@@ -748,6 +748,8 @@ static int parse_range(char *str, __be16 *min, __be16 *max) + + if (get_be16(max, sep + 1, 10)) + return -1; ++ ++ *p_is_range = true; + } else { + if (get_be16(min, str, 10)) + return -1; +@@ -759,19 +761,20 @@ static int flower_parse_port(char *str, __u8 ip_proto, + enum flower_endpoint endpoint, + struct nlmsghdr *n) + { ++ bool is_range = false; + char *slash = NULL; + __be16 min = 0; + __be16 max = 0; + int ret; + +- ret = parse_range(str, &min, &max); ++ ret = parse_range(str, &min, &max, &is_range); + if (ret) { + slash = strchr(str, '/'); + if (!slash) + return -1; + } + +- if (min && max) { ++ if (is_range) { + __be16 min_port_type, max_port_type; + + if (ntohs(max) <= ntohs(min)) { +@@ -784,7 +787,7 @@ static int flower_parse_port(char *str, __u8 ip_proto, + + addattr16(n, MAX_MSG, min_port_type, min); + addattr16(n, MAX_MSG, max_port_type, max); +- } else if (slash || (min && !max)) { ++ } else { + int type; + + type = flower_port_attr_type(ip_proto, endpoint); +@@ -802,8 +805,6 @@ static int flower_parse_port(char *str, __u8 ip_proto, + return -1; + return flower_parse_u16(str, type, mask_type, n, true); + } +- } else { +- return -1; + } + return 0; + } +-- +cgit + diff --git a/backport-ila-fix-potential-snprintf-buffer-overflow.patch b/backport-ila-fix-potential-snprintf-buffer-overflow.patch new file mode 100644 index 0000000..eea2839 --- /dev/null +++ b/backport-ila-fix-potential-snprintf-buffer-overflow.patch @@ -0,0 +1,27 @@ +From e8a3fca81cd4b8fee14cfb14a5ce9c1b3b63e797 Mon Sep 17 00:00:00 2001 +From: Stephen Hemminger +Date: Mon, 18 Sep 2023 11:36:32 -0700 +Subject: [PATCH] ila: fix potential snprintf buffer overflow + +The code to print 64 bit address has a theoretical overflow +of snprintf buffer found by CodeQL scan. +Address by checking result. + +Signed-off-by: Stephen Hemminger +--- + ip/ipila.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/ip/ipila.c b/ip/ipila.c +index 4f6d578f2..23b19a108 100644 +--- a/ip/ipila.c ++++ b/ip/ipila.c +@@ -60,6 +60,8 @@ static void print_addr64(__u64 addr, char *buff, size_t len) + sep = ""; + + ret = snprintf(&buff[written], len - written, "%x%s", v, sep); ++ if (ret < 0 || ret >= len - written) ++ break; + written += ret; + } + } diff --git a/backport-ip-error-out-if-iplink-does-not-consume-all-options.patch b/backport-ip-error-out-if-iplink-does-not-consume-all-options.patch new file mode 100644 index 0000000..f5b1616 --- /dev/null +++ b/backport-ip-error-out-if-iplink-does-not-consume-all-options.patch @@ -0,0 +1,48 @@ +From 84ffffeb0a2ff69e36bd972d57699f9e3bb29a48 Mon Sep 17 00:00:00 2001 +From: Jakub Kicinski +Date: Mon, 31 Jul 2023 09:19:20 -0700 +Subject: ip: error out if iplink does not consume all options + +Conflict:NA +Reference:https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit?id=84ffffeb0a2ff69e36bd972d57699f9e3bb29a48 + +dummy does not define .parse_opt, which make ip ignore all +trailing arguments, for example: + + # ip link add type dummy a b c d e f name cheese + +will work just fine (and won't call the device "cheese"). +Error out in this case with a clear error message: + + # ip link add type dummy a b c d e f name cheese + Garbage instead of arguments "a ...". Try "ip link help". + +Signed-off-by: Jakub Kicinski +Signed-off-by: Stephen Hemminger +--- + ip/iplink.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/ip/iplink.c b/ip/iplink.c +index 6c5d13d53..9a548dd35 100644 +--- a/ip/iplink.c ++++ b/ip/iplink.c +@@ -1112,13 +1112,12 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv) + argc -= ret; + argv += ret; + +- if (lu && argc) { ++ if (lu && lu->parse_opt && argc) { + struct rtattr *data; + + data = addattr_nest(&req.n, sizeof(req), iflatype); + +- if (lu->parse_opt && +- lu->parse_opt(lu, argc, argv, &req.n)) ++ if (lu->parse_opt(lu, argc, argv, &req.n)) + return -1; + + addattr_nest_end(&req.n, data); +-- +cgit + diff --git a/backport-ip-fix-memory-leak-in-ip-maddr-show.patch b/backport-ip-fix-memory-leak-in-ip-maddr-show.patch new file mode 100644 index 0000000..9289aa1 --- /dev/null +++ b/backport-ip-fix-memory-leak-in-ip-maddr-show.patch @@ -0,0 +1,44 @@ +From 575322b09c3c6bc1806f2faa31edcfb64df302bb Mon Sep 17 00:00:00 2001 +From: Maxim Petrov +Date: Sun, 15 Oct 2023 16:32:12 +0200 +Subject: [PATCH] ip: fix memory leak in 'ip maddr show' + +In `read_dev_mcast`, the list of ma_info is allocated, but not cleared +after use. Free the list in the end to make valgrind happy. + +Detected by valgrind: "valgrind ./ip/ip maddr show" + +Signed-off-by: Maxim Petrov +--- + ip/ipmaddr.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/ip/ipmaddr.c b/ip/ipmaddr.c +index 176f6ab74..2418b3031 100644 +--- a/ip/ipmaddr.c ++++ b/ip/ipmaddr.c +@@ -79,6 +79,16 @@ static void maddr_ins(struct ma_info **lst, struct ma_info *m) + *lst = m; + } + ++static void maddr_clear(struct ma_info *lst) ++{ ++ struct ma_info *mp; ++ ++ while ((mp = lst) != NULL) { ++ lst = mp->next; ++ free(mp); ++ } ++} ++ + static void read_dev_mcast(struct ma_info **result_p) + { + char buf[256]; +@@ -286,6 +296,7 @@ static int multiaddr_list(int argc, char **argv) + if (!filter.family || filter.family == AF_INET6) + read_igmp6(&list); + print_mlist(stdout, list); ++ maddr_clear(list); + return 0; + } + diff --git a/backport-iplink_bridge-fix-incorrect-root-id-dump.patch b/backport-iplink_bridge-fix-incorrect-root-id-dump.patch new file mode 100644 index 0000000..d85c700 --- /dev/null +++ b/backport-iplink_bridge-fix-incorrect-root-id-dump.patch @@ -0,0 +1,34 @@ +From 3181d4e14964d7845ca9730ec6b4d7b72f3712c5 Mon Sep 17 00:00:00 2001 +From: Hangbin Liu +Date: Fri, 1 Sep 2023 16:02:26 +0800 +Subject: iplink_bridge: fix incorrect root id dump + +Conflict:NA +Reference:https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit?id=3181d4e14964d7845ca9730ec6b4d7b72f3712c5 + +Fix the typo when dump root_id. + +Fixes: 70dfb0b8836d ("iplink: bridge: export bridge_id and designated_root") +Signed-off-by: Hangbin Liu +Acked-by: Nikolay Aleksandrov +Signed-off-by: Stephen Hemminger +--- + ip/iplink_bridge.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c +index 7e4e62c81..462075295 100644 +--- a/ip/iplink_bridge.c ++++ b/ip/iplink_bridge.c +@@ -499,7 +499,7 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) + if (tb[IFLA_BR_ROOT_ID]) { + char root_id[32]; + +- br_dump_bridge_id(RTA_DATA(tb[IFLA_BR_BRIDGE_ID]), root_id, ++ br_dump_bridge_id(RTA_DATA(tb[IFLA_BR_ROOT_ID]), root_id, + sizeof(root_id)); + print_string(PRINT_ANY, + "root_id", +-- +cgit + diff --git a/backport-iproute2-prevent-memory-leak.patch b/backport-iproute2-prevent-memory-leak.patch new file mode 100644 index 0000000..473e58e --- /dev/null +++ b/backport-iproute2-prevent-memory-leak.patch @@ -0,0 +1,148 @@ +From 2c3ebb2ae08a634615e56303d784ddb366e47f04 Mon Sep 17 00:00:00 2001 +From: heminhong +Date: Thu, 16 Nov 2023 11:13:08 +0800 +Subject: [PATCH] iproute2: prevent memory leak + +When the return value of rtnl_talk() is not less than 0, +'answer' will be allocated. The 'answer' should be free +after using, otherwise it will cause memory leak. + +Fixes: a066cc6623e1 ("gre/gre6: Unify local/remote endpoint address parsing") +Signed-off-by: heminhong +Reviewed-by: Andrea Claudi +Signed-off-by: Stephen Hemminger +--- + ip/link_gre.c | 3 ++- + ip/link_gre6.c | 3 ++- + ip/link_ip6tnl.c | 3 ++- + ip/link_iptnl.c | 3 ++- + ip/link_vti.c | 3 ++- + ip/link_vti6.c | 3 ++- + 6 files changed, 12 insertions(+), 6 deletions(-) + +diff --git a/ip/link_gre.c b/ip/link_gre.c +index 74a5b5e96..6d71864c1 100644 +--- a/ip/link_gre.c ++++ b/ip/link_gre.c +@@ -76,7 +76,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, + .i.ifi_family = preferred_family, + .i.ifi_index = ifi->ifi_index, + }; +- struct nlmsghdr *answer; ++ struct nlmsghdr *answer = NULL; + struct rtattr *tb[IFLA_MAX + 1]; + struct rtattr *linkinfo[IFLA_INFO_MAX+1]; + struct rtattr *greinfo[IFLA_GRE_MAX + 1]; +@@ -113,6 +113,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, + get_failed: + fprintf(stderr, + "Failed to get existing tunnel info.\n"); ++ free(answer); + return -1; + } + +diff --git a/ip/link_gre6.c b/ip/link_gre6.c +index b03bd65ad..4d1c65748 100644 +--- a/ip/link_gre6.c ++++ b/ip/link_gre6.c +@@ -79,7 +79,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, + .i.ifi_family = preferred_family, + .i.ifi_index = ifi->ifi_index, + }; +- struct nlmsghdr *answer; ++ struct nlmsghdr *answer = NULL; + struct rtattr *tb[IFLA_MAX + 1]; + struct rtattr *linkinfo[IFLA_INFO_MAX+1]; + struct rtattr *greinfo[IFLA_GRE_MAX + 1]; +@@ -115,6 +115,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, + get_failed: + fprintf(stderr, + "Failed to get existing tunnel info.\n"); ++ free(answer); + return -1; + } + +diff --git a/ip/link_ip6tnl.c b/ip/link_ip6tnl.c +index b27d696f5..3a30dca93 100644 +--- a/ip/link_ip6tnl.c ++++ b/ip/link_ip6tnl.c +@@ -72,7 +72,7 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv, + .i.ifi_family = preferred_family, + .i.ifi_index = ifi->ifi_index, + }; +- struct nlmsghdr *answer; ++ struct nlmsghdr *answer = NULL; + struct rtattr *tb[IFLA_MAX + 1]; + struct rtattr *linkinfo[IFLA_INFO_MAX+1]; + struct rtattr *iptuninfo[IFLA_IPTUN_MAX + 1]; +@@ -101,6 +101,7 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv, + get_failed: + fprintf(stderr, + "Failed to get existing tunnel info.\n"); ++ free(answer); + return -1; + } + +diff --git a/ip/link_iptnl.c b/ip/link_iptnl.c +index 1315aebe9..879202f71 100644 +--- a/ip/link_iptnl.c ++++ b/ip/link_iptnl.c +@@ -73,7 +73,7 @@ static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv, + .i.ifi_family = preferred_family, + .i.ifi_index = ifi->ifi_index, + }; +- struct nlmsghdr *answer; ++ struct nlmsghdr *answer = NULL; + struct rtattr *tb[IFLA_MAX + 1]; + struct rtattr *linkinfo[IFLA_INFO_MAX+1]; + struct rtattr *iptuninfo[IFLA_IPTUN_MAX + 1]; +@@ -105,6 +105,7 @@ static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv, + get_failed: + fprintf(stderr, + "Failed to get existing tunnel info.\n"); ++ free(answer); + return -1; + } + +diff --git a/ip/link_vti.c b/ip/link_vti.c +index 509432543..7a95dc02d 100644 +--- a/ip/link_vti.c ++++ b/ip/link_vti.c +@@ -48,7 +48,7 @@ static int vti_parse_opt(struct link_util *lu, int argc, char **argv, + .i.ifi_family = preferred_family, + .i.ifi_index = ifi->ifi_index, + }; +- struct nlmsghdr *answer; ++ struct nlmsghdr *answer = NULL; + struct rtattr *tb[IFLA_MAX + 1]; + struct rtattr *linkinfo[IFLA_INFO_MAX+1]; + struct rtattr *vtiinfo[IFLA_VTI_MAX + 1]; +@@ -69,6 +69,7 @@ static int vti_parse_opt(struct link_util *lu, int argc, char **argv, + get_failed: + fprintf(stderr, + "Failed to get existing tunnel info.\n"); ++ free(answer); + return -1; + } + +diff --git a/ip/link_vti6.c b/ip/link_vti6.c +index 5764221eb..aaf701d33 100644 +--- a/ip/link_vti6.c ++++ b/ip/link_vti6.c +@@ -50,7 +50,7 @@ static int vti6_parse_opt(struct link_util *lu, int argc, char **argv, + .i.ifi_family = preferred_family, + .i.ifi_index = ifi->ifi_index, + }; +- struct nlmsghdr *answer; ++ struct nlmsghdr *answer = NULL; + struct rtattr *tb[IFLA_MAX + 1]; + struct rtattr *linkinfo[IFLA_INFO_MAX+1]; + struct rtattr *vtiinfo[IFLA_VTI_MAX + 1]; +@@ -71,6 +71,7 @@ static int vti6_parse_opt(struct link_util *lu, int argc, char **argv, + get_failed: + fprintf(stderr, + "Failed to get existing tunnel info.\n"); ++ free(answer); + return -1; + } + diff --git a/backport-libnetlink-Fix-memory-leak-in-__rtnl_talk_iov.patch b/backport-libnetlink-Fix-memory-leak-in-__rtnl_talk_iov.patch new file mode 100644 index 0000000..9108f13 --- /dev/null +++ b/backport-libnetlink-Fix-memory-leak-in-__rtnl_talk_iov.patch @@ -0,0 +1,86 @@ +From 0faec4d050b607f7544b6cf9a4c2d57e191f981f Mon Sep 17 00:00:00 2001 +From: Lahav Schlesinger +Date: Mon, 5 Dec 2022 10:47:41 +0200 +Subject: [PATCH] libnetlink: Fix memory leak in __rtnl_talk_iov() + +If `__rtnl_talk_iov` fails then callers are not expected to free `answer`. + +Currently if `NLMSG_ERROR` was received with an error then the netlink +buffer was stored in `answer`, while still returning an error + +This leak can be observed by running this snippet over time. +This triggers an `NLMSG_ERROR` because for each neighbour update, `ip` +will try to query for the name of interface 9999 in the wrong netns. +(which in itself is a separate bug) + + set -e + + ip netns del test-a || true + ip netns add test-a + ip netns del test-b || true + ip netns add test-b + + ip -n test-a netns set test-b auto + ip -n test-a link add veth_a index 9999 type veth \ + peer name veth_b netns test-b + ip -n test-b link set veth_b up + + ip -n test-a monitor link address prefix neigh nsid label all-nsid \ + > /dev/null & + monitor_pid=$! + clean() { + kill $monitor_pid + ip netns del test-a + ip netns del test-b + } + trap clean EXIT + + while true; do + ip -n test-b neigh add dev veth_b 1.2.3.4 lladdr AA:AA:AA:AA:AA:AA + ip -n test-b neigh del dev veth_b 1.2.3.4 + done + + +Conflict:NA +Reference:https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit?id=0faec4d050b607f7544b6cf9a4c2d57e191f981f + +Fixes: 55870dfe7f8b ("Improve batch and dump times by caching link lookups") +Signed-off-by: Lahav Schlesinger +Signed-off-by: Gilad Naaman +Signed-off-by: Stephen Hemminger +--- + lib/libnetlink.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/lib/libnetlink.c b/lib/libnetlink.c +index 9af06232..001efc1d 100644 +--- a/lib/libnetlink.c ++++ b/lib/libnetlink.c +@@ -1092,14 +1092,19 @@ next: + rtnl_talk_error(h, err, errfn); + } + +- if (answer) +- *answer = (struct nlmsghdr *)buf; +- else ++ if (i < iovlen) { + free(buf); +- +- if (i < iovlen) + goto next; +- return error ? -i : 0; ++ } ++ ++ if (error) { ++ free(buf); ++ return -i; ++ } ++ ++ if (answer) ++ *answer = (struct nlmsghdr *)buf; ++ return 0; + } + + if (answer) { +-- +2.23.0 diff --git a/backport-libnetlink-validate-nlmsg-header-length-first.patch b/backport-libnetlink-validate-nlmsg-header-length-first.patch new file mode 100644 index 0000000..5b53231 --- /dev/null +++ b/backport-libnetlink-validate-nlmsg-header-length-first.patch @@ -0,0 +1,39 @@ +From 78eebdbc7d2f96b01a18d7db33c1c99266efc4bc Mon Sep 17 00:00:00 2001 +From: Max Kunzelmann +Date: Tue, 7 Nov 2023 01:20:55 +0000 +Subject: [PATCH] libnetlink: validate nlmsg header length first + +Validate the nlmsg header length before accessing the nlmsg payload +length. + +Fixes: 892a25e286fb ("libnetlink: break up dump function") + +Signed-off-by: Max Kunzelmann +Reviewed-by: Benny Baumann +Reviewed-by: Robert Geislinger +Signed-off-by: Stephen Hemminger +--- + lib/libnetlink.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/lib/libnetlink.c b/lib/libnetlink.c +index 7edcd2856..016482294 100644 +--- a/lib/libnetlink.c ++++ b/lib/libnetlink.c +@@ -727,13 +727,15 @@ int rtnl_dump_request_n(struct rtnl_handle *rth, struct nlmsghdr *n) + static int rtnl_dump_done(struct nlmsghdr *h, + const struct rtnl_dump_filter_arg *a) + { +- int len = *(int *)NLMSG_DATA(h); ++ int len; + + if (h->nlmsg_len < NLMSG_LENGTH(sizeof(int))) { + fprintf(stderr, "DONE truncated\n"); + return -1; + } + ++ len = *(int *)NLMSG_DATA(h); ++ + if (len < 0) { + errno = -len; + diff --git a/backport-lnstat-Fix-deref-of-null-in-print_json-function.patch b/backport-lnstat-Fix-deref-of-null-in-print_json-function.patch new file mode 100644 index 0000000..fab9096 --- /dev/null +++ b/backport-lnstat-Fix-deref-of-null-in-print_json-function.patch @@ -0,0 +1,32 @@ +From a193733b7a7ef1e65e1b88045c32f96ed16caeb9 Mon Sep 17 00:00:00 2001 +From: Maks Mishin +Date: Sat, 6 Jan 2024 22:04:23 +0300 +Subject: [PATCH] lnstat: Fix deref of null in print_json() function + +Now pointer `jw` is being checked for NULL before using +in function `jsonw_start_object`. +Added exit from function when `jw==NULL`. + +Found by RASU JSC + +Signed-off-by: Maks Mishin +Signed-off-by: Stephen Hemminger +--- + misc/lnstat.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/misc/lnstat.c b/misc/lnstat.c +index c3f2999cc..f802a0f35 100644 +--- a/misc/lnstat.c ++++ b/misc/lnstat.c +@@ -112,6 +112,10 @@ static void print_json(FILE *of, const struct lnstat_file *lnstat_files, + json_writer_t *jw = jsonw_new(of); + int i; + ++ if (jw == NULL) { ++ fprintf(stderr, "Failed to create JSON writer\n"); ++ exit(1); ++ } + jsonw_start_object(jw); + for (i = 0; i < fp->num; i++) { + const struct lnstat_field *lf = fp->params[i].lf; diff --git a/backport-mnl_utils-sanitize-incoming-netlink-payload-size-in-callbacks.patch b/backport-mnl_utils-sanitize-incoming-netlink-payload-size-in-callbacks.patch new file mode 100644 index 0000000..90ad01b --- /dev/null +++ b/backport-mnl_utils-sanitize-incoming-netlink-payload-size-in-callbacks.patch @@ -0,0 +1,47 @@ +From 1a68525f4613b4e02e83d4b8004f22ac7ecbfedf Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Thu, 7 Dec 2023 13:53:51 +0100 +Subject: [PATCH] mnl_utils: sanitize incoming netlink payload size in + callbacks + +Don't trust the kernel to send payload of certain size. Sanitize that by +checking the payload length in mnlu_cb_stop() and mnlu_cb_error() and +only access the payload if it is of required size. + +Note that for mnlu_cb_stop(), this is happening already for example +with devlink resource. Kernel sends NLMSG_DONE with zero size payload. + +Fixes: 049c58539f5d ("devlink: mnlg: Add support for extended ack") +Fixes: c934da8aaacb ("devlink: mnlg: Catch returned error value of dumpit commands") +Signed-off-by: Jiri Pirko +Signed-off-by: Stephen Hemminger +--- + lib/mnl_utils.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/lib/mnl_utils.c b/lib/mnl_utils.c +index 1c7822282..af5aa4f9e 100644 +--- a/lib/mnl_utils.c ++++ b/lib/mnl_utils.c +@@ -61,6 +61,8 @@ static int mnlu_cb_error(const struct nlmsghdr *nlh, void *data) + { + const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh); + ++ if (mnl_nlmsg_get_payload_len(nlh) < sizeof(*err)) ++ return MNL_CB_STOP; + /* Netlink subsystems returns the errno value with different signess */ + if (err->error < 0) + errno = -err->error; +@@ -75,8 +77,11 @@ static int mnlu_cb_error(const struct nlmsghdr *nlh, void *data) + + static int mnlu_cb_stop(const struct nlmsghdr *nlh, void *data) + { +- int len = *(int *)NLMSG_DATA(nlh); ++ int len; + ++ if (mnl_nlmsg_get_payload_len(nlh) < sizeof(len)) ++ return MNL_CB_STOP; ++ len = *(int *)mnl_nlmsg_get_payload(nlh); + if (len < 0) { + errno = -len; + nl_dump_ext_ack_done(nlh, len); diff --git a/backport-ss-Fix-socket-type-check-in-packet_show_line.patch b/backport-ss-Fix-socket-type-check-in-packet_show_line.patch new file mode 100644 index 0000000..e6eb4df --- /dev/null +++ b/backport-ss-Fix-socket-type-check-in-packet_show_line.patch @@ -0,0 +1,37 @@ +From 92e9915c36b7d4820f004fa74e0d93be99b8272a Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Tue, 22 Aug 2023 14:19:16 +0200 +Subject: ss: Fix socket type check in packet_show_line() + +Conflict:NA +Reference:https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit?id=92e9915c36b7d4820f004fa74e0d93be99b8272a + +The field is accessed before being assigned a meaningful value, +effectively disabling the checks. + +Fixes: 4a0053b606a34 ("ss: Unify packet stats output from netlink and proc") +Signed-off-by: Phil Sutter +Signed-off-by: Stephen Hemminger +--- + misc/ss.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/misc/ss.c b/misc/ss.c +index c71b08f98..653b1512c 100644 +--- a/misc/ss.c ++++ b/misc/ss.c +@@ -4535,9 +4535,9 @@ static int packet_show_line(char *buf, const struct filter *f, int fam) + &type, &prot, &iface, &state, + &rq, &uid, &ino); + +- if (stat.type == SOCK_RAW && !(f->dbs&(1<dbs & (1<dbs&(1<dbs & (1< +Date: Tue, 8 Aug 2023 23:42:57 +0200 +Subject: ss: change aafilter port from int to long (inode support) + +Conflict:NA +Reference:https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit?id=012cb5152d05122299384c9159ea82d059c80873 + +The aafilter struct considers the port as (usually) 32 bit signed +integer. In case of a unix socket, the port is used with an inode +number which is an unsigned int. In this case, the 'ss' command +fails because it assumes that the value does not look like a port +(<0). + +Here an example of command call where the inode is passed and +is larger than a signed integer: + +ss -H -A unix_stream src :2259952798 + +Signed-off-by: Mathieu Schroeter +Signed-off-by: David Ahern +--- + misc/ss.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/misc/ss.c b/misc/ss.c +index e9d813596..baa835149 100644 +--- a/misc/ss.c ++++ b/misc/ss.c +@@ -1733,7 +1733,7 @@ static void inet_addr_print(const inet_prefix *a, int port, + + struct aafilter { + inet_prefix addr; +- int port; ++ long port; + unsigned int iface; + __u32 mark; + __u32 mask; +@@ -2256,7 +2256,7 @@ void *parse_hostcond(char *addr, bool is_port) + port = find_port(addr, is_port); + if (port) { + if (*port && strcmp(port, "*")) { +- if (get_integer(&a.port, port, 0)) { ++ if (get_long(&a.port, port, 0)) { + if ((a.port = xll_name_to_index(port)) <= 0) + return NULL; + } +@@ -2279,7 +2279,7 @@ void *parse_hostcond(char *addr, bool is_port) + port = find_port(addr, is_port); + if (port) { + if (*port && strcmp(port, "*")) { +- if (get_integer(&a.port, port, 0)) { ++ if (get_long(&a.port, port, 0)) { + if (strcmp(port, "kernel") == 0) + a.port = 0; + else +@@ -2335,7 +2335,7 @@ void *parse_hostcond(char *addr, bool is_port) + *port++ = 0; + + if (*port && *port != '*') { +- if (get_integer(&a.port, port, 0)) { ++ if (get_long(&a.port, port, 0)) { + struct servent *se1 = NULL; + struct servent *se2 = NULL; + +-- +cgit + diff --git a/backport-ss-print-unix-socket-ports-as-unsigned-int-inode.patch b/backport-ss-print-unix-socket-ports-as-unsigned-int-inode.patch new file mode 100644 index 0000000..7e0b410 --- /dev/null +++ b/backport-ss-print-unix-socket-ports-as-unsigned-int-inode.patch @@ -0,0 +1,33 @@ +From e12d0c929cf5f4266f745063696dd291cb6f06a4 Mon Sep 17 00:00:00 2001 +From: Mathieu Schroeter +Date: Tue, 8 Aug 2023 23:42:58 +0200 +Subject: ss: print unix socket "ports" as unsigned int (inode) + +Conflict:NA +Reference:https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit?id=e12d0c929cf5f4266f745063696dd291cb6f06a4 + +Signed-off-by: Mathieu Schroeter +Signed-off-by: David Ahern +--- + misc/ss.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/misc/ss.c b/misc/ss.c +index baa835149..13b2523f4 100644 +--- a/misc/ss.c ++++ b/misc/ss.c +@@ -4073,9 +4073,9 @@ static void unix_stats_print(struct sockstat *s, struct filter *f) + sock_state_print(s); + + sock_addr_print(s->name ?: "*", " ", +- int_to_str(s->lport, port_name), NULL); ++ uint_to_str(s->lport, port_name), NULL); + sock_addr_print(s->peer_name ?: "*", " ", +- int_to_str(s->rport, port_name), NULL); ++ uint_to_str(s->rport, port_name), NULL); + + proc_ctx_print(s); + } +-- +cgit + diff --git a/backport-tc-ct-Fix-invalid-pointer-dereference.patch b/backport-tc-ct-Fix-invalid-pointer-dereference.patch new file mode 100644 index 0000000..818d741 --- /dev/null +++ b/backport-tc-ct-Fix-invalid-pointer-dereference.patch @@ -0,0 +1,35 @@ +From 4de59102f49ff9128378568cf967d6c7aabea6f2 Mon Sep 17 00:00:00 2001 +From: Roi Dayan +Date: Wed, 7 Dec 2022 10:22:13 +0200 +Subject: [PATCH] tc: ct: Fix invalid pointer dereference + +Using macro NEXT_ARG_FWD does not validate argc. +Use macro NEXT_ARG which validates argc while parsing args +in the same loop iteration. + +Conflict:NA +Reference:https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit?id=4de59102f49ff9128378568cf967d6c7aabea6f2 + +Fixes: c8a494314c40 ("tc: Introduce tc ct action") +Signed-off-by: Roi Dayan +Reviewed-by: Paul Blakey +Signed-off-by: Stephen Hemminger +--- + tc/m_ct.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tc/m_ct.c b/tc/m_ct.c +index a02bf0cc..54d64867 100644 +--- a/tc/m_ct.c ++++ b/tc/m_ct.c +@@ -243,7 +243,7 @@ parse_ct(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, + return -1; + } + +- NEXT_ARG_FWD(); ++ NEXT_ARG(); + if (matches(*argv, "port") != 0) + continue; + +-- +2.23.0 diff --git a/backport-tc-remove-tcindex-classifier.patch b/backport-tc-remove-tcindex-classifier.patch new file mode 100644 index 0000000..812b919 --- /dev/null +++ b/backport-tc-remove-tcindex-classifier.patch @@ -0,0 +1,336 @@ +From bc0c1661eb229b77a65f8c5f305fd6fa56e9667f Mon Sep 17 00:00:00 2001 +From: Stephen Hemminger +Date: Mon, 30 Oct 2023 11:26:33 -0700 +Subject: [PATCH] tc: remove tcindex classifier + +Support for tcindex classifier was removed by upstream commit +8c710f75256b (net/sched: Retire tcindex classifier, 2023-02-14) + +Signed-off-by: Stephen Hemminger +--- + bash-completion/tc | 7 +- + man/man8/tc-tcindex.8 | 58 ------------- + man/man8/tc.8 | 7 +- + tc/Makefile | 1 - + tc/f_tcindex.c | 185 ------------------------------------------ + 5 files changed, 2 insertions(+), 256 deletions(-) + delete mode 100644 man/man8/tc-tcindex.8 + delete mode 100644 tc/f_tcindex.c + +diff --git a/bash-completion/tc b/bash-completion/tc +index 6af3b7998..db5558ab6 100644 +--- a/bash-completion/tc ++++ b/bash-completion/tc +@@ -5,7 +5,7 @@ + QDISC_KIND=' choke codel bfifo pfifo pfifo_head_drop fq fq_codel gred hhf \ + mqprio multiq netem pfifo_fast pie fq_pie red rr sfb sfq tbf atm \ + cbq drr dsmark hfsc htb prio qfq ' +-FILTER_KIND=' basic bpf cgroup flow flower fw route rsvp tcindex u32 matchall ' ++FILTER_KIND=' basic bpf cgroup flow flower fw route rsvp u32 matchall ' + ACTION_KIND=' gact mirred bpf sample ' + + # Takes a list of words in argument; each one of them is added to COMPREPLY if +@@ -487,11 +487,6 @@ _tc_filter_options() + COMPREPLY+=( $( compgen -W 'at' -- "$cur" ) ) + return 0 + ;; +- tcindex) +- _tc_once_attr 'hash mask shift classid action' +- _tc_one_of_list 'pass_on fall_through' +- return 0 +- ;; + u32) + _tc_once_attr 'match link classid action offset ht hashkey sample' + COMPREPLY+=( $( compgen -W 'ip ip6 udp tcp icmp u8 u16 u32 mark \ +diff --git a/man/man8/tc-tcindex.8 b/man/man8/tc-tcindex.8 +deleted file mode 100644 +index ccf2c5e81..000000000 +--- a/man/man8/tc-tcindex.8 ++++ /dev/null +@@ -1,58 +0,0 @@ +-.TH "Traffic control index filter" 8 "21 Oct 2015" "iproute2" "Linux" +- +-.SH NAME +-tcindex \- traffic control index filter +-.SH SYNOPSIS +-.in +8 +-.ti -8 +-.BR tc " " filter " ... " tcindex " [ " hash +-.IR SIZE " ] [ " +-.B mask +-.IR MASK " ] [ " +-.B shift +-.IR SHIFT " ] [ " +-.BR pass_on " | " fall_through " ] [ " classid +-.IR CLASSID " ] [ " +-.B action +-.BR ACTION_SPEC " ]" +-.SH DESCRIPTION +-This filter allows to match packets based on their +-.B tcindex +-field value, i.e. the combination of the DSCP and ECN fields as present in IPv4 +-and IPv6 headers. +-.SH OPTIONS +-.TP +-.BI action " ACTION_SPEC" +-Apply an action from the generic actions framework on matching packets. +-.TP +-.BI classid " CLASSID" +-Push matching packets into the class identified by +-.IR CLASSID . +-.TP +-.BI hash " SIZE" +-Hash table size in entries to use. Defaults to 64. +-.TP +-.BI mask " MASK" +-An optional bitmask to binary +-.BR AND " to the packet's " tcindex +-field before use. +-.TP +-.BI shift " SHIFT" +-The number of bits to right-shift a packet's +-.B tcindex +-value before use. If a +-.B mask +-has been set, masking is done before shifting. +-.TP +-.B pass_on +-If this flag is set, failure to find a class for the resulting ID will make the +-filter fail and lead to the next filter being consulted. +-.TP +-.B fall_through +-This is the opposite of +-.B pass_on +-and the default. The filter will classify the packet even if there is no class +-present for the resulting class ID. +- +-.SH SEE ALSO +-.BR tc (8) +diff --git a/man/man8/tc.8 b/man/man8/tc.8 +index 59cc7b17d..ae6de397f 100644 +--- a/man/man8/tc.8 ++++ b/man/man8/tc.8 +@@ -244,10 +244,6 @@ for details. + rsvp + Match Resource Reservation Protocol (RSVP) packets. + .TP +-tcindex +-Filter packets based on traffic control index. See +-.BR tc-tcindex (8). +-.TP + u32 + Generic filtering on arbitrary packet data, assisted by syntax to abstract common operations. See + .BR tc-u32 (8) +@@ -906,8 +902,7 @@ was written by Alexey N. Kuznetsov and added in Linux 2.2. + .BR tc-sfq (8), + .BR tc-stab (8), + .BR tc-tbf (8), +-.BR tc-tcindex (8), +-.BR tc-u32 (8), ++.BR tc-u32 (8) + .br + .RB "User documentation at " http://lartc.org/ ", but please direct bugreports and patches to: " + +diff --git a/tc/Makefile b/tc/Makefile +index 82e611257..ab6ad2f5d 100644 +--- a/tc/Makefile ++++ b/tc/Makefile +@@ -31,7 +31,6 @@ TCMODULES += f_cgroup.o + TCMODULES += f_flower.o + TCMODULES += q_dsmark.o + TCMODULES += q_gred.o +-TCMODULES += f_tcindex.o + TCMODULES += q_ingress.o + TCMODULES += q_hfsc.o + TCMODULES += q_htb.o +diff --git a/tc/f_tcindex.c b/tc/f_tcindex.c +deleted file mode 100644 +index ae4cbf118..000000000 +--- a/tc/f_tcindex.c ++++ /dev/null +@@ -1,185 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0 */ +-/* +- * f_tcindex.c Traffic control index filter +- * +- * Written 1998,1999 by Werner Almesberger +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "utils.h" +-#include "tc_util.h" +- +-static void explain(void) +-{ +- fprintf(stderr, +- " Usage: ... tcindex [ hash SIZE ] [ mask MASK ] [ shift SHIFT ]\n" +- " [ pass_on | fall_through ]\n" +- " [ classid CLASSID ] [ action ACTION_SPEC ]\n"); +-} +- +-static int tcindex_parse_opt(struct filter_util *qu, char *handle, int argc, +- char **argv, struct nlmsghdr *n) +-{ +- struct tcmsg *t = NLMSG_DATA(n); +- struct rtattr *tail; +- char *end; +- +- if (handle) { +- t->tcm_handle = strtoul(handle, &end, 0); +- if (*end) { +- fprintf(stderr, "Illegal filter ID\n"); +- return -1; +- } +- } +- if (!argc) return 0; +- tail = addattr_nest(n, 4096, TCA_OPTIONS); +- while (argc) { +- if (!strcmp(*argv, "hash")) { +- int hash; +- +- NEXT_ARG(); +- hash = strtoul(*argv, &end, 0); +- if (*end || !hash || hash > 0x10000) { +- explain(); +- return -1; +- } +- addattr_l(n, 4096, TCA_TCINDEX_HASH, &hash, +- sizeof(hash)); +- } else if (!strcmp(*argv,"mask")) { +- __u16 mask; +- +- NEXT_ARG(); +- mask = strtoul(*argv, &end, 0); +- if (*end) { +- explain(); +- return -1; +- } +- addattr_l(n, 4096, TCA_TCINDEX_MASK, &mask, +- sizeof(mask)); +- } else if (!strcmp(*argv,"shift")) { +- int shift; +- +- NEXT_ARG(); +- shift = strtoul(*argv, &end, 0); +- if (*end) { +- explain(); +- return -1; +- } +- addattr_l(n, 4096, TCA_TCINDEX_SHIFT, &shift, +- sizeof(shift)); +- } else if (!strcmp(*argv,"fall_through")) { +- int value = 1; +- +- addattr_l(n, 4096, TCA_TCINDEX_FALL_THROUGH, &value, +- sizeof(value)); +- } else if (!strcmp(*argv,"pass_on")) { +- int value = 0; +- +- addattr_l(n, 4096, TCA_TCINDEX_FALL_THROUGH, &value, +- sizeof(value)); +- } else if (!strcmp(*argv,"classid")) { +- __u32 handle; +- +- NEXT_ARG(); +- if (get_tc_classid(&handle, *argv)) { +- fprintf(stderr, "Illegal \"classid\"\n"); +- return -1; +- } +- addattr_l(n, 4096, TCA_TCINDEX_CLASSID, &handle, 4); +- } else if (!strcmp(*argv,"police")) { +- NEXT_ARG(); +- if (parse_police(&argc, &argv, TCA_TCINDEX_POLICE, n)) { +- fprintf(stderr, "Illegal \"police\"\n"); +- return -1; +- } +- continue; +- } else if (!strcmp(*argv,"action")) { +- NEXT_ARG(); +- if (parse_action(&argc, &argv, TCA_TCINDEX_ACT, n)) { +- fprintf(stderr, "Illegal \"action\"\n"); +- return -1; +- } +- continue; +- } else { +- explain(); +- return -1; +- } +- argc--; +- argv++; +- } +- addattr_nest_end(n, tail); +- return 0; +-} +- +- +-static int tcindex_print_opt(struct filter_util *qu, FILE *f, +- struct rtattr *opt, __u32 handle) +-{ +- struct rtattr *tb[TCA_TCINDEX_MAX+1]; +- +- if (opt == NULL) +- return 0; +- +- parse_rtattr_nested(tb, TCA_TCINDEX_MAX, opt); +- +- if (handle != ~0) fprintf(f, "handle 0x%04x ", handle); +- if (tb[TCA_TCINDEX_HASH]) { +- __u16 hash; +- +- if (RTA_PAYLOAD(tb[TCA_TCINDEX_HASH]) < sizeof(hash)) +- return -1; +- hash = rta_getattr_u16(tb[TCA_TCINDEX_HASH]); +- fprintf(f, "hash %d ", hash); +- } +- if (tb[TCA_TCINDEX_MASK]) { +- __u16 mask; +- +- if (RTA_PAYLOAD(tb[TCA_TCINDEX_MASK]) < sizeof(mask)) +- return -1; +- mask = rta_getattr_u16(tb[TCA_TCINDEX_MASK]); +- fprintf(f, "mask 0x%04x ", mask); +- } +- if (tb[TCA_TCINDEX_SHIFT]) { +- int shift; +- +- if (RTA_PAYLOAD(tb[TCA_TCINDEX_SHIFT]) < sizeof(shift)) +- return -1; +- shift = rta_getattr_u32(tb[TCA_TCINDEX_SHIFT]); +- fprintf(f, "shift %d ", shift); +- } +- if (tb[TCA_TCINDEX_FALL_THROUGH]) { +- int fall_through; +- +- if (RTA_PAYLOAD(tb[TCA_TCINDEX_FALL_THROUGH]) < +- sizeof(fall_through)) +- return -1; +- fall_through = rta_getattr_u32(tb[TCA_TCINDEX_FALL_THROUGH]); +- fprintf(f, fall_through ? "fall_through " : "pass_on "); +- } +- if (tb[TCA_TCINDEX_CLASSID]) { +- SPRINT_BUF(b1); +- fprintf(f, "classid %s ", sprint_tc_classid(*(__u32 *) +- RTA_DATA(tb[TCA_TCINDEX_CLASSID]), b1)); +- } +- if (tb[TCA_TCINDEX_POLICE]) { +- fprintf(f, "\n"); +- tc_print_police(f, tb[TCA_TCINDEX_POLICE]); +- } +- if (tb[TCA_TCINDEX_ACT]) { +- fprintf(f, "\n"); +- tc_print_action(f, tb[TCA_TCINDEX_ACT], 0); +- } +- return 0; +-} +- +-struct filter_util tcindex_filter_util = { +- .id = "tcindex", +- .parse_fopt = tcindex_parse_opt, +- .print_fopt = tcindex_print_opt, +-}; diff --git a/backport-tc_util-Change-datatype-for-maj-to-avoid-overflow-issue.patch b/backport-tc_util-Change-datatype-for-maj-to-avoid-overflow-issue.patch new file mode 100644 index 0000000..dc41e63 --- /dev/null +++ b/backport-tc_util-Change-datatype-for-maj-to-avoid-overflow-issue.patch @@ -0,0 +1,33 @@ +From 455fa8295298a68a2dedabf9dd4c1dbf847b128b Mon Sep 17 00:00:00 2001 +From: Lai Peter Jun Ann +Date: Mon, 21 Nov 2022 10:29:09 +0800 +Subject: [PATCH] tc_util: Change datatype for maj to avoid overflow issue + +The return value by stroul() is unsigned long int. Hence the datatype +for maj should defined as unsigned long to avoid overflow issue. + +Conflict:NA +Reference:https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit?id=455fa8295298a68a2dedabf9dd4c1dbf847b128b + +Signed-off-by: Muhammad Husaini Zulkifli +Signed-off-by: Lai Peter Jun Ann +Signed-off-by: Stephen Hemminger +--- + tc/tc_util.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tc/tc_util.c b/tc/tc_util.c +index 334334db..8cd3c035 100644 +--- a/tc/tc_util.c ++++ b/tc/tc_util.c +@@ -74,7 +74,7 @@ const char *get_tc_lib(void) + + int get_qdisc_handle(__u32 *h, const char *str) + { +- __u32 maj; ++ unsigned long maj; + char *p; + + maj = TC_H_UNSPEC; +-- +2.23.0 diff --git a/backport-tc_util-Fix-no-error-return-when-large-parent-id-used.patch b/backport-tc_util-Fix-no-error-return-when-large-parent-id-used.patch new file mode 100644 index 0000000..cd95f83 --- /dev/null +++ b/backport-tc_util-Fix-no-error-return-when-large-parent-id-used.patch @@ -0,0 +1,35 @@ +From e0ecee3a33af57e01fe5d15f1a436216412f2d96 Mon Sep 17 00:00:00 2001 +From: Lai Peter Jun Ann +Date: Thu, 17 Nov 2022 13:33:17 +0800 +Subject: [PATCH] tc_util: Fix no error return when large parent id used + +This patch is to fix the issue where there is no error return +when large value of parent ID is being used. The return value by +stroul() is unsigned long int. Hence the datatype for maj and min +should defined as unsigned long to avoid overflow issue. + +Conflict:NA +Reference:https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit?id=e0ecee3a33af57e01fe5d15f1a436216412f2d96 + +Signed-off-by: Muhammad Husaini Zulkifli +Signed-off-by: Lai Peter Jun Ann +Signed-off-by: Stephen Hemminger +--- + tc/tc_util.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tc/tc_util.c b/tc/tc_util.c +index 44137adb..334334db 100644 +--- a/tc/tc_util.c ++++ b/tc/tc_util.c +@@ -93,7 +93,7 @@ ok: + + int get_tc_classid(__u32 *h, const char *str) + { +- __u32 maj, min; ++ unsigned long maj, min; + char *p; + + maj = TC_H_ROOT; +-- +2.23.0 diff --git a/backport-utils-fix-get_integer-logic.patch b/backport-utils-fix-get_integer-logic.patch new file mode 100644 index 0000000..1a99832 --- /dev/null +++ b/backport-utils-fix-get_integer-logic.patch @@ -0,0 +1,33 @@ +From 877f8149d2ed94b6ab412fabaab9fe8d15193db7 Mon Sep 17 00:00:00 2001 +From: Pedro Tammela +Date: Sat, 19 Aug 2023 17:54:48 -0300 +Subject: [PATCH] utils: fix get_integer() logic + +Conflict:NA +Reference:https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit?id=877f8149d2ed94b6ab412fabaab9fe8d15193db7 + +After 3a463c15, get_integer() doesn't return the converted value and +always writes 0 in 'val' in case of success. +Fix the logic so it writes the converted value in 'val'. + +Fixes: 3a463c15 ("Add get_long utility and adapt get_integer accordingly" +Signed-off-by: Pedro Tammela +Signed-off-by: David Ahern +--- + lib/utils.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/lib/utils.c b/lib/utils.c +index efa01668d..99ba7a233 100644 +--- a/lib/utils.c ++++ b/lib/utils.c +@@ -142,7 +142,8 @@ int get_integer(int *val, const char *arg, int base) + { + long res; + +- res = get_long(NULL, arg, base); ++ if (get_long(&res, arg, base) < 0) ++ return -1; + + /* Outside range of int */ + if (res < INT_MIN || res > INT_MAX) diff --git a/backport-xfrm-prepare-state-offload-logic-to-set-mode.patch b/backport-xfrm-prepare-state-offload-logic-to-set-mode.patch new file mode 100644 index 0000000..08143f6 --- /dev/null +++ b/backport-xfrm-prepare-state-offload-logic-to-set-mode.patch @@ -0,0 +1,117 @@ +From bdd19b1edec44c00c968950301074734cee54cab Mon Sep 17 00:00:00 2001 +From: Leon Romanovsky +Date: Mon, 12 Dec 2022 09:54:04 +0200 +Subject: [PATCH] xfrm: prepare state offload logic to set mode + +The offload in xfrm state requires to provide device and direction +in order to activate it. However, in the help section, device and +direction were displayed as an optional. + +As a preparation to addition of packet offload, let's fix the help +section and refactor the code to be more clear. + +Conflict:NA +Reference:https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit?id=bdd19b1edec44c00c968950301074734cee54cab + +Signed-off-by: Leon Romanovsky +Signed-off-by: David Ahern +--- + ip/xfrm_state.c | 35 +++++++++++++++++++---------------- + man/man8/ip-xfrm.8 | 5 +++++ + 2 files changed, 24 insertions(+), 16 deletions(-) + +diff --git a/ip/xfrm_state.c b/ip/xfrm_state.c +index b2294d9f..6de2d28d 100644 +--- a/ip/xfrm_state.c ++++ b/ip/xfrm_state.c +@@ -61,7 +61,7 @@ static void usage(void) + " [ replay-seq-hi SEQ ] [ replay-oseq-hi SEQ ]\n" + " [ flag FLAG-LIST ] [ sel SELECTOR ] [ LIMIT-LIST ] [ encap ENCAP ]\n" + " [ coa ADDR[/PLEN] ] [ ctx CTX ] [ extra-flag EXTRA-FLAG-LIST ]\n" +- " [ offload [dev DEV] dir DIR ]\n" ++ " [ offload dev DEV dir DIR ]\n" + " [ output-mark OUTPUT-MARK [ mask MASK ] ]\n" + " [ if_id IF_ID ] [ tfcpad LENGTH ]\n" + "Usage: ip xfrm state allocspi ID [ mode MODE ] [ mark MARK [ mask MASK ] ]\n" +@@ -267,7 +267,7 @@ static int xfrm_state_extra_flag_parse(__u32 *extra_flags, int *argcp, char ***a + return 0; + } + +-static int xfrm_offload_dir_parse(__u8 *dir, int *argcp, char ***argvp) ++static bool xfrm_offload_dir_parse(__u8 *dir, int *argcp, char ***argvp) + { + int argc = *argcp; + char **argv = *argvp; +@@ -277,12 +277,12 @@ static int xfrm_offload_dir_parse(__u8 *dir, int *argcp, char ***argvp) + else if (strcmp(*argv, "out") == 0) + *dir = 0; + else +- invarg("DIR value is invalid", *argv); ++ return false; + + *argcp = argc; + *argvp = argv; + +- return 0; ++ return true; + } + + static int xfrm_state_modify(int cmd, unsigned int flags, int argc, char **argv) +@@ -424,24 +424,27 @@ static int xfrm_state_modify(int cmd, unsigned int flags, int argc, char **argv) + addattr_l(&req.n, sizeof(req.buf), XFRMA_SEC_CTX, + (void *)&ctx, ctx.sctx.len); + } else if (strcmp(*argv, "offload") == 0) { +- is_offload = true; + NEXT_ARG(); + if (strcmp(*argv, "dev") == 0) { + NEXT_ARG(); + ifindex = ll_name_to_index(*argv); +- if (!ifindex) { +- invarg("value after \"offload dev\" is invalid", *argv); +- is_offload = false; +- } +- NEXT_ARG(); +- } ++ if (!ifindex) ++ invarg("Invalid device name", *argv); ++ } else ++ invarg("Missing dev keyword", *argv); ++ ++ NEXT_ARG(); + if (strcmp(*argv, "dir") == 0) { ++ bool is_dir; ++ + NEXT_ARG(); +- xfrm_offload_dir_parse(&dir, &argc, &argv); +- } else { +- invarg("value after \"offload dir\" is invalid", *argv); +- is_offload = false; +- } ++ is_dir = xfrm_offload_dir_parse(&dir, &argc, ++ &argv); ++ if (!is_dir) ++ invarg("DIR value is invalid", *argv); ++ } else ++ invarg("Missing DIR keyword", *argv); ++ is_offload = true; + } else if (strcmp(*argv, "output-mark") == 0) { + NEXT_ARG(); + if (get_u32(&output_mark.v, *argv, 0)) +diff --git a/man/man8/ip-xfrm.8 b/man/man8/ip-xfrm.8 +index bf725cab..4243a023 100644 +--- a/man/man8/ip-xfrm.8 ++++ b/man/man8/ip-xfrm.8 +@@ -65,6 +65,11 @@ ip-xfrm \- transform configuration + .IR MASK " ] ]" + .RB "[ " if_id + .IR IF-ID " ]" ++.RB "[ " offload ++.RB dev ++.IR DEV " ++.RB dir ++.IR DIR " ]" + .RB "[ " tfcpad + .IR LENGTH " ]" + +-- +2.23.0 diff --git a/iproute.spec b/iproute.spec index a3d10ae..c6a0cfa 100644 --- a/iproute.spec +++ b/iproute.spec @@ -2,7 +2,7 @@ Name: iproute Version: 5.15.0 Epoch: 1 -Release: 15 +Release: 19 Summary: Linux network configuration utilities License: GPLv2+ and Public Domain URL: https://kernel.org/pub/linux/utils/net/iproute2/ @@ -43,11 +43,35 @@ Patch6027: backport-rdma-utils-fix-some-analyzer-warnings.patch Patch6028: backport-tc-prio-handle-possible-truncated-kernel-response.patch Patch6029: backport-iproute_lwtunnel-fix-array-boundary-check.patch Patch6030: backport-rt_names-check-for-malloc-failure.patch +Patch6031: backport-tc_util-Fix-no-error-return-when-large-parent-id-used.patch +Patch6032: backport-tc_util-Change-datatype-for-maj-to-avoid-overflow-issue.patch +Patch6033: backport-tc-ct-Fix-invalid-pointer-dereference.patch +Patch6034: backport-libnetlink-Fix-memory-leak-in-__rtnl_talk_iov.patch +Patch6035: backport-xfrm-prepare-state-offload-logic-to-set-mode.patch +Patch6036: backport-Add-get_long-utility-and-adapt-get_integer-accordingly.patch +Patch6037: backport-Add-utility-to-convert-an-unsigned-int-to-string.patch +Patch6038: backport-f_flower-Treat-port-0-as-valid.patch +Patch6039: backport-ip-error-out-if-iplink-does-not-consume-all-options.patch +Patch6040: backport-iplink_bridge-fix-incorrect-root-id-dump.patch +Patch6041: backport-ss-change-aafilter-port-from-int-to-long-inode-support.patch +Patch6042: backport-ss-Fix-socket-type-check-in-packet_show_line.patch +Patch6043: backport-ss-print-unix-socket-ports-as-unsigned-int-inode.patch +Patch6044: backport-utils-fix-get_integer-logic.patch + +patch6045: backport-lnstat-Fix-deref-of-null-in-print_json-function.patch +patch6046: backport-iproute2-prevent-memory-leak.patch +patch6047: backport-libnetlink-validate-nlmsg-header-length-first.patch +patch6048: backport-tc-remove-tcindex-classifier.patch +patch6049: backport-ip-fix-memory-leak-in-ip-maddr-show.patch +patch6050: backport-ila-fix-potential-snprintf-buffer-overflow.patch +patch6051: backport-bridge-fix-potential-snprintf-overflow.patch +patch6052: backport-mnl_utils-sanitize-incoming-netlink-payload-size-in-callbacks.patch Patch9000: feature-iproute-add-support-for-ipvlan-l2e-mode.patch Patch9001: bugfix-iproute2-cancel-some-test-cases.patch -Patch9002: feature-iproute2-supports-to-parse-UB-device-and-related-display-of-vf-address.patch +Patch9002: feature-iproute2-supports-to-parse-UB-device-and-related-display-of-vf-address.patch +Patch9003: sync-ipvlan_mode-enum-with-kernel-headers.patch BuildRequires: gcc bison elfutils-libelf-devel flex iptables-devel BuildRequires: libmnl-devel libselinux-devel pkgconfig libbpf-devel sudo make @@ -123,7 +147,50 @@ install -m 0644 lib/libnetlink.a %{buildroot}%{_libdir}/libnetlink.a %{_mandir}/* %changelog -* Thu May 30 2024 mufengyan - 1:5.15.0-15 +* Tue Apr 16 2024 liweigang - 1:5.15.0-19 +- Type: bugfix +- ID: NA +- SUG: NA +- DESC: lnstat: Fix deref of null in print_json() function + iproute2: prevent memory leak + libnetlink: validate nlmsg header length first + tc: remove tcindex classifier + ip: fix memory leak in 'ip maddr show' + ila: fix potential snprintf buffer overflow + bridge: fix potential snprintf overflow + mnl_utils: sanitize incoming netlink payload size in callbacks + +* Fri Jan 12 2024 liubo - 1:5.15.0-18 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:f_flower: Treat port 0 as valid + ip: error out if iplink does not consume all options + iplink_bridge: fix incorrect root id dump + ss: change aafilter port from int to long (inode support) + ss: Fix socket type check in packet_show_line() + ss: print unix socket "ports" as unsigned int (inode) + Add utility to convert an unsigned int to string + Add get_long utility and adapt get_integer accordingly + utils: fix get_integer() logic + +* Mon Nov 27 2023 liubo - 1:5.15.0-17 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:libnetlink: Fix memory leak in __rtnl_talk_iov() + tc: ct: Fix invalid pointer dereference + tc_util: Change datatype for maj to avoid overflow issue + tc_util: Fix no error return when large parent id used + xfrm: prepare state offload logic to set mode + +* Mon Nov 27 2023 liubo - 1:5.15.0-16 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: sync ipvlan_mode enum with kernel-headers + +* Sat Nov 25 2023 mufengyan - 1:5.15.0-15 - Type:feature - ID:NA - SUG:NA diff --git a/sync-ipvlan_mode-enum-with-kernel-headers.patch b/sync-ipvlan_mode-enum-with-kernel-headers.patch new file mode 100644 index 0000000..9958862 --- /dev/null +++ b/sync-ipvlan_mode-enum-with-kernel-headers.patch @@ -0,0 +1,26 @@ +From 22f6c8174dca9de68e7a011f580ba07e7d9c15b2 Mon Sep 17 00:00:00 2001 +From: liyunqing +Date: Fri, 16 Jun 2023 17:48:11 +0800 +Subject: [PATCH] sync ipvlan_mode enum with kernel-headers + +--- + include/uapi/linux/if_link.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h +index bddbdc7..1c6f6b1 100644 +--- a/include/uapi/linux/if_link.h ++++ b/include/uapi/linux/if_link.h +@@ -702,8 +702,8 @@ enum { + enum ipvlan_mode { + IPVLAN_MODE_L2 = 0, + IPVLAN_MODE_L3, +- IPVLAN_MODE_L2E, + IPVLAN_MODE_L3S, ++ IPVLAN_MODE_L2E, + IPVLAN_MODE_MAX + }; + +-- +2.33.0 +