| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/10/03 11:04 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"KMSANReasoning": "",
"NeedsKMSAN": false,
"Reasoning": "The patch modifies the ibmveth driver (drivers/net/ethernet/ibm/ibmveth.[ch]), which depends on CONFIG_PPC_PSERIES and is specific to the PowerPC pSeries architecture. Because the target architecture is amd64, this code cannot be compiled or executed in the fuzzing environment.",
"WorthFuzzing": false
} |
| 1/1 | 2026/10/03 11:04 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 5172e6b380e145ebaf615c6d075260307a0b74d8\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Sat Oct 3 11:04:33 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c\nindex 73e051d26b9d8..5acd5e49b0ad0 100644\n--- a/drivers/net/ethernet/ibm/ibmveth.c\n+++ b/drivers/net/ethernet/ibm/ibmveth.c\n@@ -443,6 +443,37 @@ static void ibmveth_free_buffer_pool(struct ibmveth_adapter *adapter,\n \t}\n }\n \n+/* The correlator comes back from PHYP; a bad one schedules a reset. */\n+static bool ibmveth_rxq_correlator_valid(struct ibmveth_adapter *adapter,\n+\t\t\t\t\t u64 correlator)\n+{\n+\tunsigned int index = correlator \u0026 0xffffffffUL;\n+\tunsigned int pool = correlator \u003e\u003e 32;\n+\n+\t/* An inactive pool keeps its size but has no skbuff array. */\n+\tif (pool \u003c IBMVETH_NUM_BUFF_POOLS \u0026\u0026\n+\t index \u003c adapter-\u003erx_buff_pool[pool].size \u0026\u0026\n+\t adapter-\u003erx_buff_pool[pool].skbuff)\n+\t\treturn true;\n+\n+\tif (net_ratelimit())\n+\t\tnetdev_err(adapter-\u003enetdev,\n+\t\t\t \"invalid RX correlator %llx, resetting\\n\",\n+\t\t\t correlator);\n+\tschedule_work(\u0026adapter-\u003ework);\n+\treturn false;\n+}\n+\n+static void ibmveth_rxq_no_skb(struct ibmveth_adapter *adapter,\n+\t\t\t u64 correlator)\n+{\n+\tif (net_ratelimit())\n+\t\tnetdev_err(adapter-\u003enetdev,\n+\t\t\t \"no buffer for RX correlator %llx, resetting\\n\",\n+\t\t\t correlator);\n+\tschedule_work(\u0026adapter-\u003ework);\n+}\n+\n /**\n * ibmveth_remove_buffer_from_pool - remove a buffer from a pool\n * @adapter: adapter instance\n@@ -451,7 +482,8 @@ static void ibmveth_free_buffer_pool(struct ibmveth_adapter *adapter,\n *\n * Return:\n * * %0 - success\n- * * %-EINVAL - correlator maps to pool or index out of range\n+ * * %-EINVAL - correlator maps to pool or index out of range, or to an\n+ * inactive pool\n * * %-EFAULT - pool and index map to null skb\n */\n static int ibmveth_remove_buffer_from_pool(struct ibmveth_adapter *adapter,\n@@ -462,15 +494,12 @@ static int ibmveth_remove_buffer_from_pool(struct ibmveth_adapter *adapter,\n \tunsigned int free_index;\n \tstruct sk_buff *skb;\n \n-\tif (WARN_ON(pool \u003e= IBMVETH_NUM_BUFF_POOLS) ||\n-\t WARN_ON(index \u003e= adapter-\u003erx_buff_pool[pool].size)) {\n-\t\tschedule_work(\u0026adapter-\u003ework);\n+\tif (!ibmveth_rxq_correlator_valid(adapter, correlator))\n \t\treturn -EINVAL;\n-\t}\n \n \tskb = adapter-\u003erx_buff_pool[pool].skbuff[index];\n-\tif (WARN_ON(!skb)) {\n-\t\tschedule_work(\u0026adapter-\u003ework);\n+\tif (!skb) {\n+\t\tibmveth_rxq_no_skb(adapter, correlator);\n \t\treturn -EFAULT;\n \t}\n \n@@ -510,14 +539,23 @@ static inline struct sk_buff *ibmveth_rxq_get_buffer(struct ibmveth_adapter *ada\n \tu64 correlator = adapter-\u003erx_queue.queue_addr[adapter-\u003erx_queue.index].correlator;\n \tunsigned int pool = correlator \u003e\u003e 32;\n \tunsigned int index = correlator \u0026 0xffffffffUL;\n+\tstruct sk_buff *skb;\n \n-\tif (WARN_ON(pool \u003e= IBMVETH_NUM_BUFF_POOLS) ||\n-\t WARN_ON(index \u003e= adapter-\u003erx_buff_pool[pool].size)) {\n-\t\tschedule_work(\u0026adapter-\u003ework);\n+\tif (!ibmveth_rxq_correlator_valid(adapter, correlator))\n \t\treturn NULL;\n-\t}\n \n-\treturn adapter-\u003erx_buff_pool[pool].skbuff[index];\n+\tskb = adapter-\u003erx_buff_pool[pool].skbuff[index];\n+\tif (!skb)\n+\t\tibmveth_rxq_no_skb(adapter, correlator);\n+\treturn skb;\n+}\n+\n+static void ibmveth_rxq_advance(struct ibmveth_adapter *adapter)\n+{\n+\tif (++adapter-\u003erx_queue.index == adapter-\u003erx_queue.num_slots) {\n+\t\tadapter-\u003erx_queue.index = 0;\n+\t\tadapter-\u003erx_queue.toggle = !adapter-\u003erx_queue.toggle;\n+\t}\n }\n \n /**\n@@ -528,6 +566,9 @@ static inline struct sk_buff *ibmveth_rxq_get_buffer(struct ibmveth_adapter *ada\n *\n * Context: called from ibmveth_poll\n *\n+ * The ring advances even on error, so poll does not return to a bad\n+ * slot before the scheduled reset can run.\n+ *\n * Return:\n * * %0 - success\n * * other - non-zero return from ibmveth_remove_buffer_from_pool\n@@ -540,15 +581,9 @@ static int ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter,\n \n \tcor = adapter-\u003erx_queue.queue_addr[adapter-\u003erx_queue.index].correlator;\n \trc = ibmveth_remove_buffer_from_pool(adapter, cor, reuse);\n-\tif (unlikely(rc))\n-\t\treturn rc;\n-\n-\tif (++adapter-\u003erx_queue.index == adapter-\u003erx_queue.num_slots) {\n-\t\tadapter-\u003erx_queue.index = 0;\n-\t\tadapter-\u003erx_queue.toggle = !adapter-\u003erx_queue.toggle;\n-\t}\n+\tibmveth_rxq_advance(adapter);\n \n-\treturn 0;\n+\treturn rc;\n }\n \n static void ibmveth_free_tx_ltb(struct ibmveth_adapter *adapter, int idx)\n@@ -623,8 +658,6 @@ static int ibmveth_open(struct net_device *netdev)\n \n \tnetdev_dbg(netdev, \"open starting\\n\");\n \n-\tnapi_enable(\u0026adapter-\u003enapi);\n-\n \tfor(i = 0; i \u003c IBMVETH_NUM_BUFF_POOLS; i++)\n \t\trxq_entries += adapter-\u003erx_buff_pool[i].size;\n \n@@ -712,10 +745,18 @@ static int ibmveth_open(struct net_device *netdev)\n \t\t}\n \t}\n \n+\t/* NAPI can run as soon as it is enabled, from netpoll during the\n+\t * direct close()/open() pairs or from a direct ibmveth_interrupt()\n+\t * call, so enable it only once everything ibmveth_poll() touches\n+\t * exists.\n+\t */\n+\tnapi_enable(\u0026adapter-\u003enapi);\n+\n \tnetdev_dbg(netdev, \"registering irq 0x%x\\n\", netdev-\u003eirq);\n \trc = request_irq(netdev-\u003eirq, ibmveth_interrupt, 0, netdev-\u003ename,\n \t\t\t netdev);\n \tif (rc != 0) {\n+\t\tnapi_disable(\u0026adapter-\u003enapi);\n \t\tnetdev_err(netdev, \"unable to request irq 0x%x, rc %d\\n\",\n \t\t\t netdev-\u003eirq, rc);\n \t\tdo {\n@@ -732,6 +773,7 @@ static int ibmveth_open(struct net_device *netdev)\n \n \tnetif_tx_start_all_queues(netdev);\n \n+\tadapter-\u003eopened = true;\n \tnetdev_dbg(netdev, \"open complete\\n\");\n \n \treturn 0;\n@@ -763,7 +805,6 @@ static int ibmveth_open(struct net_device *netdev)\n out_free_buffer_list:\n \tfree_page((unsigned long)adapter-\u003ebuffer_list_addr);\n out:\n-\tnapi_disable(\u0026adapter-\u003enapi);\n \treturn rc;\n }\n \n@@ -774,11 +815,19 @@ static int ibmveth_close(struct net_device *netdev)\n \tlong lpar_rc;\n \tint i;\n \n+\t/* change_mtu, pool sysfs, set_csum and set_tso call close() and\n+\t * open() directly. If that open() fails, IFF_UP stays set and\n+\t * NAPI is disabled; a second close() would hang in napi_disable().\n+\t */\n+\tif (!adapter-\u003eopened)\n+\t\treturn 0;\n+\tadapter-\u003eopened = false;\n+\n \tnetdev_dbg(netdev, \"close starting\\n\");\n \n \tnapi_disable(\u0026adapter-\u003enapi);\n \n-\tnetif_tx_stop_all_queues(netdev);\n+\tnetif_tx_disable(netdev);\n \n \th_vio_signal(adapter-\u003evdev-\u003eunit_address, VIO_IRQ_DISABLE);\n \n@@ -825,10 +874,10 @@ static int ibmveth_close(struct net_device *netdev)\n *\n * @w: pointer to work_struct embedded in adapter structure\n *\n- * Context: This routine acquires rtnl_mutex and disables its NAPI through\n- * ibmveth_close. It can't be called directly in a context that has\n- * already acquired rtnl_mutex or disabled its NAPI, or directly from\n- * a poll routine.\n+ * Context: This routine acquires rtnl_mutex and, if the device is open,\n+ * disables its NAPI through ibmveth_close. It can't be called\n+ * directly in a context that has already acquired rtnl_mutex or\n+ * disabled its NAPI, or directly from a poll routine.\n *\n * Return: void\n */\n@@ -1120,12 +1169,13 @@ static int ibmveth_set_channels(struct net_device *netdev,\n \tstruct ibmveth_adapter *adapter = netdev_priv(netdev);\n \tunsigned int old = netdev-\u003ereal_num_tx_queues,\n \t\t goal = channels-\u003etx_count;\n-\tint rc, i;\n+\tint rc, i, alloc_rc = 0;\n \n-\t/* If ndo_open has not been called yet then don't allocate, just set\n-\t * desired netdev_queue's and return\n+\t/* If the device is not open (including a failed close/open with\n+\t * IFF_UP still set) then don't allocate, just set desired\n+\t * netdev_queue's and return\n \t */\n-\tif (!(netdev-\u003eflags \u0026 IFF_UP))\n+\tif (!adapter-\u003eopened)\n \t\treturn netif_set_real_num_tx_queues(netdev, goal);\n \n \t/* We have IBMVETH_MAX_QUEUES netdev_queue's allocated\n@@ -1145,6 +1195,7 @@ static int ibmveth_set_channels(struct net_device *netdev,\n \t\t/* if something goes wrong, free everything we just allocated */\n \t\tnetdev_err(netdev, \"Failed to allocate more tx queues, returning to %d queues\\n\",\n \t\t\t old);\n+\t\talloc_rc = rc;\n \t\tgoal = old;\n \t\told = i;\n \t\tbreak;\n@@ -1155,6 +1206,8 @@ static int ibmveth_set_channels(struct net_device *netdev,\n \t\t\t old);\n \t\tgoal = old;\n \t\told = i;\n+\t} else if (alloc_rc) {\n+\t\trc = alloc_rc;\n \t}\n \t/* Free any that are no longer needed */\n \tfor (i = old; i \u003e goal; i--) {\n@@ -1453,6 +1506,7 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)\n \tint frames_processed = 0;\n \tunsigned long lpar_rc;\n \tu16 mss = 0;\n+\tint rc;\n \n restart_poll:\n \twhile (frames_processed \u003c budget) {\n@@ -1475,8 +1529,11 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)\n \t\t\t__sum16 iph_check = 0;\n \n \t\t\tskb = ibmveth_rxq_get_buffer(adapter);\n-\t\t\tif (unlikely(!skb))\n+\t\t\tif (unlikely(!skb)) {\n+\t\t\t\tibmveth_rxq_advance(adapter);\n+\t\t\t\tnetdev-\u003estats.rx_dropped++;\n \t\t\t\tbreak;\n+\t\t\t}\n \n \t\t\t/* if the large packet bit is set in the rx queue\n \t\t\t * descriptor, the mss will be written by PHYP eight\n@@ -1500,12 +1557,19 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)\n \t\t\t\tif (rx_flush)\n \t\t\t\t\tibmveth_flush_buffer(skb-\u003edata,\n \t\t\t\t\t\tlength + offset);\n-\t\t\t\tif (unlikely(ibmveth_rxq_harvest_buffer(adapter, true)))\n+\t\t\t\trc = ibmveth_rxq_harvest_buffer(adapter, true);\n+\t\t\t\tif (unlikely(rc)) {\n+\t\t\t\t\tdev_kfree_skb_any(new_skb);\n+\t\t\t\t\tnetdev-\u003estats.rx_dropped++;\n \t\t\t\t\tbreak;\n+\t\t\t\t}\n \t\t\t\tskb = new_skb;\n \t\t\t} else {\n-\t\t\t\tif (unlikely(ibmveth_rxq_harvest_buffer(adapter, false)))\n+\t\t\t\trc = ibmveth_rxq_harvest_buffer(adapter, false);\n+\t\t\t\tif (unlikely(rc)) {\n+\t\t\t\t\tnetdev-\u003estats.rx_dropped++;\n \t\t\t\t\tbreak;\n+\t\t\t\t}\n \t\t\t\tskb_reserve(skb, offset);\n \t\t\t}\n \n@@ -1680,14 +1744,6 @@ static int ibmveth_change_mtu(struct net_device *dev, int new_mtu)\n \treturn -EINVAL;\n }\n \n-#ifdef CONFIG_NET_POLL_CONTROLLER\n-static void ibmveth_poll_controller(struct net_device *dev)\n-{\n-\tibmveth_replenish_task(netdev_priv(dev));\n-\tibmveth_interrupt(dev-\u003eirq, dev);\n-}\n-#endif\n-\n /**\n * ibmveth_get_desired_dma - Calculate IO memory desired by the driver\n *\n@@ -1789,9 +1845,6 @@ static const struct net_device_ops ibmveth_netdev_ops = {\n \t.ndo_validate_addr\t= eth_validate_addr,\n \t.ndo_set_mac_address = ibmveth_set_mac_addr,\n \t.ndo_features_check\t= ibmveth_features_check,\n-#ifdef CONFIG_NET_POLL_CONTROLLER\n-\t.ndo_poll_controller\t= ibmveth_poll_controller,\n-#endif\n };\n \n static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)\n@@ -1915,8 +1968,7 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)\n \tif (rc) {\n \t\tnetdev_dbg(netdev, \"failed to set number of tx queues rc=%d\\n\",\n \t\t\t rc);\n-\t\tfree_netdev(netdev);\n-\t\treturn rc;\n+\t\tgoto err_put_pools;\n \t}\n \tadapter-\u003etx_ltb_size = PAGE_ALIGN(IBMVETH_MAX_TX_BUF_SIZE);\n \tfor (i = 0; i \u003c IBMVETH_MAX_QUEUES; i++)\n@@ -1931,13 +1983,18 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)\n \n \tif (rc) {\n \t\tnetdev_dbg(netdev, \"failed to register netdev rc=%d\\n\", rc);\n-\t\tfree_netdev(netdev);\n-\t\treturn rc;\n+\t\tgoto err_put_pools;\n \t}\n \n \tnetdev_dbg(netdev, \"registered\\n\");\n \n \treturn 0;\n+\n+err_put_pools:\n+\tfor (i = 0; i \u003c IBMVETH_NUM_BUFF_POOLS; i++)\n+\t\tkobject_put(\u0026adapter-\u003erx_buff_pool[i].kobj);\n+\tfree_netdev(netdev);\n+\treturn rc;\n }\n \n static void ibmveth_remove(struct vio_dev *dev)\n@@ -1946,7 +2003,7 @@ static void ibmveth_remove(struct vio_dev *dev)\n \tstruct ibmveth_adapter *adapter = netdev_priv(netdev);\n \tint i;\n \n-\tcancel_work_sync(\u0026adapter-\u003ework);\n+\tdisable_work_sync(\u0026adapter-\u003ework);\n \n \tfor (i = 0; i \u003c IBMVETH_NUM_BUFF_POOLS; i++)\n \t\tkobject_put(\u0026adapter-\u003erx_buff_pool[i].kobj);\n@@ -2196,8 +2253,7 @@ static void ibmveth_reset_kunit(struct work_struct *w)\n * @test: pointer to kunit structure\n *\n * Tests the error returns from ibmveth_remove_buffer_from_pool.\n- * ibmveth_remove_buffer_from_pool also calls WARN_ON, so dmesg should be\n- * checked to see that these warnings happened.\n+ * Each error also logs a ratelimited netdev_err.\n *\n * Return: void\n */\n@@ -2206,6 +2262,7 @@ static void ibmveth_remove_buffer_from_pool_test(struct kunit *test)\n \tstruct ibmveth_adapter *adapter = kunit_kzalloc(test, sizeof(*adapter), GFP_KERNEL);\n \tstruct ibmveth_buff_pool *pool;\n \tu64 correlator;\n+\tint ret;\n \n \tKUNIT_ASSERT_NOT_ERR_OR_NULL(test, adapter);\n \n@@ -2229,6 +2286,13 @@ static void ibmveth_remove_buffer_from_pool_test(struct kunit *test)\n \tKUNIT_EXPECT_EQ(test, -EINVAL, ibmveth_remove_buffer_from_pool(adapter, correlator, false));\n \tKUNIT_EXPECT_EQ(test, -EINVAL, ibmveth_remove_buffer_from_pool(adapter, correlator, true));\n \n+\t/* Pool 2 is in range but has no skbuff array, like an inactive pool. */\n+\tcorrelator = ((u64)2 \u003c\u003c 32) | 0;\n+\tret = ibmveth_remove_buffer_from_pool(adapter, correlator, false);\n+\tKUNIT_EXPECT_EQ(test, -EINVAL, ret);\n+\tret = ibmveth_remove_buffer_from_pool(adapter, correlator, true);\n+\tKUNIT_EXPECT_EQ(test, -EINVAL, ret);\n+\n \tcorrelator = (u64)0 | 0;\n \tpool-\u003eskbuff[0] = NULL;\n \tKUNIT_EXPECT_EQ(test, -EFAULT, ibmveth_remove_buffer_from_pool(adapter, correlator, false));\n@@ -2241,9 +2305,8 @@ static void ibmveth_remove_buffer_from_pool_test(struct kunit *test)\n * ibmveth_rxq_get_buffer_test - unit test for ibmveth_rxq_get_buffer\n * @test: pointer to kunit structure\n *\n- * Tests ibmveth_rxq_get_buffer. ibmveth_rxq_get_buffer also calls WARN_ON for\n- * the NULL returns, so dmesg should be checked to see that these warnings\n- * happened.\n+ * Tests ibmveth_rxq_get_buffer. Each NULL return also logs a ratelimited\n+ * netdev_err.\n *\n * Return: void\n */\n@@ -2280,6 +2343,10 @@ static void ibmveth_rxq_get_buffer_test(struct kunit *test)\n \tadapter-\u003erx_queue.queue_addr[0].correlator = (u64)0 \u003c\u003c 32 | adapter-\u003erx_buff_pool[0].size;\n \tKUNIT_EXPECT_PTR_EQ(test, NULL, ibmveth_rxq_get_buffer(adapter));\n \n+\t/* Pool 2 is in range but has no skbuff array, like an inactive pool. */\n+\tadapter-\u003erx_queue.queue_addr[0].correlator = (u64)2 \u003c\u003c 32 | 0;\n+\tKUNIT_EXPECT_PTR_EQ(test, NULL, ibmveth_rxq_get_buffer(adapter));\n+\n \tpool-\u003eskbuff[0] = skb;\n \tadapter-\u003erx_queue.queue_addr[0].correlator = (u64)0 \u003c\u003c 32 | 0;\n \tKUNIT_EXPECT_PTR_EQ(test, skb, ibmveth_rxq_get_buffer(adapter));\n@@ -2287,9 +2354,68 @@ static void ibmveth_rxq_get_buffer_test(struct kunit *test)\n \tflush_work(\u0026adapter-\u003ework);\n }\n \n+/**\n+ * ibmveth_rxq_harvest_buffer_test - unit test for ibmveth_rxq_harvest_buffer\n+ * @test: pointer to kunit structure\n+ *\n+ * A bad correlator must still advance the RX ring, wrapping and flipping\n+ * the toggle at the end. This covers the harvest path; the advance after\n+ * ibmveth_rxq_get_buffer() fails in ibmveth_poll() is not tested here.\n+ *\n+ * Return: void\n+ */\n+static void ibmveth_rxq_harvest_buffer_test(struct kunit *test)\n+{\n+\tstruct ibmveth_adapter *adapter;\n+\tstruct ibmveth_buff_pool *pool;\n+\tint ret;\n+\n+\tadapter = kunit_kzalloc(test, sizeof(*adapter), GFP_KERNEL);\n+\tKUNIT_ASSERT_NOT_ERR_OR_NULL(test, adapter);\n+\n+\tINIT_WORK(\u0026adapter-\u003ework, ibmveth_reset_kunit);\n+\n+\tadapter-\u003erx_queue.num_slots = 2;\n+\tadapter-\u003erx_queue.index = 0;\n+\tadapter-\u003erx_queue.toggle = 1;\n+\tadapter-\u003erx_queue.queue_addr =\n+\t\tkunit_kcalloc(test, 2, sizeof(struct ibmveth_rx_q_entry),\n+\t\t\t GFP_KERNEL);\n+\tKUNIT_ASSERT_NOT_ERR_OR_NULL(test, adapter-\u003erx_queue.queue_addr);\n+\n+\t/* Set sane values for buffer pools */\n+\tfor (int i = 0; i \u003c IBMVETH_NUM_BUFF_POOLS; i++)\n+\t\tibmveth_init_buffer_pool(\u0026adapter-\u003erx_buff_pool[i], i,\n+\t\t\t\t\t pool_count[i], pool_size[i],\n+\t\t\t\t\t pool_active[i]);\n+\n+\tpool = \u0026adapter-\u003erx_buff_pool[0];\n+\tpool-\u003eskbuff = kunit_kcalloc(test, pool-\u003esize, sizeof(void *),\n+\t\t\t\t GFP_KERNEL);\n+\tKUNIT_ASSERT_NOT_ERR_OR_NULL(test, pool-\u003eskbuff);\n+\n+\t/* Slot 0: pool out of range. Slot 1: valid, but no skb. */\n+\tadapter-\u003erx_queue.queue_addr[0].correlator =\n+\t\t(u64)IBMVETH_NUM_BUFF_POOLS \u003c\u003c 32 | 0;\n+\tadapter-\u003erx_queue.queue_addr[1].correlator = (u64)0 \u003c\u003c 32 | 0;\n+\n+\tret = ibmveth_rxq_harvest_buffer(adapter, true);\n+\tKUNIT_EXPECT_EQ(test, -EINVAL, ret);\n+\tKUNIT_EXPECT_EQ(test, 1ULL, adapter-\u003erx_queue.index);\n+\tKUNIT_EXPECT_EQ(test, 1ULL, adapter-\u003erx_queue.toggle);\n+\n+\tret = ibmveth_rxq_harvest_buffer(adapter, true);\n+\tKUNIT_EXPECT_EQ(test, -EFAULT, ret);\n+\tKUNIT_EXPECT_EQ(test, 0ULL, adapter-\u003erx_queue.index);\n+\tKUNIT_EXPECT_EQ(test, 0ULL, adapter-\u003erx_queue.toggle);\n+\n+\tflush_work(\u0026adapter-\u003ework);\n+}\n+\n static struct kunit_case ibmveth_test_cases[] = {\n \tKUNIT_CASE(ibmveth_remove_buffer_from_pool_test),\n \tKUNIT_CASE(ibmveth_rxq_get_buffer_test),\n+\tKUNIT_CASE(ibmveth_rxq_harvest_buffer_test),\n \t{}\n };\n \ndiff --git a/drivers/net/ethernet/ibm/ibmveth.h b/drivers/net/ethernet/ibm/ibmveth.h\nindex d87713668ed30..3f2240823f6a3 100644\n--- a/drivers/net/ethernet/ibm/ibmveth.h\n+++ b/drivers/net/ethernet/ibm/ibmveth.h\n@@ -172,6 +172,8 @@ struct ibmveth_adapter {\n \tint rx_csum;\n \tint large_send;\n \tbool is_active_trunk;\n+\t/* Set by a successful ibmveth_open(), cleared by ibmveth_close(). */\n+\tbool opened;\n \tunsigned int rx_buffers_per_hcall;\n \n \tu64 fw_ipv6_csum_support;\n"
} |
| 2/1 | 2026/10/03 11:04 | agent | patch-evaluator |
0mModel:core Args: null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch modifies the ibmveth driver (drivers/net/ethernet/ibm/ibmveth.[ch]), which depends on CONFIG_PPC_PSERIES and is specific to the PowerPC pSeries architecture. Because the target architecture is amd64, this code cannot be compiled or executed in the fuzzing environment.",
"WorthFuzzing": false
}Instruction: You are an expert Linux kernel maintainer and security engineer.
Your job is to review a provided patch series and evaluate whether it warrants fuzzing with syzkaller.
IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on internal assumptions. You must actively use your code access
tools to inspect the actual source code, callers, and surrounding context.
================================================================================
1. CORE TRIAGE PHILOSOPHY
================================================================================
The goal of patch fuzzing is to discover crashes, regressions, exposed latent bugs,
and newly triggered assertions introduced by the patch series.
- REACHABILITY IS THE PRIMARY GATE:
Fuzzing can only discover bugs in code that can actually execute in standard virtualized
environments (GCE or QEMU, utilizing software-emulated devices like USB gadgets, netdev, tun/tap).
If the modified code is structurally unreachable (see Section 2), it MUST NOT be fuzzed,
regardless of whether it adds assertions or complex logic.
- DO NOT BLINDLY TRUST "NO FUNCTIONAL CHANGE" (NFCI) OR "REFACTORING" CLAIMS:
Patch authors routinely label changes as "cleanups", "refactorings", or state
"No functional change intended". Do NOT take these claims at face value.
Code refactorings that rearrange logic, introduce helper functions, or alter state management
in core subsystems frequently introduce subtle semantic shifts or uncover latent kernel bugs.
If reachable executable code is modified or refactored, it MUST be fuzzed.
- NEW OR MODIFIED ASSERTIONS IN REACHABLE CODE MUST BE FUZZED:
When a patch introduces or modifies runtime checks or assertions (e.g., WARN_ON*, VM_WARN_ON*,
BUG_ON*, lockdep_assert*) in reachable code paths, it enforces new or stricter invariants.
Even if the author believes the invariant always holds, fuzzing is essential to verify whether
an unusual sequence of operations can violate it.
================================================================================
2. WHEN TO RETURN WorthFuzzing=false (NEGATIVE CRITERIA)
================================================================================
Return WorthFuzzing=false ONLY IF all modified code falls strictly into one or more of these categories:
- Non-kernel and non-executable changes:
* Modifications to Documentation/, comments, or spelling fixes.
* User-space directories, self-tests, samples, or scripts (e.g., tools/, samples/, scripts/, usr/)
that do not affect the compiled kernel image (vmlinux) or kernel modules.
* Purely decorative logging (e.g., message strings in pr_err, printk, dev_info) or tracepoints
that do not alter control flow or data structures.
* Build system or Kconfig changes that do not alter compiled C logic.
- Structurally unreachable hardware:
* Vendor-specific PCIe switches, SmartNICs, or GPU drivers (e.g., mlxsw, pds_core, qed,
ionic, amdgpu) requiring physical ASIC/PCIe cards not emulated in standard QEMU.
- Unreachable execution paths:
* Driver teardown callbacks (.remove, .shutdown, pci_unregister_driver) executed only during
physical PCI hot-unplug or manual sysfs driver unbinding.
* Code paths exclusive to architectures other than the target architecture.
================================================================================
3. WHEN TO RETURN WorthFuzzing=true (POSITIVE CRITERIA)
================================================================================
Return WorthFuzzing=true whenever the patch touches reachable executable code, including:
- Core Subsystems:
* Any logic modifications in memory management (mm/), synchronization/locking (kernel/locking/),
BPF, scheduler, core networking, VFS, or syscall handling.
- Refactorings and Code Cleanups:
* Any restructuring of reachable data structures, helper abstractions, or algorithm flows.
- Runtime Assertions and Defensive Checks:
* Any introduction or alteration of assertions (WARN_ON*, VM_WARN_ON*, BUG_ON*, etc.) in reachable paths.
- Reachable Drivers and Protocols:
* Drivers accessible via virtual buses (virtio, USB gadget, loopback, netlink, binder, sockets, etc.).
================================================================================
4. EXTRACTING FocusSymbols (PREVENTING DILUTION)
================================================================================
When WorthFuzzing=true, you must extract specific kernel functions into FocusSymbols to guide the fuzzer:
- AVOID UBIQUITOUS LIFECYCLE HOT-PATHS:
Do NOT list generic, ubiquitous functions called by almost every program in the corpus
(including, but not limited to: general memory allocators and deallocators, page fault
and trap handlers, or core synchronization primitives; this is not an exhaustive list).
Listing ubiquitous functions causes the fuzzer to classify thousands of unrelated tests as "focused",
which severely dilutes fuzzing effort away from the actual changes.
- TARGET SPECIFIC FEATURE LOGIC AND ENTRYPOINTS:
List functions that specifically implement the logic being added or altered, or direct API entrypoints
for the subsystem feature under review.
- HANDLING STATIC INLINE FUNCTIONS IN HEADERS (.h):
Compiler-inlined static functions (such as static inlines in mm/*.h or include/linux/*.h) lack
distinct symbol addresses in vmlinux and cannot be targeted directly by symbol coverage filters.
If the changes are primarily in static inline helpers, identify non-static, feature-specific caller
functions in .c files that exercise them (avoiding ubiquitous lifecycle wrappers).
================================================================================
5. IDENTIFYING EnableConfigs
================================================================================
Identify any specific CONFIG_ options required to properly compile and reach the modified code:
- Inspect Kconfig files and #ifdef guards; do not make assumptions.
- Check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed.
- Strip any 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.
Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.
Prompt: Target architecture: amd64
For your convenience, here is the diff of the changes:
commit 5172e6b380e145ebaf615c6d075260307a0b74d8
Author: syz-cluster <triage@syzkaller.com>
Date: Sat Oct 3 11:04:33 2026 +0000
syz-cluster: applied patch under review
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index 73e051d26b9d8..5acd5e49b0ad0 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -443,6 +443,37 @@ static void ibmveth_free_buffer_pool(struct ibmveth_adapter *adapter,
}
}
+/* The correlator comes back from PHYP; a bad one schedules a reset. */
+static bool ibmveth_rxq_correlator_valid(struct ibmveth_adapter *adapter,
+ u64 correlator)
+{
+ unsigned int index = correlator & 0xffffffffUL;
+ unsigned int pool = correlator >> 32;
+
+ /* An inactive pool keeps its size but has no skbuff array. */
+ if (pool < IBMVETH_NUM_BUFF_POOLS &&
+ index < adapter->rx_buff_pool[pool].size &&
+ adapter->rx_buff_pool[pool].skbuff)
+ return true;
+
+ if (net_ratelimit())
+ netdev_err(adapter->netdev,
+ "invalid RX correlator %llx, resetting\n",
+ correlator);
+ schedule_work(&adapter->work);
+ return false;
+}
+
+static void ibmveth_rxq_no_skb(struct ibmveth_adapter *adapter,
+ u64 correlator)
+{
+ if (net_ratelimit())
+ netdev_err(adapter->netdev,
+ "no buffer for RX correlator %llx, resetting\n",
+ correlator);
+ schedule_work(&adapter->work);
+}
+
/**
* ibmveth_remove_buffer_from_pool - remove a buffer from a pool
* @adapter: adapter instance
@@ -451,7 +482,8 @@ static void ibmveth_free_buffer_pool(struct ibmveth_adapter *adapter,
*
* Return:
* * %0 - success
- * * %-EINVAL - correlator maps to pool or index out of range
+ * * %-EINVAL - correlator maps to pool or index out of range, or to an
+ * inactive pool
* * %-EFAULT - pool and index map to null skb
*/
static int ibmveth_remove_buffer_from_pool(struct ibmveth_adapter *adapter,
@@ -462,15 +494,12 @@ static int ibmveth_remove_buffer_from_pool(struct ibmveth_adapter *adapter,
unsigned int free_index;
struct sk_buff *skb;
- if (WARN_ON(pool >= IBMVETH_NUM_BUFF_POOLS) ||
- WARN_ON(index >= adapter->rx_buff_pool[pool].size)) {
- schedule_work(&adapter->work);
+ if (!ibmveth_rxq_correlator_valid(adapter, correlator))
return -EINVAL;
- }
skb = adapter->rx_buff_pool[pool].skbuff[index];
- if (WARN_ON(!skb)) {
- schedule_work(&adapter->work);
+ if (!skb) {
+ ibmveth_rxq_no_skb(adapter, correlator);
return -EFAULT;
}
@@ -510,14 +539,23 @@ static inline struct sk_buff *ibmveth_rxq_get_buffer(struct ibmveth_adapter *ada
u64 correlator = adapter->rx_queue.queue_addr[adapter->rx_queue.index].correlator;
unsigned int pool = correlator >> 32;
unsigned int index = correlator & 0xffffffffUL;
+ struct sk_buff *skb;
- if (WARN_ON(pool >= IBMVETH_NUM_BUFF_POOLS) ||
- WARN_ON(index >= adapter->rx_buff_pool[pool].size)) {
- schedule_work(&adapter->work);
+ if (!ibmveth_rxq_correlator_valid(adapter, correlator))
return NULL;
- }
- return adapter->rx_buff_pool[pool].skbuff[index];
+ skb = adapter->rx_buff_pool[pool].skbuff[index];
+ if (!skb)
+ ibmveth_rxq_no_skb(adapter, correlator);
+ return skb;
+}
+
+static void ibmveth_rxq_advance(struct ibmveth_adapter *adapter)
+{
+ if (++adapter->rx_queue.index == adapter->rx_queue.num_slots) {
+ adapter->rx_queue.index = 0;
+ adapter->rx_queue.toggle = !adapter->rx_queue.toggle;
+ }
}
/**
@@ -528,6 +566,9 @@ static inline struct sk_buff *ibmveth_rxq_get_buffer(struct ibmveth_adapter *ada
*
* Context: called from ibmveth_poll
*
+ * The ring advances even on error, so poll does not return to a bad
+ * slot before the scheduled reset can run.
+ *
* Return:
* * %0 - success
* * other - non-zero return from ibmveth_remove_buffer_from_pool
@@ -540,15 +581,9 @@ static int ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter,
cor = adapter->rx_queue.queue_addr[adapter->rx_queue.index].correlator;
rc = ibmveth_remove_buffer_from_pool(adapter, cor, reuse);
- if (unlikely(rc))
- return rc;
-
- if (++adapter->rx_queue.index == adapter->rx_queue.num_slots) {
- adapter->rx_queue.index = 0;
- adapter->rx_queue.toggle = !adapter->rx_queue.toggle;
- }
+ ibmveth_rxq_advance(adapter);
- return 0;
+ return rc;
}
static void ibmveth_free_tx_ltb(struct ibmveth_adapter *adapter, int idx)
@@ -623,8 +658,6 @@ static int ibmveth_open(struct net_device *netdev)
netdev_dbg(netdev, "open starting\n");
- napi_enable(&adapter->napi);
-
for(i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++)
rxq_entries += adapter->rx_buff_pool[i].size;
@@ -712,10 +745,18 @@ static int ibmveth_open(struct net_device *netdev)
}
}
+ /* NAPI can run as soon as it is enabled, from netpoll during the
+ * direct close()/open() pairs or from a direct ibmveth_interrupt()
+ * call, so enable it only once everything ibmveth_poll() touches
+ * exists.
+ */
+ napi_enable(&adapter->napi);
+
netdev_dbg(netdev, "registering irq 0x%x\n", netdev->irq);
rc = request_irq(netdev->irq, ibmveth_interrupt, 0, netdev->name,
netdev);
if (rc != 0) {
+ napi_disable(&adapter->napi);
netdev_err(netdev, "unable to request irq 0x%x, rc %d\n",
netdev->irq, rc);
do {
@@ -732,6 +773,7 @@ static int ibmveth_open(struct net_device *netdev)
netif_tx_start_all_queues(netdev);
+ adapter->opened = true;
netdev_dbg(netdev, "open complete\n");
return 0;
@@ -763,7 +805,6 @@ static int ibmveth_open(struct net_device *netdev)
out_free_buffer_list:
free_page((unsigned long)adapter->buffer_list_addr);
out:
- napi_disable(&adapter->napi);
return rc;
}
@@ -774,11 +815,19 @@ static int ibmveth_close(struct net_device *netdev)
long lpar_rc;
int i;
+ /* change_mtu, pool sysfs, set_csum and set_tso call close() and
+ * open() directly. If that open() fails, IFF_UP stays set and
+ * NAPI is disabled; a second close() would hang in napi_disable().
+ */
+ if (!adapter->opened)
+ return 0;
+ adapter->opened = false;
+
netdev_dbg(netdev, "close starting\n");
napi_disable(&adapter->napi);
- netif_tx_stop_all_queues(netdev);
+ netif_tx_disable(netdev);
h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE);
@@ -825,10 +874,10 @@ static int ibmveth_close(struct net_device *netdev)
*
* @w: pointer to work_struct embedded in adapter structure
*
- * Context: This routine acquires rtnl_mutex and disables its NAPI through
- * ibmveth_close. It can't be called directly in a context that has
- * already acquired rtnl_mutex or disabled its NAPI, or directly from
- * a poll routine.
+ * Context: This routine acquires rtnl_mutex and, if the device is open,
+ * disables its NAPI through ibmveth_close. It can't be called
+ * directly in a context that has already acquired rtnl_mutex or
+ * disabled its NAPI, or directly from a poll routine.
*
* Return: void
*/
@@ -1120,12 +1169,13 @@ static int ibmveth_set_channels(struct net_device *netdev,
struct ibmveth_adapter *adapter = netdev_priv(netdev);
unsigned int old = netdev->real_num_tx_queues,
goal = channels->tx_count;
- int rc, i;
+ int rc, i, alloc_rc = 0;
- /* If ndo_open has not been called yet then don't allocate, just set
- * desired netdev_queue's and return
+ /* If the device is not open (including a failed close/open with
+ * IFF_UP still set) then don't allocate, just set desired
+ * netdev_queue's and return
*/
- if (!(netdev->flags & IFF_UP))
+ if (!adapter->opened)
return netif_set_real_num_tx_queues(netdev, goal);
/* We have IBMVETH_MAX_QUEUES netdev_queue's allocated
@@ -1145,6 +1195,7 @@ static int ibmveth_set_channels(struct net_device *netdev,
/* if something goes wrong, free everything we just allocated */
netdev_err(netdev, "Failed to allocate more tx queues, returning to %d queues\n",
old);
+ alloc_rc = rc;
goal = old;
old = i;
break;
@@ -1155,6 +1206,8 @@ static int ibmveth_set_channels(struct net_device *netdev,
old);
goal = old;
old = i;
+ } else if (alloc_rc) {
+ rc = alloc_rc;
}
/* Free any that are no longer needed */
for (i = old; i > goal; i--) {
@@ -1453,6 +1506,7 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)
int frames_processed = 0;
unsigned long lpar_rc;
u16 mss = 0;
+ int rc;
restart_poll:
while (frames_processed < budget) {
@@ -1475,8 +1529,11 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)
__sum16 iph_check = 0;
skb = ibmveth_rxq_get_buffer(adapter);
- if (unlikely(!skb))
+ if (unlikely(!skb)) {
+ ibmveth_rxq_advance(adapter);
+ netdev->stats.rx_dropped++;
break;
+ }
/* if the large packet bit is set in the rx queue
* descriptor, the mss will be written by PHYP eight
@@ -1500,12 +1557,19 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)
if (rx_flush)
ibmveth_flush_buffer(skb->data,
length + offset);
- if (unlikely(ibmveth_rxq_harvest_buffer(adapter, true)))
+ rc = ibmveth_rxq_harvest_buffer(adapter, true);
+ if (unlikely(rc)) {
+ dev_kfree_skb_any(new_skb);
+ netdev->stats.rx_dropped++;
break;
+ }
skb = new_skb;
} else {
- if (unlikely(ibmveth_rxq_harvest_buffer(adapter, false)))
+ rc = ibmveth_rxq_harvest_buffer(adapter, false);
+ if (unlikely(rc)) {
+ netdev->stats.rx_dropped++;
break;
+ }
skb_reserve(skb, offset);
}
@@ -1680,14 +1744,6 @@ static int ibmveth_change_mtu(struct net_device *dev, int new_mtu)
return -EINVAL;
}
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void ibmveth_poll_controller(struct net_device *dev)
-{
- ibmveth_replenish_task(netdev_priv(dev));
- ibmveth_interrupt(dev->irq, dev);
-}
-#endif
-
/**
* ibmveth_get_desired_dma - Calculate IO memory desired by the driver
*
@@ -1789,9 +1845,6 @@ static const struct net_device_ops ibmveth_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = ibmveth_set_mac_addr,
.ndo_features_check = ibmveth_features_check,
-#ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = ibmveth_poll_controller,
-#endif
};
static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
@@ -1915,8 +1968,7 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
if (rc) {
netdev_dbg(netdev, "failed to set number of tx queues rc=%d\n",
rc);
- free_netdev(netdev);
- return rc;
+ goto err_put_pools;
}
adapter->tx_ltb_size = PAGE_ALIGN(IBMVETH_MAX_TX_BUF_SIZE);
for (i = 0; i < IBMVETH_MAX_QUEUES; i++)
@@ -1931,13 +1983,18 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
if (rc) {
netdev_dbg(netdev, "failed to register netdev rc=%d\n", rc);
- free_netdev(netdev);
- return rc;
+ goto err_put_pools;
}
netdev_dbg(netdev, "registered\n");
return 0;
+
+err_put_pools:
+ for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++)
+ kobject_put(&adapter->rx_buff_pool[i].kobj);
+ free_netdev(netdev);
+ return rc;
}
static void ibmveth_remove(struct vio_dev *dev)
@@ -1946,7 +2003,7 @@ static void ibmveth_remove(struct vio_dev *dev)
struct ibmveth_adapter *adapter = netdev_priv(netdev);
int i;
- cancel_work_sync(&adapter->work);
+ disable_work_sync(&adapter->work);
for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++)
kobject_put(&adapter->rx_buff_pool[i].kobj);
@@ -2196,8 +2253,7 @@ static void ibmveth_reset_kunit(struct work_struct *w)
* @test: pointer to kunit structure
*
* Tests the error returns from ibmveth_remove_buffer_from_pool.
- * ibmveth_remove_buffer_from_pool also calls WARN_ON, so dmesg should be
- * checked to see that these warnings happened.
+ * Each error also logs a ratelimited netdev_err.
*
* Return: void
*/
@@ -2206,6 +2262,7 @@ static void ibmveth_remove_buffer_from_pool_test(struct kunit *test)
struct ibmveth_adapter *adapter = kunit_kzalloc(test, sizeof(*adapter), GFP_KERNEL);
struct ibmveth_buff_pool *pool;
u64 correlator;
+ int ret;
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adapter);
@@ -2229,6 +2286,13 @@ static void ibmveth_remove_buffer_from_pool_test(struct kunit *test)
KUNIT_EXPECT_EQ(test, -EINVAL, ibmveth_remove_buffer_from_pool(adapter, correlator, false));
KUNIT_EXPECT_EQ(test, -EINVAL, ibmveth_remove_buffer_from_pool(adapter, correlator, true));
+ /* Pool 2 is in range but has no skbuff array, like an inactive pool. */
+ correlator = ((u64)2 << 32) | 0;
+ ret = ibmveth_remove_buffer_from_pool(adapter, correlator, false);
+ KUNIT_EXPECT_EQ(test, -EINVAL, ret);
+ ret = ibmveth_remove_buffer_from_pool(adapter, correlator, true);
+ KUNIT_EXPECT_EQ(test, -EINVAL, ret);
+
correlator = (u64)0 | 0;
pool->skbuff[0] = NULL;
KUNIT_EXPECT_EQ(test, -EFAULT, ibmveth_remove_buffer_from_pool(adapter, correlator, false));
@@ -2241,9 +2305,8 @@ static void ibmveth_remove_buffer_from_pool_test(struct kunit *test)
* ibmveth_rxq_get_buffer_test - unit test for ibmveth_rxq_get_buffer
* @test: pointer to kunit structure
*
- * Tests ibmveth_rxq_get_buffer. ibmveth_rxq_get_buffer also calls WARN_ON for
- * the NULL returns, so dmesg should be checked to see that these warnings
- * happened.
+ * Tests ibmveth_rxq_get_buffer. Each NULL return also logs a ratelimited
+ * netdev_err.
*
* Return: void
*/
@@ -2280,6 +2343,10 @@ static void ibmveth_rxq_get_buffer_test(struct kunit *test)
adapter->rx_queue.queue_addr[0].correlator = (u64)0 << 32 | adapter->rx_buff_pool[0].size;
KUNIT_EXPECT_PTR_EQ(test, NULL, ibmveth_rxq_get_buffer(adapter));
+ /* Pool 2 is in range but has no skbuff array, like an inactive pool. */
+ adapter->rx_queue.queue_addr[0].correlator = (u64)2 << 32 | 0;
+ KUNIT_EXPECT_PTR_EQ(test, NULL, ibmveth_rxq_get_buffer(adapter));
+
pool->skbuff[0] = skb;
adapter->rx_queue.queue_addr[0].correlator = (u64)0 << 32 | 0;
KUNIT_EXPECT_PTR_EQ(test, skb, ibmveth_rxq_get_buffer(adapter));
@@ -2287,9 +2354,68 @@ static void ibmveth_rxq_get_buffer_test(struct kunit *test)
flush_work(&adapter->work);
}
+/**
+ * ibmveth_rxq_harvest_buffer_test - unit test for ibmveth_rxq_harvest_buffer
+ * @test: pointer to kunit structure
+ *
+ * A bad correlator must still advance the RX ring, wrapping and flipping
+ * the toggle at the end. This covers the harvest path; the advance after
+ * ibmveth_rxq_get_buffer() fails in ibmveth_poll() is not tested here.
+ *
+ * Return: void
+ */
+static void ibmveth_rxq_harvest_buffer_test(struct kunit *test)
+{
+ struct ibmveth_adapter *adapter;
+ struct ibmveth_buff_pool *pool;
+ int ret;
+
+ adapter = kunit_kzalloc(test, sizeof(*adapter), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adapter);
+
+ INIT_WORK(&adapter->work, ibmveth_reset_kunit);
+
+ adapter->rx_queue.num_slots = 2;
+ adapter->rx_queue.index = 0;
+ adapter->rx_queue.toggle = 1;
+ adapter->rx_queue.queue_addr =
+ kunit_kcalloc(test, 2, sizeof(struct ibmveth_rx_q_entry),
+ GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adapter->rx_queue.queue_addr);
+
+ /* Set sane values for buffer pools */
+ for (int i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++)
+ ibmveth_init_buffer_pool(&adapter->rx_buff_pool[i], i,
+ pool_count[i], pool_size[i],
+ pool_active[i]);
+
+ pool = &adapter->rx_buff_pool[0];
+ pool->skbuff = kunit_kcalloc(test, pool->size, sizeof(void *),
+ GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pool->skbuff);
+
+ /* Slot 0: pool out of range. Slot 1: valid, but no skb. */
+ adapter->rx_queue.queue_addr[0].correlator =
+ (u64)IBMVETH_NUM_BUFF_POOLS << 32 | 0;
+ adapter->rx_queue.queue_addr[1].correlator = (u64)0 << 32 | 0;
+
+ ret = ibmveth_rxq_harvest_buffer(adapter, true);
+ KUNIT_EXPECT_EQ(test, -EINVAL, ret);
+ KUNIT_EXPECT_EQ(test, 1ULL, adapter->rx_queue.index);
+ KUNIT_EXPECT_EQ(test, 1ULL, adapter->rx_queue.toggle);
+
+ ret = ibmveth_rxq_harvest_buffer(adapter, true);
+ KUNIT_EXPECT_EQ(test, -EFAULT, ret);
+ KUNIT_EXPECT_EQ(test, 0ULL, adapter->rx_queue.index);
+ KUNIT_EXPECT_EQ(test, 0ULL, adapter->rx_queue.toggle);
+
+ flush_work(&adapter->work);
+}
+
static struct kunit_case ibmveth_test_cases[] = {
KUNIT_CASE(ibmveth_remove_buffer_from_pool_test),
KUNIT_CASE(ibmveth_rxq_get_buffer_test),
+ KUNIT_CASE(ibmveth_rxq_harvest_buffer_test),
{}
};
diff --git a/drivers/net/ethernet/ibm/ibmveth.h b/drivers/net/ethernet/ibm/ibmveth.h
index d87713668ed30..3f2240823f6a3 100644
--- a/drivers/net/ethernet/ibm/ibmveth.h
+++ b/drivers/net/ethernet/ibm/ibmveth.h
@@ -172,6 +172,8 @@ struct ibmveth_adapter {
int rx_csum;
int large_send;
bool is_active_trunk;
+ /* Set by a successful ibmveth_open(), cleared by ibmveth_close(). */
+ bool opened;
unsigned int rx_buffers_per_hcall;
u64 fw_ipv6_csum_support;
|
| 3/2 | 2026/10/03 11:04 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 9381 output: 33 thoughts: 97 Thoughts: **Analyzing a Patch for Syzkaller Fuzzing Potential** Okay, let's dive into this patch and figure out if it's a good candidate for some syzkaller love. First, the target is amd64, which is good. That's a common architecture and syzkaller has strong support there. Now, let's see what's changed. The diff points to `drivers/net/ethernet/ibm/ibmveth.c` and `drivers/net/ethernet/ibm/ibmveth.h`. Alright, I'm already thinking networking, which is a classic area to find interesting bugs. What *is* `ibmveth`, though? I'll quickly check the Kconfig to understand the scope and dependencies of this subsystem. Knowing if it's widely used, or more niche, will help me assess the potential impact if we *do* find something exploitable. This is definitely a good starting point for a deeper dive. |
| 4/2 | 2026/10/03 11:04 | tool | grepper |
0mArgs:{
"Expression": "config IBMVETH",
"PathPrefix": "drivers/net/ethernet/ibm/"
}Results: {
"Output": "drivers/net/ethernet/ibm/Kconfig=18=if NET_VENDOR_IBM\ndrivers/net/ethernet/ibm/Kconfig-19-\ndrivers/net/ethernet/ibm/Kconfig:20:config IBMVETH\ndrivers/net/ethernet/ibm/Kconfig-21-\ttristate \"IBM LAN Virtual Ethernet support\"\n--\ndrivers/net/ethernet/ibm/Kconfig-29-\ndrivers/net/ethernet/ibm/Kconfig:30:config IBMVETH_KUNIT_TEST\ndrivers/net/ethernet/ibm/Kconfig-31-\tbool \"KUnit test for IBM LAN Virtual Ethernet support\" if !KUNIT_ALL_TESTS\n"
} |
| 5/2 | 2026/10/03 11:04 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 9896 output: 38 thoughts: 26 Thoughts: Here's a summary of my thought process, as requested: **Kconfig Inspection for IBM Ethernet Drivers** Okay, let's dive into this. My initial thought is to zero in on the `drivers/net/ethernet/ibm/Kconfig` file. I'm specifically interested in what's happening around line 20. This is likely where key configurations related to the IBM Ethernet driver are defined – things like feature selections, module dependencies, or perhaps platform-specific settings. I anticipate finding conditionals or configuration variables that dictate how the driver is built and which components are included based on the user's kernel configuration. By examining this section of the Kconfig file, I should gain insight into how the IBM Ethernet driver integrates with the broader kernel networking stack and understand the options available to a system administrator who wants to include, exclude, or customize this specific driver within their kernel build. I will look for any clues. |
| 6/2 | 2026/10/03 11:04 | tool | read-file |
0mArgs:{
"File": "drivers/net/ethernet/ibm/Kconfig",
"FirstLine": 15,
"LineCount": 35
}Results: {
"Contents": " 15:\t\t the questions about IBM devices. If you say Y, you will be asked for\n 16:\t\t your specific card in the following questions.\n 17:\t\n 18:\tif NET_VENDOR_IBM\n 19:\t\n 20:\tconfig IBMVETH\n 21:\t\ttristate \"IBM LAN Virtual Ethernet support\"\n 22:\t\tdepends on PPC_PSERIES\n 23:\t\thelp\n 24:\t\t This driver supports virtual ethernet adapters on newer IBM iSeries\n 25:\t\t and pSeries systems.\n 26:\t\n 27:\t\t To compile this driver as a module, choose M here. The module will\n 28:\t\t be called ibmveth.\n 29:\t\n 30:\tconfig IBMVETH_KUNIT_TEST\n 31:\t\tbool \"KUnit test for IBM LAN Virtual Ethernet support\" if !KUNIT_ALL_TESTS\n 32:\t\tdepends on KUNIT\n 33:\t\tdepends on KUNIT=y \u0026\u0026 IBMVETH=y\n 34:\t\tdefault KUNIT_ALL_TESTS\n 35:\t\thelp\n 36:\t\t This builds unit tests for the IBM LAN Virtual Ethernet driver.\n 37:\t\n 38:\t\t For more information on KUnit and unit tests in general, please refer\n 39:\t\t to the KUnit documentation in Documentation/dev-tools/kunit/.\n 40:\t\n 41:\t\t If unsure, say N.\n 42:\t\n 43:\tsource \"drivers/net/ethernet/ibm/emac/Kconfig\"\n 44:\t\n 45:\tconfig IBMVNIC\n 46:\t\ttristate \"IBM Virtual NIC support\"\n 47:\t\tdepends on PPC_PSERIES\n 48:\t\thelp\n 49:\t\t This driver supports Virtual NIC adapters on IBM i and IBM System p\n"
} |
| 7/2 | 2026/10/03 11:04 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 10628 output: 20 thoughts: 61 Thoughts: **Investigating a Potential Configuration Issue** Okay, here's what's running through my head. I've spotted something interesting on line 22 – that condition, `depends on PPC_PSERIES`, is jumping out at me. I'm focusing in because I see the target architecture is `amd64`. Now, my gut feeling – and my experience with these sorts of build configurations – is raising a red flag. Can `PPC_PSERIES` even *be* enabled when the target is `amd64`? It seems highly unlikely, and if it is enabled, there's going to be a problem. This smells like a potential configuration error or a very obscure platform-specific conditional. Time to get to the bottom of this. My next step? I need to track down where `PPC_PSERIES` is defined. Knowing the definition will give me a clear understanding of its implications in this context. |
| 8/2 | 2026/10/03 11:04 | tool | grepper |
0mArgs:{
"Expression": "config PPC_PSERIES"
}Results: {
"Output": "arch/powerpc/platforms/pseries/Kconfig-1-# SPDX-License-Identifier: GPL-2.0\narch/powerpc/platforms/pseries/Kconfig:2:config PPC_PSERIES\narch/powerpc/platforms/pseries/Kconfig-3-\tdepends on PPC64 \u0026\u0026 PPC_BOOK3S\n--\narch/powerpc/platforms/pseries/Kconfig=92=config LPARCFG\n--\narch/powerpc/platforms/pseries/Kconfig-98-\narch/powerpc/platforms/pseries/Kconfig:99:config PPC_PSERIES_DEBUG\narch/powerpc/platforms/pseries/Kconfig-100-\tdepends on PPC_PSERIES \u0026\u0026 PPC_EARLY_DEBUG\n"
} |
| 9/2 | 2026/10/03 11:04 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 11097 output: 99 thoughts: 995 Thoughts: **Analysis of Unfuzzable Code: IBMVETH on AMD64** Okay, so the initial dependency chain is clear: `PPC_PSERIES` is required for `ibmveth`, and that hinges on `PPC64 && PPC_BOOK3S`, which screams "PowerPC only." This rules out direct execution on our `amd64` target. Now, let's consider KUnit testing. Can we build `IBMVETH` or `IBMVETH_KUNIT_TEST` on UML or amd64 as a workaround? The config options confirm that `IBMVETH` *does* depend on `PPC_PSERIES`. Even with `KUNIT` enabled and `IBMVETH` enabled, we're still stuck because the base driver itself has that PowerPC dependency. Alright, let's drill down into the code itself. Checking `drivers/net/ethernet/ibm/Kconfig`, line 22 confirms the dependency on `PPC_PSERIES` and there's no escape hatch via `COMPILE_TEST`. This dependency is absolute. I need to know how the driver works to be sure. Diving into `ibmveth.c`, the probe function, `ibmveth_probe`, is critical. It takes a `struct vio_dev`, which is *the* PowerPC Virtual I/O bus abstraction. `vio_bus_type` is explicitly PPC-specific, designed for the IBM pSeries/iSeries LPAR virtual bus. Bingo! The core logic revolves around the PowerPC hypervisor's virtual I/O. Now, let's revisit the triage criteria, the negative criteria. It's time to confirm that the driver can't possibly execute on our `amd64` target. The criteria clearly states that we can return `WorthFuzzing=false` if the code falls into several categories. This case perfectly matches the negative criteria: "Unreachable execution paths: Code paths exclusive to architectures other than the target architecture." Our target architecture is, explicitly, `amd64`. The driver `ibmveth` hinges on `PPC_PSERIES`, which in turn hinges on `PPC64` and `PPC_BOOK3S`. That means this driver is *exclusively* for the PowerPC architecture, specifically on IBM pSeries LPARs under the PHYP hypervisor. Think `h_vio_signal` and related hypervisor calls. There's no way it's going to compile, let alone run, on `amd64`. Just to be absolutely certain, I'll confirm only the expected driver files were touched, checking the diff. Yes, it's just `ibmveth.c` and `ibmveth.h`. Nothing outside of the driver. Again, `CONFIG_IBMVETH` depends on `PPC_PSERIES`, which is PowerPC only. No other architecture can even enable that. The modified code is definitely exclusive to a different architecture, specifically PowerPC. Double-checking against the negative criteria. The modified code falls *exactly* into "Code paths exclusive to architectures other than the target architecture." Therefore, I need to create the `set-results` parameters to accurately convey this: - `WorthFuzzing`: `false` - `Reasoning`: The patch modifies the `ibmveth` driver (`drivers/net/ethernet/ibm/ibmveth.[ch]`), which depends on `CONFIG_PPC_PSERIES` (PowerPC architecture). Since the target architecture is `amd64`, this driver cannot be compiled or executed, making the modified code structurally unreachable. - `FocusSymbols`: `[]` - `EnableConfigs`: `[]` I'm confident in this assessment. It's time to invoke that `set-results` tool call. |
| 10/2 | 2026/10/03 11:04 | tool | set-results |
0mArgs:{
"EnableConfigs": [],
"FocusSymbols": [],
"Reasoning": "The patch modifies the ibmveth driver (drivers/net/ethernet/ibm/ibmveth.[ch]), which depends on CONFIG_PPC_PSERIES and is specific to the PowerPC pSeries architecture. Because the target architecture is amd64, this code cannot be compiled or executed in the fuzzing environment.",
"WorthFuzzing": false
}Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch modifies the ibmveth driver (drivers/net/ethernet/ibm/ibmveth.[ch]), which depends on CONFIG_PPC_PSERIES and is specific to the PowerPC pSeries architecture. Because the target architecture is amd64, this code cannot be compiled or executed in the fuzzing environment.",
"WorthFuzzing": false
} |
| 11/1 | 2026/10/03 11:04 | action | If |
0mArgs:{
"WorthFuzzing": false
}Results: null |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|