From 552d5e248fbe365179cc0b50334ba6780f546321 Mon Sep 17 00:00:00 2001 From: gaoxingwang Date: Thu, 17 Aug 2023 11:29:10 +0800 Subject: [PATCH] backport patches to fix bugs (cherry picked from commit 2e9232daaeeab8917abc9a7830b7a9195d7a1da0) --- ...ereference-of-NULL-on-malloc-failure.patch | 317 +++++++++++++++ ...pnetns-fix-fd-leak-with-ip-netns-set.patch | 49 +++ ...mize-code-and-fix-some-mem-leak-risk.patch | 309 +++++++++++++++ ...te_lwtunnel-fix-array-boundary-check.patch | 34 ++ ...-fix-possible-use-of-NULL-when-mallo.patch | 178 +++++++++ ...t-protocol-mismatch-on-tunnel-change.patch | 67 ++++ ...warning-of-overwrite-of-const-string.patch | 162 ++++++++ ...fix-NULL-deref-on-allocation-failure.patch | 197 ++++++++++ backport-nstat-fix-potential-NULL-deref.patch | 364 ++++++++++++++++++ ...dma-utils-fix-some-analyzer-warnings.patch | 87 +++++ ...rt-rt_names-check-for-malloc-failure.patch | 30 ++ ...e-possible-truncated-kernel-response.patch | 74 ++++ ...t-dereference-NULL-on-calloc-failure.patch | 106 +++++ ...port-tc_util-fix-unitialized-warning.patch | 318 +++++++++++++++ iproute.spec | 36 +- 15 files changed, 2327 insertions(+), 1 deletion(-) create mode 100644 backport-ipmaddr-fix-dereference-of-NULL-on-malloc-failure.patch create mode 100644 backport-ipnetns-fix-fd-leak-with-ip-netns-set.patch create mode 100644 backport-iproute2-optimize-code-and-fix-some-mem-leak-risk.patch create mode 100644 backport-iproute_lwtunnel-fix-array-boundary-check.patch create mode 100644 backport-iproute_lwtunnel-fix-possible-use-of-NULL-when-mallo.patch create mode 100644 backport-iptunnel-detect-protocol-mismatch-on-tunnel-change.patch create mode 100644 backport-m_action-fix-warning-of-overwrite-of-const-string.patch create mode 100644 backport-netem-fix-NULL-deref-on-allocation-failure.patch create mode 100644 backport-nstat-fix-potential-NULL-deref.patch create mode 100644 backport-rdma-utils-fix-some-analyzer-warnings.patch create mode 100644 backport-rt_names-check-for-malloc-failure.patch create mode 100644 backport-tc-prio-handle-possible-truncated-kernel-response.patch create mode 100644 backport-tc_exec-don-t-dereference-NULL-on-calloc-failure.patch create mode 100644 backport-tc_util-fix-unitialized-warning.patch diff --git a/backport-ipmaddr-fix-dereference-of-NULL-on-malloc-failure.patch b/backport-ipmaddr-fix-dereference-of-NULL-on-malloc-failure.patch new file mode 100644 index 0000000..34e633c --- /dev/null +++ b/backport-ipmaddr-fix-dereference-of-NULL-on-malloc-failure.patch @@ -0,0 +1,317 @@ +From 8cda7a24a971170b833009f392579cfea87711bf Mon Sep 17 00:00:00 2001 +From: Stephen Hemminger +Date: Mon, 8 May 2023 19:02:20 -0700 +Subject: [PATCH] ipmaddr: fix dereference of NULL on malloc() failure +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Found by -fanalyzer. This is a bug since beginning of initial +versions of ip multicast support (pre git). + +ipmaddr.c: In function ‘read_dev_mcast’: +ipmaddr.c:105:25: warning: dereference of possibly-NULL ‘ma’ [CWE-690] [-Wanalyzer-possible-null-dereference] + 105 | memcpy(ma, &m, sizeof(m)); + | ^~~~~~~~~~~~~~~~~~~~~~~~~ + ‘do_multiaddr’: events 1-4 + | + | 354 | int do_multiaddr(int argc, char **argv) + | | ^~~~~~~~~~~~ + | | | + | | (1) entry to ‘do_multiaddr’ + | 355 | { + | 356 | if (argc < 1) + | | ~ + | | | + | | (2) following ‘true’ branch (when ‘argc <= 0’)... + | 357 | return multiaddr_list(0, NULL); + | | ~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (3) ...to here + | | (4) calling ‘multiaddr_list’ from ‘do_multiaddr’ + | + +--> ‘multiaddr_list’: events 5-10 + | + | 255 | static int multiaddr_list(int argc, char **argv) + | | ^~~~~~~~~~~~~~ + | | | + | | (5) entry to ‘multiaddr_list’ + |...... + | 262 | while (argc > 0) { + | | ~~~~~~~~ + | | | + | | (6) following ‘false’ branch (when ‘argc <= 0’)... + |...... + | 275 | if (!filter.family || filter.family == AF_PACKET) + | | ~ ~~~~~~~~~~~~~ + | | | | + | | | (7) ...to here + | | (8) following ‘true’ branch... + | 276 | read_dev_mcast(&list); + | | ~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (9) ...to here + | | (10) calling ‘read_dev_mcast’ from ‘multiaddr_list’ + | + +--> ‘read_dev_mcast’: events 11-12 + | + | 82 | static void read_dev_mcast(struct ma_info **result_p) + | | ^~~~~~~~~~~~~~ + | | | + | | (11) entry to ‘read_dev_mcast’ + |...... + | 87 | if (!fp) + | | ~ + | | | + | | (12) following ‘false’ branch (when ‘fp’ is non-NULL)... + | + ‘read_dev_mcast’: event 13 + | + |cc1: + | (13): ...to here + | + ‘read_dev_mcast’: events 14-17 + | + | 90 | while (fgets(buf, sizeof(buf), fp)) { + | | ^~~~~ + | | | + | | (14) following ‘true’ branch... + | 91 | char hexa[256]; + | 92 | struct ma_info m = { .addr.family = AF_PACKET }; + | | ~ + | | | + | | (15) ...to here + |...... + | 103 | struct ma_info *ma = malloc(sizeof(m)); + | | ~~~~~~~~~~~~~~~~~ + | | | + | | (16) this call could return NULL + | 104 | + | 105 | memcpy(ma, &m, sizeof(m)); + | | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (17) ‘ma’ could be NULL: unchecked value from (16) + | +ipmaddr.c: In function ‘read_igmp’: +ipmaddr.c:152:17: warning: dereference of possibly-NULL ‘ma’ [CWE-690] [-Wanalyzer-possible-null-dereference] + 152 | memcpy(ma, &m, sizeof(m)); + | ^~~~~~~~~~~~~~~~~~~~~~~~~ + ‘do_multiaddr’: events 1-4 + | + | 354 | int do_multiaddr(int argc, char **argv) + | | ^~~~~~~~~~~~ + | | | + | | (1) entry to ‘do_multiaddr’ + | 355 | { + | 356 | if (argc < 1) + | | ~ + | | | + | | (2) following ‘true’ branch (when ‘argc <= 0’)... + | 357 | return multiaddr_list(0, NULL); + | | ~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (3) ...to here + | | (4) calling ‘multiaddr_list’ from ‘do_multiaddr’ + | + +--> ‘multiaddr_list’: events 5-10 + | + | 255 | static int multiaddr_list(int argc, char **argv) + | | ^~~~~~~~~~~~~~ + | | | + | | (5) entry to ‘multiaddr_list’ + |...... + | 262 | while (argc > 0) { + | | ~~~~~~~~ + | | | + | | (6) following ‘false’ branch (when ‘argc <= 0’)... + |...... + | 275 | if (!filter.family || filter.family == AF_PACKET) + | | ~~~~~~~~~~~~~ + | | | + | | (7) ...to here + | 276 | read_dev_mcast(&list); + | 277 | if (!filter.family || filter.family == AF_INET) + | | ~ + | | | + | | (8) following ‘true’ branch... + | 278 | read_igmp(&list); + | | ~~~~~~~~~~~~~~~~ + | | | + | | (9) ...to here + | | (10) calling ‘read_igmp’ from ‘multiaddr_list’ + | + +--> ‘read_igmp’: events 11-14 + | + | 116 | static void read_igmp(struct ma_info **result_p) + | | ^~~~~~~~~ + | | | + | | (11) entry to ‘read_igmp’ + |...... + | 126 | if (!fp) + | | ~ + | | | + | | (12) following ‘false’ branch (when ‘fp’ is non-NULL)... + | 127 | return; + | 128 | if (!fgets(buf, sizeof(buf), fp)) { + | | ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | | + | | | (13) ...to here + | | (14) following ‘false’ branch... + | + ‘read_igmp’: event 15 + | + |cc1: + | (15): ...to here + | + ‘read_igmp’: events 16-19 + | + | 133 | while (fgets(buf, sizeof(buf), fp)) { + | | ^~~~~ + | | | + | | (16) following ‘true’ branch... + |...... + | 136 | if (buf[0] != '\t') { + | | ~~~~~~ + | | | + | | (17) ...to here + |...... + | 151 | ma = malloc(sizeof(m)); + | | ~~~~~~~~~~~~~~~~~ + | | | + | | (18) this call could return NULL + | 152 | memcpy(ma, &m, sizeof(m)); + | | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (19) ‘ma’ could be NULL: unchecked value from (18) + | +ipmaddr.c: In function ‘read_igmp6’: +ipmaddr.c:181:25: warning: dereference of possibly-NULL ‘ma’ [CWE-690] [-Wanalyzer-possible-null-dereference] + 181 | memcpy(ma, &m, sizeof(m)); + | ^~~~~~~~~~~~~~~~~~~~~~~~~ + ‘do_multiaddr’: events 1-4 + | + | 354 | int do_multiaddr(int argc, char **argv) + | | ^~~~~~~~~~~~ + | | | + | | (1) entry to ‘do_multiaddr’ + | 355 | { + | 356 | if (argc < 1) + | | ~ + | | | + | | (2) following ‘true’ branch (when ‘argc <= 0’)... + | 357 | return multiaddr_list(0, NULL); + | | ~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (3) ...to here + | | (4) calling ‘multiaddr_list’ from ‘do_multiaddr’ + | + +--> ‘multiaddr_list’: events 5-10 + | + | 255 | static int multiaddr_list(int argc, char **argv) + | | ^~~~~~~~~~~~~~ + | | | + | | (5) entry to ‘multiaddr_list’ + |...... + | 262 | while (argc > 0) { + | | ~~~~~~~~ + | | | + | | (6) following ‘false’ branch (when ‘argc <= 0’)... + |...... + | 275 | if (!filter.family || filter.family == AF_PACKET) + | | ~~~~~~~~~~~~~ + | | | + | | (7) ...to here + |...... + | 279 | if (!filter.family || filter.family == AF_INET6) + | | ~ + | | | + | | (8) following ‘true’ branch... + | 280 | read_igmp6(&list); + | | ~~~~~~~~~~~~~~~~~ + | | | + | | (9) ...to here + | | (10) calling ‘read_igmp6’ from ‘multiaddr_list’ + | + +--> ‘read_igmp6’: events 11-12 + | + | 159 | static void read_igmp6(struct ma_info **result_p) + | | ^~~~~~~~~~ + | | | + | | (11) entry to ‘read_igmp6’ + |...... + | 164 | if (!fp) + | | ~ + | | | + | | (12) following ‘false’ branch (when ‘fp’ is non-NULL)... + | + ‘read_igmp6’: event 13 + | + |cc1: + | (13): ...to here + | + ‘read_igmp6’: events 14-17 + | + | 167 | while (fgets(buf, sizeof(buf), fp)) { + | | ^~~~~ + | | | + | | (14) following ‘true’ branch... + | 168 | char hexa[256]; + | 169 | struct ma_info m = { .addr.family = AF_INET6 }; + | | ~ + | | | + | | (15) ...to here + |...... + | 179 | struct ma_info *ma = malloc(sizeof(m)); + | | ~~~~~~~~~~~~~~~~~ + | | | + | | (16) this call could return NULL + | 180 | + | 181 | memcpy(ma, &m, sizeof(m)); + | | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (17) ‘ma’ could be NULL: unchecked value from (16) + | + +Signed-off-by: Stephen Hemminger +--- + ip/ipmaddr.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/ip/ipmaddr.c b/ip/ipmaddr.c +index f8d6b992..a8ef20ec 100644 +--- a/ip/ipmaddr.c ++++ b/ip/ipmaddr.c +@@ -102,6 +102,8 @@ static void read_dev_mcast(struct ma_info **result_p) + if (len >= 0) { + struct ma_info *ma = malloc(sizeof(m)); + ++ if (ma == NULL) ++ break; + memcpy(ma, &m, sizeof(m)); + ma->addr.bytelen = len; + ma->addr.bitlen = len<<3; +@@ -149,6 +151,9 @@ static void read_igmp(struct ma_info **result_p) + sscanf(buf, "%08x%d", (__u32 *)&m.addr.data, &m.users); + + ma = malloc(sizeof(m)); ++ if (ma == NULL) ++ break; ++ + memcpy(ma, &m, sizeof(m)); + maddr_ins(result_p, ma); + } +@@ -178,8 +183,10 @@ static void read_igmp6(struct ma_info **result_p) + if (len >= 0) { + struct ma_info *ma = malloc(sizeof(m)); + +- memcpy(ma, &m, sizeof(m)); ++ if (ma == NULL) ++ break; + ++ memcpy(ma, &m, sizeof(m)); + ma->addr.bytelen = len; + ma->addr.bitlen = len<<3; + maddr_ins(result_p, ma); +-- +2.27.0 + diff --git a/backport-ipnetns-fix-fd-leak-with-ip-netns-set.patch b/backport-ipnetns-fix-fd-leak-with-ip-netns-set.patch new file mode 100644 index 0000000..d60d04f --- /dev/null +++ b/backport-ipnetns-fix-fd-leak-with-ip-netns-set.patch @@ -0,0 +1,49 @@ +From 465e87a89c134d28a7fae540d26b27e6a2e1d6c0 Mon Sep 17 00:00:00 2001 +From: Nicolas Dichtel +Date: Thu, 11 May 2023 16:42:24 +0200 +Subject: [PATCH] ipnetns: fix fd leak with 'ip netns set' + +There is no reason to open this netns file. set_netnsid_from_name() uses +netns_get_fd() for this purpose and uses the returned fd. + +Reported-by: Stephen Hemminger +Fixes: d182ee1307c7 ("ipnetns: allow to get and set netns ids") +Signed-off-by: Nicolas Dichtel +Signed-off-by: Stephen Hemminger +--- + ip/ipnetns.c | 11 +---------- + 1 file changed, 1 insertion(+), 10 deletions(-) + +diff --git a/ip/ipnetns.c b/ip/ipnetns.c +index 12035349..9d996832 100644 +--- a/ip/ipnetns.c ++++ b/ip/ipnetns.c +@@ -967,9 +967,8 @@ int set_netnsid_from_name(const char *name, int nsid) + + static int netns_set(int argc, char **argv) + { +- char netns_path[PATH_MAX]; + const char *name; +- int netns, nsid; ++ int nsid; + + if (argc < 1) { + fprintf(stderr, "No netns name specified\n"); +@@ -988,14 +987,6 @@ static int netns_set(int argc, char **argv) + else if (nsid < 0) + invarg("\"netnsid\" value should be >= 0", argv[1]); + +- snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name); +- netns = open(netns_path, O_RDONLY | O_CLOEXEC); +- if (netns < 0) { +- fprintf(stderr, "Cannot open network namespace \"%s\": %s\n", +- name, strerror(errno)); +- return -1; +- } +- + return set_netnsid_from_name(name, nsid); + } + +-- +2.27.0 + diff --git a/backport-iproute2-optimize-code-and-fix-some-mem-leak-risk.patch b/backport-iproute2-optimize-code-and-fix-some-mem-leak-risk.patch new file mode 100644 index 0000000..dc61171 --- /dev/null +++ b/backport-iproute2-optimize-code-and-fix-some-mem-leak-risk.patch @@ -0,0 +1,309 @@ +From 7e8cdfa2eac57c8c1c469681d5ee016fc432ee4d Mon Sep 17 00:00:00 2001 +From: zhaoshuang +Date: Thu, 11 May 2023 08:37:26 +0800 +Subject: [PATCH] iproute2: optimize code and fix some mem-leak risk + +Conflict:contaxt adapt in devlink/devlink.c ip/ipnexthop.c,and remove modify in tc/tc_class.c because it +does not have leak +Reference:https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit?id=7e8cdfa2eac57c8c1c469681d5ee016fc432ee4d + +Signed-off-by: zhaoshuang +Reviewed-by: Pawel Chmielewski +Signed-off-by: Stephen Hemminger +--- + bridge/mdb.c | 4 ++++ + devlink/devlink.c | 21 +++++++++------------ + ip/ipaddrlabel.c | 1 + + ip/ipfou.c | 1 + + ip/ipila.c | 1 + + ip/ipnetconf.c | 1 + + ip/ipnexthop.c | 4 ++++ + ip/iproute.c | 6 ++++++ + ip/iprule.c | 1 + + ip/iptuntap.c | 1 + + ip/tunnel.c | 2 ++ + tc/tc_filter.c | 1 + + tc/tc_qdisc.c | 1 + + 13 files changed, 33 insertions(+), 12 deletions(-) + +diff --git a/bridge/mdb.c b/bridge/mdb.c +index b427d87..c5f23d0 100644 +--- a/bridge/mdb.c ++++ b/bridge/mdb.c +@@ -423,12 +423,14 @@ static int mdb_show(int argc, char **argv) + /* get mdb entries */ + if (rtnl_mdbdump_req(&rth, PF_BRIDGE) < 0) { + perror("Cannot send dump request"); ++ delete_json_obj(); + return -1; + } + + open_json_array(PRINT_JSON, "mdb"); + if (rtnl_dump_filter(&rth, print_mdbs, stdout) < 0) { + fprintf(stderr, "Dump terminated\n"); ++ delete_json_obj(); + return -1; + } + close_json_array(PRINT_JSON, NULL); +@@ -436,12 +438,14 @@ static int mdb_show(int argc, char **argv) + /* get router ports */ + if (rtnl_mdbdump_req(&rth, PF_BRIDGE) < 0) { + perror("Cannot send dump request"); ++ delete_json_obj(); + return -1; + } + + open_json_object("router"); + if (rtnl_dump_filter(&rth, print_rtrs, stdout) < 0) { + fprintf(stderr, "Dump terminated\n"); ++ delete_json_obj(); + return -1; + } + close_json_object(); +diff --git a/devlink/devlink.c b/devlink/devlink.c +index 765e90d..9275ee5 100644 +--- a/devlink/devlink.c ++++ b/devlink/devlink.c +@@ -209,6 +209,14 @@ struct ifname_map { + char *ifname; + }; + ++static void ifname_map_free(struct ifname_map *ifname_map) ++{ ++ free(ifname_map->ifname); ++ free(ifname_map->dev_name); ++ free(ifname_map->bus_name); ++ free(ifname_map); ++} ++ + static struct ifname_map *ifname_map_alloc(const char *bus_name, + const char *dev_name, + uint32_t port_index, +@@ -225,23 +233,12 @@ static struct ifname_map *ifname_map_alloc(const char *bus_name, + ifname_map->ifname = strdup(ifname); + if (!ifname_map->bus_name || !ifname_map->dev_name || + !ifname_map->ifname) { +- free(ifname_map->ifname); +- free(ifname_map->dev_name); +- free(ifname_map->bus_name); +- free(ifname_map); ++ ifname_map_free(ifname_map); + return NULL; + } + return ifname_map; + } + +-static void ifname_map_free(struct ifname_map *ifname_map) +-{ +- free(ifname_map->ifname); +- free(ifname_map->dev_name); +- free(ifname_map->bus_name); +- free(ifname_map); +-} +- + #define DL_OPT_HANDLE BIT(0) + #define DL_OPT_HANDLEP BIT(1) + #define DL_OPT_PORT_TYPE BIT(2) +diff --git a/ip/ipaddrlabel.c b/ip/ipaddrlabel.c +index beb08da..9e468b0 100644 +--- a/ip/ipaddrlabel.c ++++ b/ip/ipaddrlabel.c +@@ -127,6 +127,7 @@ static int ipaddrlabel_list(int argc, char **argv) + new_json_obj(json); + if (rtnl_dump_filter(&rth, print_addrlabel, stdout) < 0) { + fprintf(stderr, "Dump terminated\n"); ++ delete_json_obj(); + return 1; + } + delete_json_obj(); +diff --git a/ip/ipfou.c b/ip/ipfou.c +index 9c69777..5db137d 100644 +--- a/ip/ipfou.c ++++ b/ip/ipfou.c +@@ -322,6 +322,7 @@ static int do_show(int argc, char **argv) + new_json_obj(json); + if (rtnl_dump_filter(&genl_rth, print_fou_mapping, stdout) < 0) { + fprintf(stderr, "Dump terminated\n"); ++ delete_json_obj(); + return 1; + } + delete_json_obj(); +diff --git a/ip/ipila.c b/ip/ipila.c +index 475c35b..cbc3dd3 100644 +--- a/ip/ipila.c ++++ b/ip/ipila.c +@@ -154,6 +154,7 @@ static int do_list(int argc, char **argv) + new_json_obj(json); + if (rtnl_dump_filter(&genl_rth, print_ila_mapping, stdout) < 0) { + fprintf(stderr, "Dump terminated\n"); ++ delete_json_obj(); + return 1; + } + delete_json_obj(); +diff --git a/ip/ipnetconf.c b/ip/ipnetconf.c +index bb0ebe1..f5ebb1a 100644 +--- a/ip/ipnetconf.c ++++ b/ip/ipnetconf.c +@@ -214,6 +214,7 @@ dump: + */ + if (errno == EOPNOTSUPP && + filter.family == AF_UNSPEC) { ++ delete_json_obj(); + filter.family = AF_INET; + goto dump; + } +diff --git a/ip/ipnexthop.c b/ip/ipnexthop.c +index 9478aa5..36dafa1 100644 +--- a/ip/ipnexthop.c ++++ b/ip/ipnexthop.c +@@ -732,6 +732,7 @@ static int ipnh_get_id(__u32 id) + new_json_obj(json); + + if (print_nexthop(answer, (void *)stdout) < 0) { ++ delete_json_obj(); + free(answer); + return -1; + } +@@ -817,6 +818,7 @@ static int ipnh_list_flush(int argc, char **argv, int action) + new_json_obj(json); + + if (rtnl_dump_filter(&rth, print_nexthop, stdout) < 0) { ++ delete_json_obj(); + fprintf(stderr, "Dump terminated\n"); + return -2; + } +@@ -892,6 +894,7 @@ static int ipnh_bucket_list(int argc, char **argv) + new_json_obj(json); + + if (rtnl_dump_filter(&rth, print_nexthop_bucket, stdout) < 0) { ++ delete_json_obj(); + fprintf(stderr, "Dump terminated\n"); + return -2; + } +@@ -932,6 +935,7 @@ static int ipnh_bucket_get_id(__u32 id, __u16 bucket_index) + new_json_obj(json); + + if (print_nexthop_bucket(answer, (void *)stdout) < 0) { ++ delete_json_obj(); + free(answer); + return -1; + } +diff --git a/ip/iproute.c b/ip/iproute.c +index 9922cb0..6e359fa 100644 +--- a/ip/iproute.c ++++ b/ip/iproute.c +@@ -1962,6 +1962,7 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action) + if (rtnl_dump_filter_errhndlr(&rth, filter_fn, stdout, + save_route_errhndlr, NULL) < 0) { + fprintf(stderr, "Dump terminated\n"); ++ delete_json_obj(); + return -2; + } + +@@ -2157,18 +2158,21 @@ static int iproute_get(int argc, char **argv) + + if (print_route(answer, (void *)stdout) < 0) { + fprintf(stderr, "An error :-)\n"); ++ delete_json_obj(); + free(answer); + return -1; + } + + if (answer->nlmsg_type != RTM_NEWROUTE) { + fprintf(stderr, "Not a route?\n"); ++ delete_json_obj(); + free(answer); + return -1; + } + len -= NLMSG_LENGTH(sizeof(*r)); + if (len < 0) { + fprintf(stderr, "Wrong len %d\n", len); ++ delete_json_obj(); + free(answer); + return -1; + } +@@ -2180,6 +2184,7 @@ static int iproute_get(int argc, char **argv) + r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]); + } else if (!tb[RTA_SRC]) { + fprintf(stderr, "Failed to connect the route\n"); ++ delete_json_obj(); + free(answer); + return -1; + } +@@ -2202,6 +2207,7 @@ static int iproute_get(int argc, char **argv) + + if (print_route(answer, (void *)stdout) < 0) { + fprintf(stderr, "An error :-)\n"); ++ delete_json_obj(); + free(answer); + return -1; + } +diff --git a/ip/iprule.c b/ip/iprule.c +index 4166073..7307908 100644 +--- a/ip/iprule.c ++++ b/ip/iprule.c +@@ -718,6 +718,7 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action) + new_json_obj(json); + if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) { + fprintf(stderr, "Dump terminated\n"); ++ delete_json_obj(); + return 1; + } + delete_json_obj(); +diff --git a/ip/iptuntap.c b/ip/iptuntap.c +index 385d2bd..ff88844 100644 +--- a/ip/iptuntap.c ++++ b/ip/iptuntap.c +@@ -444,6 +444,7 @@ static int do_show(int argc, char **argv) + + if (rtnl_dump_filter(&rth, print_tuntap, NULL) < 0) { + fprintf(stderr, "Dump terminated\n"); ++ delete_json_obj(); + return -1; + } + +diff --git a/ip/tunnel.c b/ip/tunnel.c +index 88585cf..51a0016 100644 +--- a/ip/tunnel.c ++++ b/ip/tunnel.c +@@ -439,11 +439,13 @@ int do_tunnels_list(struct tnl_print_nlmsg_info *info) + new_json_obj(json); + if (rtnl_linkdump_req(&rth, preferred_family) < 0) { + perror("Cannot send dump request\n"); ++ delete_json_obj(); + return -1; + } + + if (rtnl_dump_filter(&rth, print_nlmsg_tunnel, info) < 0) { + fprintf(stderr, "Dump terminated\n"); ++ delete_json_obj(); + return -1; + } + delete_json_obj(); +diff --git a/tc/tc_filter.c b/tc/tc_filter.c +index 71be2e8..5a2a6ba 100644 +--- a/tc/tc_filter.c ++++ b/tc/tc_filter.c +@@ -738,6 +738,7 @@ static int tc_filter_list(int cmd, int argc, char **argv) + new_json_obj(json); + if (rtnl_dump_filter(&rth, print_filter, stdout) < 0) { + fprintf(stderr, "Dump terminated\n"); ++ delete_json_obj(); + return 1; + } + delete_json_obj(); +diff --git a/tc/tc_qdisc.c b/tc/tc_qdisc.c +index b79029d..77f4d97 100644 +--- a/tc/tc_qdisc.c ++++ b/tc/tc_qdisc.c +@@ -435,6 +435,7 @@ static int tc_qdisc_list(int argc, char **argv) + new_json_obj(json); + if (rtnl_dump_filter(&rth, print_qdisc, stdout) < 0) { + fprintf(stderr, "Dump terminated\n"); ++ delete_json_obj(); + return 1; + } + delete_json_obj(); +-- +2.27.0 + diff --git a/backport-iproute_lwtunnel-fix-array-boundary-check.patch b/backport-iproute_lwtunnel-fix-array-boundary-check.patch new file mode 100644 index 0000000..9c207de --- /dev/null +++ b/backport-iproute_lwtunnel-fix-array-boundary-check.patch @@ -0,0 +1,34 @@ +From 1cf50a1f2723764eb53fad7c5ff8754835806df0 Mon Sep 17 00:00:00 2001 +From: Andrea Claudi +Date: Mon, 29 May 2023 23:42:16 +0200 +Subject: [PATCH] iproute_lwtunnel: fix array boundary check + +seg6_mode_types is made up of 5 elements, so ARRAY_SIZE(seg6_mode_types) +evaluates to 5. Thus, when mode = 5, this function returns +seg6_mode_types[5], resulting in an out-of-bound access. + +Fix this bailing out when mode is equal to or greater than 5. + +Fixes: cf87da417bb4 ("iproute: add support for seg6 l2encap mode") +Signed-off-by: Andrea Claudi +Signed-off-by: Stephen Hemminger +--- + ip/iproute_lwtunnel.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c +index 96de3b20..94985972 100644 +--- a/ip/iproute_lwtunnel.c ++++ b/ip/iproute_lwtunnel.c +@@ -140,7 +140,7 @@ static const char *seg6_mode_types[] = { + + static const char *format_seg6mode_type(int mode) + { +- if (mode < 0 || mode > ARRAY_SIZE(seg6_mode_types)) ++ if (mode < 0 || mode >= ARRAY_SIZE(seg6_mode_types)) + return ""; + + return seg6_mode_types[mode]; +-- +2.27.0 + diff --git a/backport-iproute_lwtunnel-fix-possible-use-of-NULL-when-mallo.patch b/backport-iproute_lwtunnel-fix-possible-use-of-NULL-when-mallo.patch new file mode 100644 index 0000000..31c42f7 --- /dev/null +++ b/backport-iproute_lwtunnel-fix-possible-use-of-NULL-when-mallo.patch @@ -0,0 +1,178 @@ +From fa44c2d6f1dab40ad615bcb16fdbdb189d617ed6 Mon Sep 17 00:00:00 2001 +From: Stephen Hemminger +Date: Mon, 8 May 2023 19:05:38 -0700 +Subject: [PATCH] iproute_lwtunnel: fix possible use of NULL when malloc() + fails +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +iproute_lwtunnel.c: In function ‘parse_srh’: +iproute_lwtunnel.c:903:9: warning: use of possibly-NULL ‘srh’ where non-null expected [CWE-690] [-Wanalyzer-possible-null-argument] + 903 | memset(srh, 0, srhlen); + | ^~~~~~~~~~~~~~~~~~~~~~ + ‘parse_srh’: events 1-2 + | + | 902 | srh = malloc(srhlen); + | | ^~~~~~~~~~~~~~ + | | | + | | (1) this call could return NULL + | 903 | memset(srh, 0, srhlen); + | | ~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (2) argument 1 (‘srh’) from (1) could be NULL where non-null expected + | +In file included from iproute_lwtunnel.c:13: +/usr/include/string.h:61:14: note: argument 1 of ‘memset’ must be non-null + 61 | extern void *memset (void *__s, int __c, size_t __n) __THROW __nonnull ((1)); + | ^~~~~~ +iproute_lwtunnel.c: In function ‘parse_encap_seg6’: +iproute_lwtunnel.c:980:9: warning: use of possibly-NULL ‘tuninfo’ where non-null expected [CWE-690] [-Wanalyzer-possible-null-argument] + 980 | memset(tuninfo, 0, sizeof(*tuninfo) + srhlen); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ‘parse_encap_seg6’: events 1-2 + | + | 934 | static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp, + | | ^~~~~~~~~~~~~~~~ + | | | + | | (1) entry to ‘parse_encap_seg6’ + |...... + | 976 | srh = parse_srh(segbuf, hmac, encap); + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (2) calling ‘parse_srh’ from ‘parse_encap_seg6’ + | + +--> ‘parse_srh’: events 3-5 + | + | 882 | static struct ipv6_sr_hdr *parse_srh(char *segbuf, int hmac, bool encap) + | | ^~~~~~~~~ + | | | + | | (3) entry to ‘parse_srh’ + |...... + | 922 | if (hmac) { + | | ~ + | | | + | | (4) following ‘false’ branch (when ‘hmac == 0’)... + |...... + | 931 | return srh; + | | ~~~ + | | | + | | (5) ...to here + | + <------+ + | + ‘parse_encap_seg6’: events 6-8 + | + | 976 | srh = parse_srh(segbuf, hmac, encap); + | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (6) returning to ‘parse_encap_seg6’ from ‘parse_srh’ + |...... + | 979 | tuninfo = malloc(sizeof(*tuninfo) + srhlen); + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (7) this call could return NULL + | 980 | memset(tuninfo, 0, sizeof(*tuninfo) + srhlen); + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (8) argument 1 (‘tuninfo’) from (7) could be NULL where non-null expected + | +/usr/include/string.h:61:14: note: argument 1 of ‘memset’ must be non-null + 61 | extern void *memset (void *__s, int __c, size_t __n) __THROW __nonnull ((1)); + | ^~~~~~ +iproute_lwtunnel.c: In function ‘parse_rpl_srh’: +iproute_lwtunnel.c:1018:21: warning: dereference of possibly-NULL ‘srh’ [CWE-690] [-Wanalyzer-possible-null-dereference] + 1018 | srh->hdrlen = (srhlen >> 3) - 1; + | ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~ + ‘parse_rpl_srh’: events 1-2 + | + | 1016 | srh = calloc(1, srhlen); + | | ^~~~~~~~~~~~~~~~~ + | | | + | | (1) this call could return NULL + | 1017 | + | 1018 | srh->hdrlen = (srhlen >> 3) - 1; + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (2) ‘srh’ could be NULL: unchecked value from (1) + | + +Fixes: 00e76d4da37f ("iproute: add helper functions for SRH processing") +Signed-off-by: Stephen Hemminger +--- + ip/iproute_lwtunnel.c | 18 +++++++++++++----- + 1 file changed, 13 insertions(+), 5 deletions(-) + +diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c +index 308178ef..96de3b20 100644 +--- a/ip/iproute_lwtunnel.c ++++ b/ip/iproute_lwtunnel.c +@@ -900,6 +900,9 @@ static struct ipv6_sr_hdr *parse_srh(char *segbuf, int hmac, bool encap) + srhlen += 40; + + srh = malloc(srhlen); ++ if (srh == NULL) ++ return NULL; ++ + memset(srh, 0, srhlen); + + srh->hdrlen = (srhlen >> 3) - 1; +@@ -935,14 +938,14 @@ static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp, + char ***argvp) + { + int mode_ok = 0, segs_ok = 0, hmac_ok = 0; +- struct seg6_iptunnel_encap *tuninfo; ++ struct seg6_iptunnel_encap *tuninfo = NULL; + struct ipv6_sr_hdr *srh; + char **argv = *argvp; + char segbuf[1024] = ""; + int argc = *argcp; + int encap = -1; + __u32 hmac = 0; +- int ret = 0; ++ int ret = -1; + int srhlen; + + while (argc > 0) { +@@ -974,9 +977,13 @@ static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp, + } + + srh = parse_srh(segbuf, hmac, encap); ++ if (srh == NULL) ++ goto out; + srhlen = (srh->hdrlen + 1) << 3; + + tuninfo = malloc(sizeof(*tuninfo) + srhlen); ++ if (tuninfo == NULL) ++ goto out; + memset(tuninfo, 0, sizeof(*tuninfo) + srhlen); + + tuninfo->mode = encap; +@@ -984,13 +991,12 @@ static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp, + memcpy(tuninfo->srh, srh, srhlen); + + if (rta_addattr_l(rta, len, SEG6_IPTUNNEL_SRH, tuninfo, +- sizeof(*tuninfo) + srhlen)) { +- ret = -1; ++ sizeof(*tuninfo) + srhlen)) + goto out; +- } + + *argcp = argc + 1; + *argvp = argv - 1; ++ ret = 0; + + out: + free(tuninfo); +@@ -1014,6 +1020,8 @@ static struct ipv6_rpl_sr_hdr *parse_rpl_srh(char *segbuf) + srhlen = 8 + 16 * nsegs; + + srh = calloc(1, srhlen); ++ if (srh == NULL) ++ return NULL; + + srh->hdrlen = (srhlen >> 3) - 1; + srh->type = 3; +-- +2.27.0 + diff --git a/backport-iptunnel-detect-protocol-mismatch-on-tunnel-change.patch b/backport-iptunnel-detect-protocol-mismatch-on-tunnel-change.patch new file mode 100644 index 0000000..841b4a5 --- /dev/null +++ b/backport-iptunnel-detect-protocol-mismatch-on-tunnel-change.patch @@ -0,0 +1,67 @@ +From 8cc2eac60d5f1f5ec2c40d02c0003731c8b610dc Mon Sep 17 00:00:00 2001 +From: Stephen Hemminger +Date: Mon, 10 Apr 2023 16:22:51 -0700 +Subject: [PATCH] iptunnel: detect protocol mismatch on tunnel change + +If attempt is made to change an IPv6 tunnel by using IPv4 +parameters, a stack overflow would happen and garbage request +would be passed to kernel. + +Example: +ip tunnel add gre1 mode ip6gre local 2001:db8::1 remote 2001:db8::2 ttl 255 +ip tunnel change gre1 mode gre local 192.168.0.0 remote 192.168.0.1 ttl 255 + +The second command should fail because it attempting set IPv4 addresses +on a GRE tunnel that is IPv6. + +Do best effort detection of this mismatch by giving a bigger buffer to get +tunnel request, and checking that the IP header is IPv4. It is still possible +but unlikely that byte would match in IPv6 tunnel paramater, but good enough +to catch the obvious cases. + +Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1032642 +Tested-by: Luca Boccassi +Reported-by: Robin +Signed-off-by: Stephen Hemminger +--- + ip/iptunnel.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/ip/iptunnel.c b/ip/iptunnel.c +index 02c3670b..b6da1459 100644 +--- a/ip/iptunnel.c ++++ b/ip/iptunnel.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + + #include "rt_names.h" + #include "utils.h" +@@ -172,11 +173,20 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p) + if (get_ifname(p->name, *argv)) + invarg("\"name\" not a valid ifname", *argv); + if (cmd == SIOCCHGTUNNEL && count == 0) { +- struct ip_tunnel_parm old_p = {}; ++ union { ++ struct ip_tunnel_parm ip_tnl; ++ struct ip6_tnl_parm2 ip6_tnl; ++ } old_p = {}; + + if (tnl_get_ioctl(*argv, &old_p)) + return -1; +- *p = old_p; ++ ++ if (old_p.ip_tnl.iph.version != 4 || ++ old_p.ip_tnl.iph.ihl != 5) ++ invarg("\"name\" is not an ip tunnel", ++ *argv); ++ ++ *p = old_p.ip_tnl; + } + } + count++; +-- +2.27.0 + diff --git a/backport-m_action-fix-warning-of-overwrite-of-const-string.patch b/backport-m_action-fix-warning-of-overwrite-of-const-string.patch new file mode 100644 index 0000000..dae5218 --- /dev/null +++ b/backport-m_action-fix-warning-of-overwrite-of-const-string.patch @@ -0,0 +1,162 @@ +From b134c2c344582f12d3e350168334e50b91a99c7d Mon Sep 17 00:00:00 2001 +From: Stephen Hemminger +Date: Mon, 8 May 2023 19:25:33 -0700 +Subject: [PATCH] m_action: fix warning of overwrite of const string +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The function get_action_kind() searches first for the given +action, then rescans on failure for "gact". In the process, +it would overwrite the argument. Avoid the warning +by using a const argument and not copying. + +The problem dates back to pre-git history. + +m_action.c: In function ‘get_action_kind’: +m_action.c:126:17: warning: write to string literal [-Wanalyzer-write-to-string-literal] + 126 | strcpy(str, "gact"); + | ^~~~~~~~~~~~~~~~~~~ + ‘do_action’: events 1-6 + | + | 853 | int do_action(int argc, char **argv) + | | ^~~~~~~~~ + | | | + | | (1) entry to ‘do_action’ + |...... + | 858 | while (argc > 0) { + | | ~~~~~~~~ + | | | + | | (2) following ‘true’ branch... + | 859 | + | 860 | if (matches(*argv, "add") == 0) { + | | ~~~~~~~~~~~~~~~~~~~~~~ + | | || + | | |(3) ...to here + | | (4) following ‘false’ branch... + | 861 | ret = tc_action_modify(RTM_NEWACTION, + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (5) ...to here + | | (6) calling ‘tc_action_modify’ from ‘do_action’ + | 862 | NLM_F_EXCL | NLM_F_CREATE, + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + | 863 | &argc, &argv); + | | ~~~~~~~~~~~~~ + | + +--> ‘tc_action_modify’: events 7-8 + | + | 715 | static int tc_action_modify(int cmd, unsigned int flags, + | | ^~~~~~~~~~~~~~~~ + | | | + | | (7) entry to ‘tc_action_modify’ + |...... + | 735 | if (parse_action(&argc, &argv, TCA_ACT_TAB, &req.n)) { + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (8) calling ‘parse_action’ from ‘tc_action_modify’ + | + +--> ‘parse_action’: events 9-18 + | + | 203 | int parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) + | | ^~~~~~~~~~~~ + | | | + | | (9) entry to ‘parse_action’ + |...... + | 217 | if (argc <= 0) + | | ~ + | | | + | | (10) following ‘false’ branch... + |...... + | 220 | tail2 = addattr_nest(n, MAX_MSG, tca_id); + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (11) ...to here + | 221 | + | 222 | while (argc > 0) { + | | ~~~~~~~~ + | | | + | | (12) following ‘true’ branch... + | 223 | + | 224 | memset(k, 0, sizeof(k)); + | | ~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (13) ...to here + | 225 | + | 226 | if (strcmp(*argv, "action") == 0) { + | | ~ + | | | + | | (14) following ‘true’ branch (when the strings are equal)... + | 227 | argc--; + | | ~~~~~~ + | | | + | | (15) ...to here + |...... + | 231 | if (!gact_ld) + | | ~ + | | | + | | (16) following ‘true’ branch... + | 232 | get_action_kind("gact"); + | | ~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (17) ...to here + | | (18) calling ‘get_action_kind’ from ‘parse_action’ + | + +--> ‘get_action_kind’: events 19-24 + | + | 86 | static struct action_util *get_action_kind(char *str) + | | ^~~~~~~~~~~~~~~ + | | | + | | (19) entry to ‘get_action_kind’ + |...... + | 114 | if (a == NULL) + | | ~ + | | | + | | (20) following ‘true’ branch (when ‘a’ is NULL)... + | 115 | goto noexist; + | | ~~~~ + | | | + | | (21) ...to here + |...... + | 124 | if (!looked4gact) { + | | ~ + | | | + | | (22) following ‘true’ branch (when ‘looked4gact == 0’)... + | 125 | looked4gact = 1; + | 126 | strcpy(str, "gact"); + | | ~~~~~~~~~~~~~~~~~~~ + | | | + | | (23) ...to here + | | (24) write to string literal here + | + +Signed-off-by: Stephen Hemminger +--- + tc/m_action.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/tc/m_action.c b/tc/m_action.c +index a446cabd..16474c56 100644 +--- a/tc/m_action.c ++++ b/tc/m_action.c +@@ -83,7 +83,7 @@ static int parse_noaopt(struct action_util *au, int *argc_p, + return -1; + } + +-static struct action_util *get_action_kind(char *str) ++static struct action_util *get_action_kind(const char *str) + { + static void *aBODY; + void *dlh; +@@ -123,7 +123,7 @@ noexist: + #ifdef CONFIG_GACT + if (!looked4gact) { + looked4gact = 1; +- strcpy(str, "gact"); ++ str = "gact"; + goto restart_s; + } + #endif +-- +2.27.0 + diff --git a/backport-netem-fix-NULL-deref-on-allocation-failure.patch b/backport-netem-fix-NULL-deref-on-allocation-failure.patch new file mode 100644 index 0000000..d4d7e0a --- /dev/null +++ b/backport-netem-fix-NULL-deref-on-allocation-failure.patch @@ -0,0 +1,197 @@ +From 6c266d7c22a8f4f631d278ba6102f1b1d2bca148 Mon Sep 17 00:00:00 2001 +From: Stephen Hemminger +Date: Mon, 8 May 2023 19:36:14 -0700 +Subject: [PATCH] netem: fix NULL deref on allocation failure +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +q_netem.c: In function ‘get_distribution’: +q_netem.c:159:35: warning: dereference of possibly-NULL ‘data’ [CWE-690] [-Wanalyzer-possible-null-dereference] + 159 | data[n++] = x; + | ~~~~~~~~~~^~~ + ‘netem_parse_opt’: events 1-24 + | + | 192 | static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, + | | ^~~~~~~~~~~~~~~ + | | | + | | (1) entry to ‘netem_parse_opt’ + |...... + | 212 | for ( ; argc > 0; --argc, ++argv) { + | | ~~~~~~~~ + | | | + | | (2) following ‘true’ branch (when ‘argc > 0’)... + | 213 | if (matches(*argv, "limit") == 0) { + | | ~~~~~~~~~~~~~~~~~~~~~~~~ + | | || + | | |(3) ...to here + | | (4) following ‘true’ branch... + |...... + | 219 | } else if (matches(*argv, "latency") == 0 || + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | || | + | | |(5) ...to here (8) following ‘true’ branch... + | | (6) following ‘true’ branch... + | 220 | matches(*argv, "delay") == 0) { + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (7) ...to here + |...... + | 243 | } else if (matches(*argv, "loss") == 0 || + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | || | + | | |(9) ...to here (12) following ‘true’ branch... + | | (10) following ‘true’ branch... + | 244 | matches(*argv, "drop") == 0) { + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (11) ...to here + |...... + | 366 | } else if (matches(*argv, "ecn") == 0) { + | | ~~~~~~~~~~~~~~~~~~~~~~ + | | || + | | |(13) ...to here + | | (14) following ‘true’ branch... + | 367 | present[TCA_NETEM_ECN] = 1; + | 368 | } else if (matches(*argv, "reorder") == 0) { + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | || + | | |(15) ...to here + | | (16) following ‘true’ branch... + |...... + | 383 | } else if (matches(*argv, "corrupt") == 0) { + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | || + | | |(17) ...to here + | | (18) following ‘true’ branch... + |...... + | 398 | } else if (matches(*argv, "gap") == 0) { + | | ~~~~~~~~~~~~~~~~~~~~~~ + | | || + | | |(19) ...to here + | | (20) following ‘true’ branch... + |...... + | 404 | } else if (matches(*argv, "duplicate") == 0) { + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | || + | | |(21) ...to here + | | (22) following ‘true’ branch... + |...... + | 417 | } else if (matches(*argv, "distribution") == 0) { + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | || + | | |(23) ...to here + | | (24) following ‘false’ branch... + | + ‘netem_parse_opt’: event 25 + | + |../include/utils.h:50:29: + | 50 | #define NEXT_ARG() do { argv++; if (--argc <= 0) incomplete_command(); } while(0) + | | ~~~~^~ + | | | + | | (25) ...to here +q_netem.c:418:25: note: in expansion of macro ‘NEXT_ARG’ + | 418 | NEXT_ARG(); + | | ^~~~~~~~ + | + ‘netem_parse_opt’: event 26 + | + |../include/utils.h:50:36: + | 50 | #define NEXT_ARG() do { argv++; if (--argc <= 0) incomplete_command(); } while(0) + | | ^ + | | | + | | (26) following ‘false’ branch (when ‘argc != 0’)... +q_netem.c:418:25: note: in expansion of macro ‘NEXT_ARG’ + | 418 | NEXT_ARG(); + | | ^~~~~~~~ + | + ‘netem_parse_opt’: events 27-29 + | + | 419 | dist_data = calloc(sizeof(dist_data[0]), MAX_DIST); + | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (27) ...to here + | | (28) this call could return NULL + | 420 | dist_size = get_distribution(*argv, dist_data, MAX_DIST); + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (29) calling ‘get_distribution’ from ‘netem_parse_opt’ + | + +--> ‘get_distribution’: events 30-31 + | + | 124 | static int get_distribution(const char *type, __s16 *data, int maxdata) + | | ^~~~~~~~~~~~~~~~ + | | | + | | (30) entry to ‘get_distribution’ + |...... + | 135 | if (f == NULL) { + | | ~ + | | | + | | (31) following ‘false’ branch (when ‘f’ is non-NULL)... + | + ‘get_distribution’: event 32 + | + |cc1: + | (32): ...to here + | + ‘get_distribution’: events 33-35 + | + | 142 | while (getline(&line, &len, f) != -1) { + | | ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~ + | | | + | | (33) following ‘true’ branch... + |...... + | 145 | if (*line == '\n' || *line == '#') + | | ~~~~~~ + | | || + | | |(34) ...to here + | | (35) following ‘false’ branch... + | + ‘get_distribution’: event 36 + | + |cc1: + | (36): ...to here + | + ‘get_distribution’: events 37-41 + | + | 150 | if (endp == p) + | | ^ + | | | + | | (37) following ‘false’ branch... + |...... + | 153 | if (n >= maxdata) { + | | ~ + | | | + | | (38) ...to here + | | (39) following ‘false’ branch (when ‘n < maxdata’)... + |...... + | 159 | data[n++] = x; + | | ~~~~~~~~~~~~~ + | | | | + | | | (41) ‘data + (long unsigned int)n * 2’ could be NULL: unchecked value from (28) + | | (40) ...to here + | + +Fixes: c1b81cb5fe92 ("netem potential dist table overflow") +Signed-off-by: Stephen Hemminger +--- + tc/q_netem.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/tc/q_netem.c b/tc/q_netem.c +index 26402e9a..d1d79b0b 100644 +--- a/tc/q_netem.c ++++ b/tc/q_netem.c +@@ -417,6 +417,9 @@ random_loss_model: + } else if (matches(*argv, "distribution") == 0) { + NEXT_ARG(); + dist_data = calloc(sizeof(dist_data[0]), MAX_DIST); ++ if (dist_data == NULL) ++ return -1; ++ + dist_size = get_distribution(*argv, dist_data, MAX_DIST); + if (dist_size <= 0) { + free(dist_data); +-- +2.27.0 + diff --git a/backport-nstat-fix-potential-NULL-deref.patch b/backport-nstat-fix-potential-NULL-deref.patch new file mode 100644 index 0000000..663136f --- /dev/null +++ b/backport-nstat-fix-potential-NULL-deref.patch @@ -0,0 +1,364 @@ +From d348d1d6466a4a712b47612c1e9388161334fc7a Mon Sep 17 00:00:00 2001 +From: Stephen Hemminger +Date: Mon, 8 May 2023 19:42:03 -0700 +Subject: [PATCH] nstat: fix potential NULL deref +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reported as: + CC nstat +nstat.c: In function ‘load_ugly_table’: +nstat.c:205:24: warning: dereference of NULL ‘p’ [CWE-476] [-Wanalyzer-null-dereference] + 205 | while (*p) { + | ^~ + ‘main’: events 1-14 + | + | 575 | int main(int argc, char *argv[]) + | | ^~~~ + | | | + | | (1) entry to ‘main’ + |...... + | 635 | if (scan_interval > 0) { + | | ~ + | | | + | | (2) following ‘true’ branch... + | 636 | if (time_constant == 0) + | | ~~~~~~~~~~~~~~~~~~ + | | | + | | (3) ...to here + |...... + | 640 | if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + | | ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | | + | | | (4) when ‘socket’ succeeds + | | (5) following ‘false’ branch (when ‘fd >= 0’)... + |...... + | 644 | if (bind(fd, (struct sockaddr *)&sun, 2+1+strlen(sun.sun_path+1)) < 0) { + | | ~ ~~~~~~~~~~~~~~~~~~~~~~ + | | | | + | | (7) following ‘false’ branch... (6) ...to here + |...... + | 648 | if (listen(fd, 5) < 0) { + | | ~~~~~~~~~~~~~~ + | | || + | | |(8) ...to here + | | |(9) when ‘listen’ succeeds + | | (10) following ‘false’ branch... + |...... + | 652 | if (daemon(0, 0)) { + | | ~~~~~~~~~~~~~ + | | || + | | |(11) ...to here + | | (12) following ‘false’ branch... + |...... + | 656 | signal(SIGPIPE, SIG_IGN); + | | ~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (13) ...to here + | 657 | signal(SIGCHLD, sigchild); + | 658 | server_loop(fd); + | | ~~~~~~~~~~~~~~~ + | | | + | | (14) calling ‘server_loop’ from ‘main’ + | + +--> ‘server_loop’: events 15-16 + | + | 472 | static void server_loop(int fd) + | | ^~~~~~~~~~~ + | | | + | | (15) entry to ‘server_loop’ + |...... + | 483 | load_netstat(); + | | ~~~~~~~~~~~~~~ + | | | + | | (16) calling ‘load_netstat’ from ‘server_loop’ + | + +--> ‘load_netstat’: events 17-20 + | + | 302 | static void load_netstat(void) + | | ^~~~~~~~~~~~ + | | | + | | (17) entry to ‘load_netstat’ + |...... + | 306 | if (fp) { + | | ~ + | | | + | | (18) following ‘true’ branch (when ‘fp’ is non-NULL)... + | 307 | load_ugly_table(fp); + | | ~~~~~~~~~~~~~~~~~~~ + | | | + | | (19) ...to here + | | (20) calling ‘load_ugly_table’ from ‘load_netstat’ + | + +--> ‘load_ugly_table’: events 21-26 + | + | 178 | static void load_ugly_table(FILE *fp) + | | ^~~~~~~~~~~~~~~ + | | | + | | (21) entry to ‘load_ugly_table’ + | 179 | { + | 180 | char *buf = NULL; + | | ~~~ + | | | + | | (22) ‘buf’ is NULL + |...... + | 186 | while ((nread = getline(&buf, &buflen, fp)) != -1) { + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (23) following ‘true’ branch... + |...... + | 192 | p = strchr(buf, ':'); + | | ~~~~~~~~~~~~~~~~ + | | | + | | (24) ...to here + | | (25) when ‘strchr’ returns non-NULL + | 193 | if (!p) { + | | ~ + | | | + | | (26) following ‘false’ branch (when ‘p’ is non-NULL)... + | + ‘load_ugly_table’: event 27 + | + |cc1: + | (27): ...to here + | + ‘load_ugly_table’: events 28-40 + | + | 205 | while (*p) { + | | ^~ + | | | + | | (28) following ‘true’ branch... + | | (40) dereference of NULL ‘p’ + |...... + | 208 | if ((next = strchr(p, ' ')) != NULL) + | | ~ ~~~~~~~~~~~~~~ + | | | | + | | | (29) ...to here + | | | (30) when ‘strchr’ returns NULL + | | (31) following ‘false’ branch (when ‘next’ is NULL)... + | 209 | *next++ = 0; + | 210 | else if ((next = strchr(p, '\n')) != NULL) + | | ~ ~~~~~~~~~~~~~~~ + | | | | + | | | (32) ...to here + | | | (33) when ‘strchr’ returns NULL + | | (34) following ‘false’ branch (when ‘next’ is NULL)... + | 211 | *next++ = 0; + | 212 | if (off < sizeof(idbuf)) { + | | ~~~~~~~~~~~~~~~~~~~~ + | | | | + | | | (35) ...to here + | | (36) following ‘false’ branch... + |...... + | 216 | n = malloc(sizeof(*n)); + | | ~~~~~~~~~~~~~~~~~~ + | | | + | | (37) ...to here + | 217 | if (!n) { + | | ~ + | | | + | | (38) following ‘false’ branch (when ‘n’ is non-NULL)... + |...... + | 221 | n->id = strdup(idbuf); + | | ~~~~~~~~~~~~~ + | | | + | | (39) ...to here + | +nstat.c:254:35: warning: dereference of NULL ‘n’ [CWE-476] [-Wanalyzer-null-dereference] + 254 | n = n->next; + | ~~^~~~~~~~~ + ‘main’: events 1-14 + | + | 575 | int main(int argc, char *argv[]) + | | ^~~~ + | | | + | | (1) entry to ‘main’ + |...... + | 635 | if (scan_interval > 0) { + | | ~ + | | | + | | (2) following ‘true’ branch... + | 636 | if (time_constant == 0) + | | ~~~~~~~~~~~~~~~~~~ + | | | + | | (3) ...to here + |...... + | 640 | if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + | | ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | | + | | | (4) when ‘socket’ succeeds + | | (5) following ‘false’ branch (when ‘fd >= 0’)... + |...... + | 644 | if (bind(fd, (struct sockaddr *)&sun, 2+1+strlen(sun.sun_path+1)) < 0) { + | | ~ ~~~~~~~~~~~~~~~~~~~~~~ + | | | | + | | (7) following ‘false’ branch... (6) ...to here + |...... + | 648 | if (listen(fd, 5) < 0) { + | | ~~~~~~~~~~~~~~ + | | || + | | |(8) ...to here + | | |(9) when ‘listen’ succeeds + | | (10) following ‘false’ branch... + |...... + | 652 | if (daemon(0, 0)) { + | | ~~~~~~~~~~~~~ + | | || + | | |(11) ...to here + | | (12) following ‘false’ branch... + |...... + | 656 | signal(SIGPIPE, SIG_IGN); + | | ~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (13) ...to here + | 657 | signal(SIGCHLD, sigchild); + | 658 | server_loop(fd); + | | ~~~~~~~~~~~~~~~ + | | | + | | (14) calling ‘server_loop’ from ‘main’ + | + +--> ‘server_loop’: events 15-16 + | + | 472 | static void server_loop(int fd) + | | ^~~~~~~~~~~ + | | | + | | (15) entry to ‘server_loop’ + |...... + | 483 | load_netstat(); + | | ~~~~~~~~~~~~~~ + | | | + | | (16) calling ‘load_netstat’ from ‘server_loop’ + | + +--> ‘load_netstat’: events 17-20 + | + | 302 | static void load_netstat(void) + | | ^~~~~~~~~~~~ + | | | + | | (17) entry to ‘load_netstat’ + |...... + | 306 | if (fp) { + | | ~ + | | | + | | (18) following ‘true’ branch (when ‘fp’ is non-NULL)... + | 307 | load_ugly_table(fp); + | | ~~~~~~~~~~~~~~~~~~~ + | | | + | | (19) ...to here + | | (20) calling ‘load_ugly_table’ from ‘load_netstat’ + | + +--> ‘load_ugly_table’: events 21-25 + | + | 178 | static void load_ugly_table(FILE *fp) + | | ^~~~~~~~~~~~~~~ + | | | + | | (21) entry to ‘load_ugly_table’ + |...... + | 186 | while ((nread = getline(&buf, &buflen, fp)) != -1) { + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (22) following ‘true’ branch... + |...... + | 192 | p = strchr(buf, ':'); + | | ~~~~~~~~~~~~~~~~ + | | | + | | (23) ...to here + | | (24) when ‘strchr’ returns non-NULL + | 193 | if (!p) { + | | ~ + | | | + | | (25) following ‘false’ branch (when ‘p’ is non-NULL)... + | + ‘load_ugly_table’: event 26 + | + |cc1: + | (26): ...to here + | + ‘load_ugly_table’: events 27-28 + | + | 205 | while (*p) { + | | ^ + | | | + | | (27) following ‘false’ branch... + |...... + | 228 | nread = getline(&buf, &buflen, fp); + | | ~ + | | | + | | (28) inlined call to ‘getline’ from ‘load_ugly_table’ + | + +--> ‘getline’: event 29 + | + |/usr/include/bits/stdio.h:120:10: + | 120 | return __getdelim (__lineptr, __n, '\n', __stream); + | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (29) ...to here + | + <------+ + | + ‘load_ugly_table’: events 30-36 + | + |nstat.c:229:20: + | 229 | if (nread == -1) { + | | ^ + | | | + | | (30) following ‘false’ branch... + |...... + | 234 | count2 = count_spaces(buf); + | | ~~~~~~~~~~~~~~~~~ + | | | + | | (31) ...to here + |...... + | 239 | if (!p) { + | | ~ + | | | + | | (32) following ‘false’ branch (when ‘p’ is non-NULL)... + |...... + | 244 | *p = 0; + | | ~~~~~~ + | | | + | | (33) ...to here + | 245 | if (sscanf(p+1, "%llu", &n->val) != 1) { + | | ~ + | | | + | | (34) following ‘false’ branch... + |...... + | 251 | if (skip) + | | ~ + | | | + | | (35) ...to here + |...... + | 254 | n = n->next; + | | ~~~~~~~~~~~ + | | | + | | (36) dereference of NULL ‘n’ + | + +Signed-off-by: Stephen Hemminger +--- + misc/nstat.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/misc/nstat.c b/misc/nstat.c +index 0ab92ecb..2c10feaa 100644 +--- a/misc/nstat.c ++++ b/misc/nstat.c +@@ -219,9 +219,15 @@ static void load_ugly_table(FILE *fp) + exit(-1); + } + n->id = strdup(idbuf); ++ if (n->id == NULL) { ++ perror("nstat: strdup"); ++ exit(-1); ++ } + n->rate = 0; + n->next = db; + db = n; ++ if (next == NULL) ++ break; + p = next; + } + n = db; +-- +2.27.0 + diff --git a/backport-rdma-utils-fix-some-analyzer-warnings.patch b/backport-rdma-utils-fix-some-analyzer-warnings.patch new file mode 100644 index 0000000..214d578 --- /dev/null +++ b/backport-rdma-utils-fix-some-analyzer-warnings.patch @@ -0,0 +1,87 @@ +From 33722349feb9ac8ea77cf658f79940a42261f44d Mon Sep 17 00:00:00 2001 +From: Stephen Hemminger +Date: Mon, 8 May 2023 20:15:52 -0700 +Subject: [PATCH] rdma/utils: fix some analyzer warnings +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add error checks for cases where analyzer thinks it is possible +to us a possibly NULL value. + +utils.c: In function ‘get_port_from_argv’: +utils.c:76:17: warning: use of NULL where non-null expected [CWE-476] [-Wanalyzer-null-argument] + 76 | slash = strchr(rd_argv(rd), '/'); + | ^~~~~~~~~~~~~~~~~~~~~~~~ + ‘get_port_from_argv’: events 1-2 + | + | 68 | static int get_port_from_argv(struct rd *rd, uint32_t *port, + | | ^~~~~~~~~~~~~~~~~~ + | | | + | | (1) entry to ‘get_port_from_argv’ + |...... + | 76 | slash = strchr(rd_argv(rd), '/'); + | | ~ + | | | + | | (2) inlined call to ‘rd_argv’ from ‘get_port_from_argv’ + | + +--> ‘rd_argv’: event 3 + | + | 18 | if (!rd_argc(rd)) + | | ^ + | | | + | | (3) following ‘true’ branch... + | + <------+ + | + ‘get_port_from_argv’: events 4-5 + | + | 76 | slash = strchr(rd_argv(rd), '/'); + | | ^~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (4) ...to here + | | (5) argument 1 (‘’) NULL where non-null expected + | +In file included from rdma.h:10, + from utils.c:7: +/usr/include/string.h:246:14: note: argument 1 of ‘strchr’ must be non-null + 246 | extern char *strchr (const char *__s, int __c) + | ^~~~~~ + +Fixes: 40df8263a0f0 ("rdma: Add dev object") +Signed-off-by: Stephen Hemminger +--- + rdma/utils.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/rdma/utils.c b/rdma/utils.c +index 21177b56..a33ff420 100644 +--- a/rdma/utils.c ++++ b/rdma/utils.c +@@ -75,6 +75,13 @@ static int get_port_from_argv(struct rd *rd, uint32_t *port, + + slash = strchr(rd_argv(rd), '/'); + /* if no port found, return 0 */ ++ if (slash == NULL) { ++ if (strict_port) ++ return -EINVAL; ++ else ++ return 0; ++ } ++ + if (slash++) { + if (*slash == '-') { + if (strict_port) +@@ -747,6 +754,9 @@ struct dev_map *dev_map_lookup(struct rd *rd, bool allow_port_index) + return NULL; + + dev_name = strdup(rd_argv(rd)); ++ if (!dev_name) ++ return NULL; ++ + if (allow_port_index) { + slash = strrchr(dev_name, '/'); + if (slash) +-- +2.27.0 + diff --git a/backport-rt_names-check-for-malloc-failure.patch b/backport-rt_names-check-for-malloc-failure.patch new file mode 100644 index 0000000..2b5b7b4 --- /dev/null +++ b/backport-rt_names-check-for-malloc-failure.patch @@ -0,0 +1,30 @@ +From 507fe042181c8e481e4463ab66b3f7af897a5500 Mon Sep 17 00:00:00 2001 +From: Stephen Hemminger +Date: Wed, 7 Jun 2023 18:33:49 -0700 +Subject: [PATCH] rt_names: check for malloc() failure + +Fixes issue reported by Gcc 13 analayzer. + +Signed-off-by: Stephen Hemminger +--- + lib/rt_names.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/lib/rt_names.c b/lib/rt_names.c +index b441e98f..68db74e3 100644 +--- a/lib/rt_names.c ++++ b/lib/rt_names.c +@@ -81,6 +81,10 @@ rtnl_hash_initialize(const char *file, struct rtnl_hash_entry **hash, int size) + continue; + + entry = malloc(sizeof(*entry)); ++ if (entry == NULL) { ++ fprintf(stderr, "malloc error: for entry\n"); ++ break; ++ } + entry->id = id; + entry->name = strdup(namebuf); + entry->next = hash[id & (size - 1)]; +-- +2.27.0 + diff --git a/backport-tc-prio-handle-possible-truncated-kernel-response.patch b/backport-tc-prio-handle-possible-truncated-kernel-response.patch new file mode 100644 index 0000000..7ce1b60 --- /dev/null +++ b/backport-tc-prio-handle-possible-truncated-kernel-response.patch @@ -0,0 +1,74 @@ +From c90d25e96b010c5837b5db9eaa57f5063f0c2aeb Mon Sep 17 00:00:00 2001 +From: Stephen Hemminger +Date: Mon, 8 May 2023 20:17:50 -0700 +Subject: [PATCH] tc/prio: handle possible truncated kernel response +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reported by -fanalyzer. If kernel did not send full qdisc +info, then uninitialized or null data could be referenced. + +q_prio.c: In function ‘prio_print_opt’: +q_prio.c:105:57: warning: dereference of NULL ‘0’ [CWE-476] [-Wanalyzer-null-dereference] + 105 | print_uint(PRINT_ANY, "bands", "bands %u ", qopt->bands); + | ~~~~^~~~~~~ + ‘prio_print_opt’: event 1 + | + | 98 | if (opt == NULL) + | | ^ + | | | + | | (1) following ‘false’ branch (when ‘opt’ is non-NULL)... + | + ‘prio_print_opt’: event 2 + | + |../include/uapi/linux/rtnetlink.h:228:38: + | 228 | #define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0)) + | | ~~~~~~^~~~~~~~~~ + | | | + | | (2) ...to here +../include/libnetlink.h:236:19: note: in expansion of macro ‘RTA_PAYLOAD’ + | 236 | ({ data = RTA_PAYLOAD(rta) >= len ? RTA_DATA(rta) : NULL; \ + | | ^~~~~~~~~~~ +q_prio.c:101:13: note: in expansion of macro ‘parse_rtattr_nested_compat’ + | 101 | if (parse_rtattr_nested_compat(tb, TCA_PRIO_MAX, opt, qopt, + | | ^~~~~~~~~~~~~~~~~~~~~~~~~~ + | + ‘prio_print_opt’: event 3 + | + |../include/libnetlink.h:236:59: + | 236 | ({ data = RTA_PAYLOAD(rta) >= len ? RTA_DATA(rta) : NULL; \ +q_prio.c:101:13: note: in expansion of macro ‘parse_rtattr_nested_compat’ + | 101 | if (parse_rtattr_nested_compat(tb, TCA_PRIO_MAX, opt, qopt, + | | ^~~~~~~~~~~~~~~~~~~~~~~~~~ + | + ‘prio_print_opt’: events 4-5 + | + | 105 | print_uint(PRINT_ANY, "bands", "bands %u ", qopt->bands); + | | ~~~~^~~~~~~ + | | | + | | (4) ...to here + | | (5) dereference of NULL ‘’ + | + +Signed-off-by: Stephen Hemminger +--- + tc/q_prio.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tc/q_prio.c b/tc/q_prio.c +index c8c6477e..a3781ffe 100644 +--- a/tc/q_prio.c ++++ b/tc/q_prio.c +@@ -101,6 +101,8 @@ int prio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) + if (parse_rtattr_nested_compat(tb, TCA_PRIO_MAX, opt, qopt, + sizeof(*qopt))) + return -1; ++ if (qopt == NULL) ++ return -1; /* missing data from kernel */ + + print_uint(PRINT_ANY, "bands", "bands %u ", qopt->bands); + open_json_array(PRINT_ANY, "priomap"); +-- +2.27.0 + diff --git a/backport-tc_exec-don-t-dereference-NULL-on-calloc-failure.patch b/backport-tc_exec-don-t-dereference-NULL-on-calloc-failure.patch new file mode 100644 index 0000000..8b1a8c2 --- /dev/null +++ b/backport-tc_exec-don-t-dereference-NULL-on-calloc-failure.patch @@ -0,0 +1,106 @@ +From 0b9b9d659880a3084ec0a5b49f07f387de7b0f0c Mon Sep 17 00:00:00 2001 +From: Stephen Hemminger +Date: Mon, 8 May 2023 19:21:27 -0700 +Subject: [PATCH] tc_exec: don't dereference NULL on calloc failure +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reported as: +tc_exec.c: In function ‘do_exec’: +tc_exec.c:103:18: warning: dereference of NULL ‘eu’ [CWE-476] [-Wanalyzer-null-dereference] + 103 | return eu->parse_eopt(eu, argc, argv); + | ~~^~~~~~~~~~~~ + ‘do_exec’: events 1-6 + | + | 81 | int do_exec(int argc, char **argv) + | | ^~~~~~~ + | | | + | | (1) entry to ‘do_exec’ + |...... + | 86 | if (argc < 1) { + | | ~ + | | | + | | (2) following ‘false’ branch (when ‘argc > 0’)... + |...... + | 91 | if (matches(*argv, "help") == 0) { + | | ~~~~~~~~~~~~~~~~~~~~~~~ + | | || + | | |(3) ...to here + | | (4) following ‘true’ branch... + |...... + | 96 | strncpy(kind, *argv, sizeof(kind) - 1); + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (5) ...to here + | 97 | + | 98 | eu = get_exec_kind(kind); + | | ~~~~~~~~~~~~~~~~~~~ + | | | + | | (6) calling ‘get_exec_kind’ from ‘do_exec’ + | + +--> ‘get_exec_kind’: events 7-10 + | + | 40 | static struct exec_util *get_exec_kind(const char *name) + | | ^~~~~~~~~~~~~ + | | | + | | (7) entry to ‘get_exec_kind’ + |...... + | 63 | if (eu == NULL) + | | ~ + | | | + | | (8) following ‘true’ branch (when ‘eu’ is NULL)... + | 64 | goto noexist; + | | ~~~~ + | | | + | | (9) ...to here + |...... + | 72 | if (eu) { + | | ~ + | | | + | | (10) following ‘false’ branch (when ‘eu’ is NULL)... + | + ‘get_exec_kind’: event 11 + | + |cc1: + | (11): ...to here + | + <------+ + | + ‘do_exec’: events 12-13 + | + | 98 | eu = get_exec_kind(kind); + | | ^~~~~~~~~~~~~~~~~~~ + | | | + | | (12) return of NULL to ‘do_exec’ from ‘get_exec_kind’ + |...... + | 103 | return eu->parse_eopt(eu, argc, argv); + | | ~~~~~~~~~~~~~~ + | | | + | | (13) dereference of NULL ‘eu’ + | + +Fixes: 4bd624467bc6 ("tc: built-in eBPF exec proxy") +Signed-off-by: Stephen Hemminger +--- + tc/tc_exec.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/tc/tc_exec.c b/tc/tc_exec.c +index 5d883402..182fbb4c 100644 +--- a/tc/tc_exec.c ++++ b/tc/tc_exec.c +@@ -96,6 +96,10 @@ int do_exec(int argc, char **argv) + strncpy(kind, *argv, sizeof(kind) - 1); + + eu = get_exec_kind(kind); ++ if (eu == NULL) { ++ fprintf(stderr, "Allocation failed finding exec\n"); ++ return -1; ++ } + + argc--; + argv++; +-- +2.27.0 + diff --git a/backport-tc_util-fix-unitialized-warning.patch b/backport-tc_util-fix-unitialized-warning.patch new file mode 100644 index 0000000..fc40f86 --- /dev/null +++ b/backport-tc_util-fix-unitialized-warning.patch @@ -0,0 +1,318 @@ +From c9c1c9d59a6cfe52f380805a3e91a13ab1a28482 Mon Sep 17 00:00:00 2001 +From: Stephen Hemminger +Date: Mon, 8 May 2023 19:15:43 -0700 +Subject: [PATCH] tc_util fix unitialized warning +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +tc_util.c: In function ‘parse_action_control_slash_spaces’: +tc_util.c:488:28: warning: use of uninitialized value ‘result2’ [CWE-457] [-Wanalyzer-use-of-uninitialized-value] + 488 | *result2_p = result2; + | ~~~~~~~~~~~^~~~~~~~~ + ‘parse_action_control_slash_spaces’: events 1-5 + | + | 455 | static int parse_action_control_slash_spaces(int *argc_p, char ***argv_p, + | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (1) entry to ‘parse_action_control_slash_spaces’ + |...... + | 461 | int result1 = -1, result2; + | | ~~~~~~~ + | | | + | | (2) region created on stack here + | | (3) capacity: 4 bytes + |...... + | 467 | switch (ok) { + | | ~~~~~~ + | | | + | | (4) following ‘case 0:’ branch... + |...... + | 475 | ret = parse_action_control(&argc, &argv, + | | ~ + | | | + | | (5) inlined call to ‘parse_action_control’ from ‘parse_action_control_slash_spaces’ + | + +--> ‘parse_action_control’: events 6-7 + | + | 432 | return __parse_action_control(argc_p, argv_p, result_p, + | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (6) ...to here + | | (7) calling ‘__parse_action_control’ from ‘parse_action_control_slash_spaces’ + | 433 | allow_num, false); + | | ~~~~~~~~~~~~~~~~~ + | + ‘__parse_action_control’: events 8-11 + | + | 371 | static int __parse_action_control(int *argc_p, char ***argv_p, int *result_p, + | | ^~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (8) entry to ‘__parse_action_control’ + |...... + | 378 | if (!argc) + | | ~ + | | | + | | (9) following ‘false’ branch (when ‘argc != 0’)... + | 379 | return -1; + | 380 | if (action_a2n(*argv, &result, allow_num) == -1) { + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (10) ...to here + | | (11) calling ‘action_a2n’ from ‘__parse_action_control’ + | + +--> ‘action_a2n’: events 12-16 + | + | 335 | int action_a2n(char *arg, int *result, bool allow_num) + | | ^~~~~~~~~~ + | | | + | | (12) entry to ‘action_a2n’ + |...... + | 356 | for (iter = a2n; iter->a; iter++) { + | | ~~~~ + | | | + | | (13) following ‘true’ branch... + | 357 | if (matches(arg, iter->a) != 0) + | | ~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (14) ...to here + |...... + | 366 | if (result) + | | ~ + | | | + | | (15) following ‘true’ branch (when ‘result’ is non-NULL)... + | 367 | *result = n; + | | ~~~~~~~~~~~ + | | | + | | (16) ...to here + | + <------+ + | + ‘__parse_action_control’: event 17 + | + | 380 | if (action_a2n(*argv, &result, allow_num) == -1) { + | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (17) returning to ‘__parse_action_control’ from ‘action_a2n’ + | + <------+ + | + ‘parse_action_control_slash_spaces’: event 18 + | + | 475 | ret = parse_action_control(&argc, &argv, + | | ^ + | | | + | | (18) inlined call to ‘parse_action_control’ from ‘parse_action_control_slash_spaces’ + | + +--> ‘parse_action_control’: event 19 + | + | 432 | return __parse_action_control(argc_p, argv_p, result_p, + | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (19) returning to ‘parse_action_control_slash_spaces’ from ‘__parse_action_control’ + | 433 | allow_num, false); + | | ~~~~~~~~~~~~~~~~~ + | + <------+ + | + ‘parse_action_control_slash_spaces’: events 20-24 + | + | 477 | if (ret) + | | ^ + | | | + | | (20) following ‘false’ branch... + | 478 | return ret; + | 479 | ok++; + | | ~~~~ + | | | + | | (21) ...to here + |...... + | 487 | if (ok == 2) + | | ~ + | | | + | | (22) following ‘true’ branch (when ‘ok == 2’)... + | 488 | *result2_p = result2; + | | ~~~~~~~~~~~~~~~~~~~~ + | | | + | | (23) ...to here + | | (24) use of uninitialized value ‘result2’ here + | +tc_util.c:488:28: warning: use of uninitialized value ‘result2’ [CWE-457] [-Wanalyzer-use-of-uninitialized-value] + 488 | *result2_p = result2; + | ~~~~~~~~~~~^~~~~~~~~ + ‘parse_action_control_slash’: events 1-5 + | + | 505 | int parse_action_control_slash(int *argc_p, char ***argv_p, + | | ^~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (1) entry to ‘parse_action_control_slash’ + |...... + | 510 | char *p = strchr(*argv, '/'); + | | ~~~~~~~~~~~~~~~~~~ + | | | + | | (2) when ‘strchr’ returns NULL + | 511 | + | 512 | if (!p) + | | ~ + | | | + | | (3) following ‘true’ branch (when ‘p’ is NULL)... + | 513 | return parse_action_control_slash_spaces(argc_p, argv_p, + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (4) ...to here + | | (5) calling ‘parse_action_control_slash_spaces’ from ‘parse_action_control_slash’ + | 514 | result1_p, result2_p, + | | ~~~~~~~~~~~~~~~~~~~~~ + | 515 | allow_num); + | | ~~~~~~~~~~ + | + +--> ‘parse_action_control_slash_spaces’: events 6-10 + | + | 455 | static int parse_action_control_slash_spaces(int *argc_p, char ***argv_p, + | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (6) entry to ‘parse_action_control_slash_spaces’ + |...... + | 461 | int result1 = -1, result2; + | | ~~~~~~~ + | | | + | | (7) region created on stack here + | | (8) capacity: 4 bytes + |...... + | 467 | switch (ok) { + | | ~~~~~~ + | | | + | | (9) following ‘case 0:’ branch... + |...... + | 475 | ret = parse_action_control(&argc, &argv, + | | ~ + | | | + | | (10) inlined call to ‘parse_action_control’ from ‘parse_action_control_slash_spaces’ + | + +--> ‘parse_action_control’: events 11-12 + | + | 432 | return __parse_action_control(argc_p, argv_p, result_p, + | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (11) ...to here + | | (12) calling ‘__parse_action_control’ from ‘parse_action_control_slash_spaces’ + | 433 | allow_num, false); + | | ~~~~~~~~~~~~~~~~~ + | + ‘__parse_action_control’: events 13-16 + | + | 371 | static int __parse_action_control(int *argc_p, char ***argv_p, int *result_p, + | | ^~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (13) entry to ‘__parse_action_control’ + |...... + | 378 | if (!argc) + | | ~ + | | | + | | (14) following ‘false’ branch (when ‘argc != 0’)... + | 379 | return -1; + | 380 | if (action_a2n(*argv, &result, allow_num) == -1) { + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (15) ...to here + | | (16) calling ‘action_a2n’ from ‘__parse_action_control’ + | + +--> ‘action_a2n’: events 17-21 + | + | 335 | int action_a2n(char *arg, int *result, bool allow_num) + | | ^~~~~~~~~~ + | | | + | | (17) entry to ‘action_a2n’ + |...... + | 356 | for (iter = a2n; iter->a; iter++) { + | | ~~~~ + | | | + | | (18) following ‘true’ branch... + | 357 | if (matches(arg, iter->a) != 0) + | | ~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (19) ...to here + |...... + | 366 | if (result) + | | ~ + | | | + | | (20) following ‘true’ branch (when ‘result’ is non-NULL)... + | 367 | *result = n; + | | ~~~~~~~~~~~ + | | | + | | (21) ...to here + | + <------+ + | + ‘__parse_action_control’: event 22 + | + | 380 | if (action_a2n(*argv, &result, allow_num) == -1) { + | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (22) returning to ‘__parse_action_control’ from ‘action_a2n’ + | + <------+ + | + ‘parse_action_control_slash_spaces’: event 23 + | + | 475 | ret = parse_action_control(&argc, &argv, + | | ^ + | | | + | | (23) inlined call to ‘parse_action_control’ from ‘parse_action_control_slash_spaces’ + | + +--> ‘parse_action_control’: event 24 + | + | 432 | return __parse_action_control(argc_p, argv_p, result_p, + | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (24) returning to ‘parse_action_control_slash_spaces’ from ‘__parse_action_control’ + | 433 | allow_num, false); + | | ~~~~~~~~~~~~~~~~~ + | + <------+ + | + ‘parse_action_control_slash_spaces’: events 25-29 + | + | 477 | if (ret) + | | ^ + | | | + | | (25) following ‘false’ branch... + | 478 | return ret; + | 479 | ok++; + | | ~~~~ + | | | + | | (26) ...to here + |...... + | 487 | if (ok == 2) + | | ~ + | | | + | | (27) following ‘true’ branch (when ‘ok == 2’)... + | 488 | *result2_p = result2; + | | ~~~~~~~~~~~~~~~~~~~~ + | | | + | | (28) ...to here + | | (29) use of uninitialized value ‘result2’ here + | + +Fixes: e67aba559581 ("tc: actions: add helpers to parse and print control actions") +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 0714134e..ed9efa70 100644 +--- a/tc/tc_util.c ++++ b/tc/tc_util.c +@@ -458,7 +458,7 @@ static int parse_action_control_slash_spaces(int *argc_p, char ***argv_p, + { + int argc = *argc_p; + char **argv = *argv_p; +- int result1 = -1, result2; ++ int result1 = -1, result2 = -1; + int *result_p = &result1; + int ok = 0; + int ret; +-- +2.27.0 + diff --git a/iproute.spec b/iproute.spec index c0bbcdc..6b27e29 100644 --- a/iproute.spec +++ b/iproute.spec @@ -2,7 +2,7 @@ Name: iproute Version: 5.15.0 Epoch: 1 -Release: 13 +Release: 14 Summary: Linux network configuration utilities License: GPLv2+ and Public Domain URL: https://kernel.org/pub/linux/utils/net/iproute2/ @@ -29,6 +29,21 @@ Patch6013: backport-ip-address-Fix-memory-leak-when-specifying-device.patch Patch6014: backport-ip-neigh-Fix-memory-leak-when-doing-get.patch Patch6015: backport-mptcp-Fix-memory-leak-when-doing-endpoint-show.patch Patch6016: backport-mptcp-Fix-memory-leak-when-getting-limits.patch +Patch6017: backport-iptunnel-detect-protocol-mismatch-on-tunnel-change.patch +Patch6018: backport-ipnetns-fix-fd-leak-with-ip-netns-set.patch +Patch6019: backport-iproute2-optimize-code-and-fix-some-mem-leak-risk.patch +Patch6020: backport-ipmaddr-fix-dereference-of-NULL-on-malloc-failure.patch +Patch6021: backport-iproute_lwtunnel-fix-possible-use-of-NULL-when-mallo.patch +Patch6022: backport-tc_util-fix-unitialized-warning.patch +Patch6023: backport-tc_exec-don-t-dereference-NULL-on-calloc-failure.patch +Patch6024: backport-m_action-fix-warning-of-overwrite-of-const-string.patch +Patch6025: backport-netem-fix-NULL-deref-on-allocation-failure.patch +Patch6026: backport-nstat-fix-potential-NULL-deref.patch +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 + Patch9000: feature-iproute-add-support-for-ipvlan-l2e-mode.patch Patch9001: bugfix-iproute2-cancel-some-test-cases.patch @@ -107,6 +122,25 @@ install -m 0644 lib/libnetlink.a %{buildroot}%{_libdir}/libnetlink.a %{_mandir}/* %changelog +* Thu Aug 17 2023 gaoxingwang - 1:5.15.0-14 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:ipnetns: fix fd leak with 'ip netns set' + iproute2: optimize code and fix some mem-leak risk + iproute_lwtunnel: fix array boundary check + iproute_lwtunnel: fix possible use of NULL when malloc() + m_action: fix warning of overwrite of const string + netem: fix NULL deref on allocation failure + nstat: fix potential NULL deref + rdma/utils: fix some analyzer warnings + rt_names: check for malloc() failure + tc/prio: handle possible truncated kernel response + tc_exec: don't dereference NULL on calloc failure + tc_util fix unitialized warning + iptunnel: detect protocol mismatch on tunnel change + ipmaddr: fix dereference of NULL on malloc() failure + * Thu Mar 02 2023 jiangheng - 1:5.15.0-13 - Type:bugfix - ID:NA