From: Greg Kroah-Hartman Date: Mon, 29 Apr 2024 11:07:36 +0000 (+0200) Subject: 6.1-stable patches X-Git-Tag: v4.19.313~67 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=187695329699f58c98a261b2b478c9d8c08ebbdc;p=thirdparty%2Fkernel%2Fstable-queue.git 6.1-stable patches added patches: virtio_net-do-not-send-rss-key-if-it-is-not-supported.patch --- diff --git a/queue-6.1/series b/queue-6.1/series index 5d1f823fa7c..811b72c5599 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -58,3 +58,4 @@ net-ethernet-ti-am65-cpts-fix-ptpv1-message-type-on-.patch af_unix-suppress-false-positive-lockdep-splat-for-sp.patch cifs-replace-remaining-1-element-arrays.patch revert-crypto-api-disallow-identical-driver-names.patch +virtio_net-do-not-send-rss-key-if-it-is-not-supported.patch diff --git a/queue-6.1/virtio_net-do-not-send-rss-key-if-it-is-not-supported.patch b/queue-6.1/virtio_net-do-not-send-rss-key-if-it-is-not-supported.patch new file mode 100644 index 00000000000..042c14e3b11 --- /dev/null +++ b/queue-6.1/virtio_net-do-not-send-rss-key-if-it-is-not-supported.patch @@ -0,0 +1,131 @@ +From 059a49aa2e25c58f90b50151f109dd3c4cdb3a47 Mon Sep 17 00:00:00 2001 +From: Breno Leitao +Date: Wed, 3 Apr 2024 08:43:12 -0700 +Subject: virtio_net: Do not send RSS key if it is not supported + +From: Breno Leitao + +commit 059a49aa2e25c58f90b50151f109dd3c4cdb3a47 upstream. + +There is a bug when setting the RSS options in virtio_net that can break +the whole machine, getting the kernel into an infinite loop. + +Running the following command in any QEMU virtual machine with virtionet +will reproduce this problem: + + # ethtool -X eth0 hfunc toeplitz + +This is how the problem happens: + +1) ethtool_set_rxfh() calls virtnet_set_rxfh() + +2) virtnet_set_rxfh() calls virtnet_commit_rss_command() + +3) virtnet_commit_rss_command() populates 4 entries for the rss +scatter-gather + +4) Since the command above does not have a key, then the last +scatter-gatter entry will be zeroed, since rss_key_size == 0. +sg_buf_size = vi->rss_key_size; + +5) This buffer is passed to qemu, but qemu is not happy with a buffer +with zero length, and do the following in virtqueue_map_desc() (QEMU +function): + + if (!sz) { + virtio_error(vdev, "virtio: zero sized buffers are not allowed"); + +6) virtio_error() (also QEMU function) set the device as broken + + vdev->broken = true; + +7) Qemu bails out, and do not repond this crazy kernel. + +8) The kernel is waiting for the response to come back (function +virtnet_send_command()) + +9) The kernel is waiting doing the following : + + while (!virtqueue_get_buf(vi->cvq, &tmp) && + !virtqueue_is_broken(vi->cvq)) + cpu_relax(); + +10) None of the following functions above is true, thus, the kernel +loops here forever. Keeping in mind that virtqueue_is_broken() does +not look at the qemu `vdev->broken`, so, it never realizes that the +vitio is broken at QEMU side. + +Fix it by not sending RSS commands if the feature is not available in +the device. + +Fixes: c7114b1249fa ("drivers/net/virtio_net: Added basic RSS support.") +Cc: stable@vger.kernel.org +Cc: qemu-devel@nongnu.org +Signed-off-by: Breno Leitao +Reviewed-by: Heng Qi +Reviewed-by: Xuan Zhuo +Signed-off-by: David S. Miller +Signed-off-by: Konstantin Ovsepian +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/virtio_net.c | 26 ++++++++++++++++++++++---- + 1 file changed, 22 insertions(+), 4 deletions(-) + +--- a/drivers/net/virtio_net.c ++++ b/drivers/net/virtio_net.c +@@ -2948,19 +2948,35 @@ static int virtnet_get_rxfh(struct net_d + static int virtnet_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key, const u8 hfunc) + { + struct virtnet_info *vi = netdev_priv(dev); ++ bool update = false; + int i; + + if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) + return -EOPNOTSUPP; + + if (indir) { ++ if (!vi->has_rss) ++ return -EOPNOTSUPP; ++ + for (i = 0; i < vi->rss_indir_table_size; ++i) + vi->ctrl->rss.indirection_table[i] = indir[i]; ++ update = true; + } +- if (key) ++ ++ if (key) { ++ /* If either _F_HASH_REPORT or _F_RSS are negotiated, the ++ * device provides hash calculation capabilities, that is, ++ * hash_key is configured. ++ */ ++ if (!vi->has_rss && !vi->has_rss_hash_report) ++ return -EOPNOTSUPP; ++ + memcpy(vi->ctrl->rss.key, key, vi->rss_key_size); ++ update = true; ++ } + +- virtnet_commit_rss_command(vi); ++ if (update) ++ virtnet_commit_rss_command(vi); + + return 0; + } +@@ -3852,13 +3868,15 @@ static int virtnet_probe(struct virtio_d + if (virtio_has_feature(vdev, VIRTIO_NET_F_HASH_REPORT)) + vi->has_rss_hash_report = true; + +- if (virtio_has_feature(vdev, VIRTIO_NET_F_RSS)) ++ if (virtio_has_feature(vdev, VIRTIO_NET_F_RSS)) { + vi->has_rss = true; + +- if (vi->has_rss || vi->has_rss_hash_report) { + vi->rss_indir_table_size = + virtio_cread16(vdev, offsetof(struct virtio_net_config, + rss_max_indirection_table_length)); ++ } ++ ++ if (vi->has_rss || vi->has_rss_hash_report) { + vi->rss_key_size = + virtio_cread8(vdev, offsetof(struct virtio_net_config, rss_max_key_size)); +