diff --git a/ethtool-Improve-compatibility-between-netlink-and-io.patch b/ethtool-Improve-compatibility-between-netlink-and-io.patch new file mode 100644 index 0000000..f77837f --- /dev/null +++ b/ethtool-Improve-compatibility-between-netlink-and-io.patch @@ -0,0 +1,187 @@ +From: Ido Schimmel +Date: Mon, 9 Nov 2020 14:29:59 +0100 +Subject: ethtool: Improve compatibility between netlink and ioctl interfaces +Patch-mainline: v5.10 +Git-commit: 124a3c06d1c34b125d84a9eb312fddd365bb7bf6 +References: bsc#1178633 + +With the ioctl interface, when autoneg is enabled, but without +specifying speed, duplex or link modes, the advertised link modes are +set to the supported link modes by the ethtool user space utility. + +This does not happen when using the netlink interface. Fix this +incompatibility problem by having ethtool query the supported link modes +from the kernel and advertise all the "real" ones when only "autoneg on" +is specified. + +Before: + +Settings for eth0: + Supported ports: [ TP ] + Supported link modes: 10baseT/Half 10baseT/Full + 100baseT/Half 100baseT/Full + 1000baseT/Full + Supported pause frame use: No + Supports auto-negotiation: Yes + Supported FEC modes: Not reported + Advertised link modes: 100baseT/Half 100baseT/Full + Advertised pause frame use: No + Advertised auto-negotiation: Yes + Advertised FEC modes: Not reported + Speed: 1000Mb/s + Duplex: Full + Auto-negotiation: on + Port: Twisted Pair + PHYAD: 0 + Transceiver: internal + MDI-X: off (auto) + Supports Wake-on: umbg + Wake-on: d + Current message level: 0x00000007 (7) + drv probe link + Link detected: yes + +After: + +Settings for eth0: + Supported ports: [ TP ] + Supported link modes: 10baseT/Half 10baseT/Full + 100baseT/Half 100baseT/Full + 1000baseT/Full + Supported pause frame use: No + Supports auto-negotiation: Yes + Supported FEC modes: Not reported + Advertised link modes: 10baseT/Half 10baseT/Full + 100baseT/Half 100baseT/Full + 1000baseT/Full + Advertised pause frame use: No + Advertised auto-negotiation: Yes + Advertised FEC modes: Not reported + Speed: 1000Mb/s + Duplex: Full + Auto-negotiation: on + Port: Twisted Pair + PHYAD: 0 + Transceiver: internal + MDI-X: on (auto) + Supports Wake-on: umbg + Wake-on: d + Current message level: 0x00000007 (7) + drv probe link + Link detected: yes + +Signed-off-by: Ido Schimmel +Signed-off-by: Michal Kubecek + +--- + netlink/settings.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 92 insertions(+) + +--- a/netlink/settings.c ++++ b/netlink/settings.c +@@ -1115,6 +1115,93 @@ static const struct param_parser sset_params[] = { + */ + #define SSET_MAX_MSGS 4 + ++static int linkmodes_reply_advert_all_cb(const struct nlmsghdr *nlhdr, ++ void *data) ++{ ++ const struct nlattr *tb[ETHTOOL_A_LINKMODES_MAX + 1] = {}; ++ DECLARE_ATTR_TB_INFO(tb); ++ struct nl_msg_buff *req_msgbuff = data; ++ const struct nlattr *ours_attr; ++ struct nlattr *req_bitset; ++ uint32_t *supported_modes; ++ unsigned int modes_count; ++ unsigned int i; ++ int ret; ++ ++ ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info); ++ if (ret < 0) ++ return MNL_CB_ERROR; ++ ours_attr = tb[ETHTOOL_A_LINKMODES_OURS]; ++ if (!ours_attr) ++ return MNL_CB_ERROR; ++ modes_count = bitset_get_count(tb[ETHTOOL_A_LINKMODES_OURS], &ret); ++ if (ret < 0) ++ return MNL_CB_ERROR; ++ supported_modes = get_compact_bitset_mask(tb[ETHTOOL_A_LINKMODES_OURS]); ++ if (!supported_modes) ++ return MNL_CB_ERROR; ++ ++ /* keep only "real" link modes */ ++ for (i = 0; i < modes_count; i++) ++ if (!lm_class_match(i, LM_CLASS_REAL)) ++ supported_modes[i / 32] &= ~((uint32_t)1 << (i % 32)); ++ ++ req_bitset = ethnla_nest_start(req_msgbuff, ETHTOOL_A_LINKMODES_OURS); ++ if (!req_bitset) ++ return MNL_CB_ERROR; ++ ++ if (ethnla_put_u32(req_msgbuff, ETHTOOL_A_BITSET_SIZE, modes_count) || ++ ethnla_put(req_msgbuff, ETHTOOL_A_BITSET_VALUE, ++ DIV_ROUND_UP(modes_count, 32) * sizeof(uint32_t), ++ supported_modes) || ++ ethnla_put(req_msgbuff, ETHTOOL_A_BITSET_MASK, ++ DIV_ROUND_UP(modes_count, 32) * sizeof(uint32_t), ++ supported_modes)) { ++ ethnla_nest_cancel(req_msgbuff, req_bitset); ++ return MNL_CB_ERROR; ++ } ++ ++ ethnla_nest_end(req_msgbuff, req_bitset); ++ return MNL_CB_OK; ++} ++ ++/* For compatibility reasons with ioctl-based ethtool, when "autoneg on" is ++ * specified without "advertise", "speed" and "duplex", we need to query the ++ * supported link modes from the kernel and advertise all the "real" ones. ++ */ ++static int nl_sset_compat_linkmodes(struct nl_context *nlctx, ++ struct nl_msg_buff *msgbuff) ++{ ++ const struct nlattr *tb[ETHTOOL_A_LINKMODES_MAX + 1] = {}; ++ DECLARE_ATTR_TB_INFO(tb); ++ struct nl_socket *nlsk = nlctx->ethnl_socket; ++ int ret; ++ ++ ret = mnl_attr_parse(msgbuff->nlhdr, GENL_HDRLEN, attr_cb, &tb_info); ++ if (ret < 0) ++ return ret; ++ if (!tb[ETHTOOL_A_LINKMODES_AUTONEG] || tb[ETHTOOL_A_LINKMODES_OURS] || ++ tb[ETHTOOL_A_LINKMODES_SPEED] || tb[ETHTOOL_A_LINKMODES_DUPLEX]) ++ return 0; ++ if (!mnl_attr_get_u8(tb[ETHTOOL_A_LINKMODES_AUTONEG])) ++ return 0; ++ ++ /* all conditions satisfied, create ETHTOOL_A_LINKMODES_OURS */ ++ if (netlink_cmd_check(nlctx->ctx, ETHTOOL_MSG_LINKMODES_GET, false) || ++ netlink_cmd_check(nlctx->ctx, ETHTOOL_MSG_LINKMODES_SET, false)) ++ return -EOPNOTSUPP; ++ ret = nlsock_prep_get_request(nlsk, ETHTOOL_MSG_LINKMODES_GET, ++ ETHTOOL_A_LINKMODES_HEADER, ++ ETHTOOL_FLAG_COMPACT_BITSETS); ++ if (ret < 0) ++ return ret; ++ ret = nlsock_sendmsg(nlsk, NULL); ++ if (ret < 0) ++ return ret; ++ return nlsock_process_reply(nlsk, linkmodes_reply_advert_all_cb, ++ msgbuff); ++} ++ + int nl_sset(struct cmd_context *ctx) + { + struct nl_msg_buff *msgbuffs[SSET_MAX_MSGS] = {}; +@@ -1136,6 +1223,11 @@ int nl_sset(struct cmd_context *ctx) + for (i = 0; i < SSET_MAX_MSGS && msgbuffs[i]; i++) { + struct nl_socket *nlsk = nlctx->ethnl_socket; + ++ if (msgbuffs[i]->genlhdr->cmd == ETHTOOL_MSG_LINKMODES_SET) { ++ ret = nl_sset_compat_linkmodes(nlctx, msgbuffs[i]); ++ if (ret < 0) ++ goto out_free; ++ } + ret = nlsock_sendmsg(nlsk, msgbuffs[i]); + if (ret < 0) + goto out_free; diff --git a/ethtool.changes b/ethtool.changes index 7f7bca3..465836b 100644 --- a/ethtool.changes +++ b/ethtool.changes @@ -1,3 +1,12 @@ +------------------------------------------------------------------- +Wed Nov 11 16:57:07 UTC 2020 - Michal Kubecek + +- backport post-5.9 fixes + * netlink-fix-use-after-free-in-netlink_run_handler.patch + * netlink-fix-leaked-instances-of-struct-nl_socket.patch + * netlink-do-not-send-messages-and-process-replies-in-.patch + * ethtool-Improve-compatibility-between-netlink-and-io.patch + ------------------------------------------------------------------- Thu Oct 15 18:50:12 UTC 2020 - Michal Kubecek diff --git a/ethtool.spec b/ethtool.spec index d7dbde8..8f39281 100644 --- a/ethtool.spec +++ b/ethtool.spec @@ -33,12 +33,21 @@ BuildRequires: pkgconfig BuildRequires: xz BuildRequires: pkgconfig(libmnl) +Patch1: netlink-fix-use-after-free-in-netlink_run_handler.patch +Patch2: netlink-fix-leaked-instances-of-struct-nl_socket.patch +Patch3: netlink-do-not-send-messages-and-process-replies-in-.patch +Patch4: ethtool-Improve-compatibility-between-netlink-and-io.patch + %description Ethtool is a small utility for examining and tuning ethernet-based network interfaces. See the man page for more details. %prep %setup -q +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 %build export CFLAGS="%optflags -Wall -Wextra -Wstrict-prototypes -Wformat-security -Wpointer-arith" diff --git a/netlink-do-not-send-messages-and-process-replies-in-.patch b/netlink-do-not-send-messages-and-process-replies-in-.patch new file mode 100644 index 0000000..d6639ea --- /dev/null +++ b/netlink-do-not-send-messages-and-process-replies-in-.patch @@ -0,0 +1,281 @@ +From: Michal Kubecek +Date: Mon, 9 Nov 2020 14:29:56 +0100 +Subject: netlink: do not send messages and process replies in nl_parser() +Patch-mainline: v5.10 +Git-commit: acd9730d1e794f85caf1192fe8788876e6f96305 +References: bsc#1178633 + +When called with group_style = PARSER_GROUP_MSG, nl_parser() not only +parses the command line and composes the messages but also sends them to +kernel and processes the replies. This is inconsistent with other modes and +also impractical as it takes the control over the process from caller where +it belongs. + +Modify nl_parser() to pass composed messages back to caller (which is only +nl_sset() at the moment) and let it send requests and process replies. This +will be needed for an upcoming backward compatibility patch which will need +to inspect and possibly modify one of the composed messages. + +Signed-off-by: Michal Kubecek + +--- + netlink/cable_test.c | 2 +- + netlink/channels.c | 2 +- + netlink/coalesce.c | 2 +- + netlink/eee.c | 2 +- + netlink/parser.c | 43 ++++++++++++++++++++++++++++--------------- + netlink/parser.h | 3 ++- + netlink/pause.c | 2 +- + netlink/rings.c | 2 +- + netlink/settings.c | 35 ++++++++++++++++++++++++++++++----- + 9 files changed, 66 insertions(+), 27 deletions(-) + +--- a/netlink/cable_test.c ++++ b/netlink/cable_test.c +@@ -574,7 +574,7 @@ int nl_cable_test_tdr(struct cmd_context *ctx) + ctx->devname, 0)) + return -EMSGSIZE; + +- ret = nl_parser(nlctx, tdr_params, NULL, PARSER_GROUP_NEST); ++ ret = nl_parser(nlctx, tdr_params, NULL, PARSER_GROUP_NEST, NULL); + if (ret < 0) + return ret; + +--- a/netlink/channels.c ++++ b/netlink/channels.c +@@ -126,7 +126,7 @@ int nl_schannels(struct cmd_context *ctx) + ctx->devname, 0)) + return -EMSGSIZE; + +- ret = nl_parser(nlctx, schannels_params, NULL, PARSER_GROUP_NONE); ++ ret = nl_parser(nlctx, schannels_params, NULL, PARSER_GROUP_NONE, NULL); + if (ret < 0) + return 1; + +--- a/netlink/coalesce.c ++++ b/netlink/coalesce.c +@@ -254,7 +254,7 @@ int nl_scoalesce(struct cmd_context *ctx) + ctx->devname, 0)) + return -EMSGSIZE; + +- ret = nl_parser(nlctx, scoalesce_params, NULL, PARSER_GROUP_NONE); ++ ret = nl_parser(nlctx, scoalesce_params, NULL, PARSER_GROUP_NONE, NULL); + if (ret < 0) + return 1; + +--- a/netlink/eee.c ++++ b/netlink/eee.c +@@ -174,7 +174,7 @@ int nl_seee(struct cmd_context *ctx) + ctx->devname, 0)) + return -EMSGSIZE; + +- ret = nl_parser(nlctx, seee_params, NULL, PARSER_GROUP_NONE); ++ ret = nl_parser(nlctx, seee_params, NULL, PARSER_GROUP_NONE, NULL); + if (ret < 0) + return 1; + +--- a/netlink/parser.c ++++ b/netlink/parser.c +@@ -920,7 +920,7 @@ static void __parser_set(uint64_t *map, unsigned int idx) + } + + struct tmp_buff { +- struct nl_msg_buff msgbuff; ++ struct nl_msg_buff *msgbuff; + unsigned int id; + unsigned int orig_len; + struct tmp_buff *next; +@@ -951,7 +951,12 @@ static struct tmp_buff *tmp_buff_find_or_create(struct tmp_buff **phead, + if (!new_buff) + return NULL; + new_buff->id = id; +- msgbuff_init(&new_buff->msgbuff); ++ new_buff->msgbuff = malloc(sizeof(*new_buff->msgbuff)); ++ if (!new_buff->msgbuff) { ++ free(new_buff); ++ return NULL; ++ } ++ msgbuff_init(new_buff->msgbuff); + new_buff->next = NULL; + *pbuff = new_buff; + +@@ -965,7 +970,10 @@ static void tmp_buff_destroy(struct tmp_buff *head) + + while (buff) { + next = buff->next; +- msgbuff_done(&buff->msgbuff); ++ if (buff->msgbuff) { ++ msgbuff_done(buff->msgbuff); ++ free(buff->msgbuff); ++ } + free(buff); + buff = next; + } +@@ -980,13 +988,22 @@ static void tmp_buff_destroy(struct tmp_buff *head) + * param_parser::offset) + * @group_style: defines if identifiers in .group represent separate messages, + * nested attributes or are not allowed ++ * @msgbuffs: (only used for @group_style = PARSER_GROUP_MSG) array to store ++ * pointers to composed messages; caller must make sure this ++ * array is sufficient, i.e. that it has at least as many entries ++ * as the number of different .group values in params array; ++ * entries are filled from the start, remaining entries are not ++ * modified; caller should zero initialize the array before ++ * calling nl_parser() + */ + int nl_parser(struct nl_context *nlctx, const struct param_parser *params, +- void *dest, enum parser_group_style group_style) ++ void *dest, enum parser_group_style group_style, ++ struct nl_msg_buff **msgbuffs) + { + struct nl_socket *nlsk = nlctx->ethnl_socket; + const struct param_parser *parser; + struct tmp_buff *buffs = NULL; ++ unsigned int n_msgbuffs = 0; + struct tmp_buff *buff; + unsigned int n_params; + uint64_t *params_seen; +@@ -1004,7 +1021,7 @@ int nl_parser(struct nl_context *nlctx, const struct param_parser *params, + buff = tmp_buff_find_or_create(&buffs, parser->group); + if (!buff) + goto out_free_buffs; +- msgbuff = &buff->msgbuff; ++ msgbuff = buff->msgbuff; + ret = msg_init(nlctx, msgbuff, parser->group, + NLM_F_REQUEST | NLM_F_ACK); + if (ret < 0) +@@ -1013,7 +1030,7 @@ int nl_parser(struct nl_context *nlctx, const struct param_parser *params, + switch (group_style) { + case PARSER_GROUP_NEST: + ret = -EMSGSIZE; +- nest = ethnla_nest_start(&buff->msgbuff, parser->group); ++ nest = ethnla_nest_start(buff->msgbuff, parser->group); + if (!nest) + goto out_free_buffs; + break; +@@ -1062,7 +1079,7 @@ int nl_parser(struct nl_context *nlctx, const struct param_parser *params, + buff = NULL; + if (parser->group) + buff = tmp_buff_find(buffs, parser->group); +- msgbuff = buff ? &buff->msgbuff : &nlsk->msgbuff; ++ msgbuff = buff ? buff->msgbuff : &nlsk->msgbuff; + + param_dest = dest ? ((char *)dest + parser->dest_offset) : NULL; + ret = parser->handler(nlctx, parser->type, parser->handler_data, +@@ -1074,12 +1091,12 @@ int nl_parser(struct nl_context *nlctx, const struct param_parser *params, + if (group_style == PARSER_GROUP_MSG) { + ret = -EOPNOTSUPP; + for (buff = buffs; buff; buff = buff->next) +- if (msgbuff_len(&buff->msgbuff) > buff->orig_len && ++ if (msgbuff_len(buff->msgbuff) > buff->orig_len && + netlink_cmd_check(nlctx->ctx, buff->id, false)) + goto out_free; + } + for (buff = buffs; buff; buff = buff->next) { +- struct nl_msg_buff *msgbuff = &buff->msgbuff; ++ struct nl_msg_buff *msgbuff = buff->msgbuff; + + if (group_style == PARSER_GROUP_NONE || + msgbuff_len(msgbuff) == buff->orig_len) +@@ -1092,12 +1109,8 @@ int nl_parser(struct nl_context *nlctx, const struct param_parser *params, + goto out_free; + break; + case PARSER_GROUP_MSG: +- ret = nlsock_sendmsg(nlsk, msgbuff); +- if (ret < 0) +- goto out_free; +- ret = nlsock_process_reply(nlsk, nomsg_reply_cb, NULL); +- if (ret < 0) +- goto out_free; ++ msgbuffs[n_msgbuffs++] = msgbuff; ++ buff->msgbuff = NULL; + break; + default: + break; +--- a/netlink/parser.h ++++ b/netlink/parser.h +@@ -143,6 +143,7 @@ int nl_parse_char_bitset(struct nl_context *nlctx, uint16_t type, + + /* main entry point called to parse the command line */ + int nl_parser(struct nl_context *nlctx, const struct param_parser *params, +- void *dest, enum parser_group_style group_style); ++ void *dest, enum parser_group_style group_style, ++ struct nl_msg_buff **msgbuffs); + + #endif /* ETHTOOL_NETLINK_PARSER_H__ */ +--- a/netlink/pause.c ++++ b/netlink/pause.c +@@ -208,7 +208,7 @@ int nl_spause(struct cmd_context *ctx) + ctx->devname, 0)) + return -EMSGSIZE; + +- ret = nl_parser(nlctx, spause_params, NULL, PARSER_GROUP_NONE); ++ ret = nl_parser(nlctx, spause_params, NULL, PARSER_GROUP_NONE, NULL); + if (ret < 0) + return 1; + +--- a/netlink/rings.c ++++ b/netlink/rings.c +@@ -126,7 +126,7 @@ int nl_sring(struct cmd_context *ctx) + ctx->devname, 0)) + return -EMSGSIZE; + +- ret = nl_parser(nlctx, sring_params, NULL, PARSER_GROUP_NONE); ++ ret = nl_parser(nlctx, sring_params, NULL, PARSER_GROUP_NONE, NULL); + if (ret < 0) + return 1; + +--- a/netlink/settings.c ++++ b/netlink/settings.c +@@ -1110,9 +1110,16 @@ static const struct param_parser sset_params[] = { + {} + }; + ++/* Maximum number of request messages sent to kernel; must be equal to the ++ * number of different .group values in sset_params[] array. ++ */ ++#define SSET_MAX_MSGS 4 ++ + int nl_sset(struct cmd_context *ctx) + { ++ struct nl_msg_buff *msgbuffs[SSET_MAX_MSGS] = {}; + struct nl_context *nlctx = ctx->nlctx; ++ unsigned int i; + int ret; + + nlctx->cmd = "-s"; +@@ -1120,11 +1127,29 @@ int nl_sset(struct cmd_context *ctx) + nlctx->argc = ctx->argc; + nlctx->devname = ctx->devname; + +- ret = nl_parser(nlctx, sset_params, NULL, PARSER_GROUP_MSG); +- if (ret < 0) +- return 1; ++ ret = nl_parser(nlctx, sset_params, NULL, PARSER_GROUP_MSG, msgbuffs); ++ if (ret < 0) { ++ ret = 1; ++ goto out_free; ++ } ++ ++ for (i = 0; i < SSET_MAX_MSGS && msgbuffs[i]; i++) { ++ struct nl_socket *nlsk = nlctx->ethnl_socket; + +- if (ret == 0) +- return 0; ++ ret = nlsock_sendmsg(nlsk, msgbuffs[i]); ++ if (ret < 0) ++ goto out_free; ++ ret = nlsock_process_reply(nlsk, nomsg_reply_cb, NULL); ++ if (ret < 0) ++ goto out_free; ++ } ++ ++out_free: ++ for (i = 0; i < SSET_MAX_MSGS && msgbuffs[i]; i++) { ++ msgbuff_done(msgbuffs[i]); ++ free(msgbuffs[i]); ++ } ++ if (ret >= 0) ++ return ret; + return nlctx->exit_code ?: 75; + } diff --git a/netlink-fix-leaked-instances-of-struct-nl_socket.patch b/netlink-fix-leaked-instances-of-struct-nl_socket.patch new file mode 100644 index 0000000..c8bd719 --- /dev/null +++ b/netlink-fix-leaked-instances-of-struct-nl_socket.patch @@ -0,0 +1,59 @@ +From: Michal Kubecek +Date: Mon, 9 Nov 2020 13:30:57 +0100 +Subject: netlink: fix leaked instances of struct nl_socket +Patch-mainline: v5.10 +Git-commit: d85f57499d75da5c98b73652488f3f62c6f6d8ea +References: bsc#1178633 + +Valgrind detected memory leaks caused by missing cleanup of netlink +context's ethnl_socket, ethnl2_socket and rtnl_socket. Also, contrary to +its description, nlsock_done() does not free struct nl_socket itself. +Fix nlsock_done() to free the structure and use it to dispose of sockets +pointed to by struct nl_context members. + +Fixes: 50efb3cdd2bb ("netlink: netlink socket wrapper and helpers") +Fixes: 87307c30724d ("netlink: initialize ethtool netlink socket") +Fixes: 7f3585b22a4b ("netlink: add handler for permaddr (-P)") +Signed-off-by: Michal Kubecek + +--- + netlink/netlink.c | 11 ++++++++--- + netlink/nlsock.c | 3 +++ + 2 files changed, 11 insertions(+), 3 deletions(-) + +--- a/netlink/netlink.c ++++ b/netlink/netlink.c +@@ -280,11 +280,16 @@ out_free: + + static void netlink_done(struct cmd_context *ctx) + { +- if (!ctx->nlctx) ++ struct nl_context *nlctx = ctx->nlctx; ++ ++ if (!nlctx) + return; + +- free(ctx->nlctx->ops_flags); +- free(ctx->nlctx); ++ nlsock_done(nlctx->ethnl_socket); ++ nlsock_done(nlctx->ethnl2_socket); ++ nlsock_done(nlctx->rtnl_socket); ++ free(nlctx->ops_flags); ++ free(nlctx); + ctx->nlctx = NULL; + cleanup_all_strings(); + } +--- a/netlink/nlsock.c ++++ b/netlink/nlsock.c +@@ -395,8 +395,11 @@ out_msgbuff: + */ + void nlsock_done(struct nl_socket *nlsk) + { ++ if (!nlsk) ++ return; + if (nlsk->sk) + mnl_socket_close(nlsk->sk); + msgbuff_done(&nlsk->msgbuff); + memset(nlsk, '\0', sizeof(*nlsk)); ++ free(nlsk); + } diff --git a/netlink-fix-use-after-free-in-netlink_run_handler.patch b/netlink-fix-use-after-free-in-netlink_run_handler.patch new file mode 100644 index 0000000..e0ba8b5 --- /dev/null +++ b/netlink-fix-use-after-free-in-netlink_run_handler.patch @@ -0,0 +1,50 @@ +From: Michal Kubecek +Date: Mon, 9 Nov 2020 13:30:54 +0100 +Subject: netlink: fix use after free in netlink_run_handler() +Patch-mainline: v5.10 +Git-commit: 29b38ea218bd978d1950e12cc24da98215a1eeef +References: bsc#1178633 + +Valgrind detected use after free in netlink_run_handler(): some members of +struct nl_context are accessed after the netlink context is freed by +netlink_done(). Use local variables to store the two flags and check them +instead. + +Fixes: 6c19c0d559c8 ("netlink: use genetlink ops information to decide about fallback") +Signed-off-by: Michal Kubecek + +--- + netlink/netlink.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +--- a/netlink/netlink.c ++++ b/netlink/netlink.c +@@ -302,6 +302,7 @@ void netlink_run_handler(struct cmd_context *ctx, nl_func_t nlfunc, + bool no_fallback) + { + bool wildcard = ctx->devname && !strcmp(ctx->devname, WILDCARD_DEVNAME); ++ bool wildcard_unsupported, ioctl_fallback; + struct nl_context *nlctx; + const char *reason; + int ret; +@@ -323,14 +324,17 @@ void netlink_run_handler(struct cmd_context *ctx, nl_func_t nlfunc, + nlctx = ctx->nlctx; + + ret = nlfunc(ctx); ++ wildcard_unsupported = nlctx->wildcard_unsupported; ++ ioctl_fallback = nlctx->ioctl_fallback; + netlink_done(ctx); +- if (no_fallback || ret != -EOPNOTSUPP || !nlctx->ioctl_fallback) { +- if (nlctx->wildcard_unsupported) ++ ++ if (no_fallback || ret != -EOPNOTSUPP || !ioctl_fallback) { ++ if (wildcard_unsupported) + fprintf(stderr, "%s\n", + "subcommand does not support wildcard dump"); + exit(ret >= 0 ? ret : 1); + } +- if (nlctx->wildcard_unsupported) ++ if (wildcard_unsupported) + reason = "subcommand does not support wildcard dump"; + else + reason = "kernel netlink support for subcommand missing";