Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH net-next v2] net: libwx: disable TX VLAN offload for packets with >2 VLAN tags
From: Jacob Keller @ 2026-07-15  0:26 UTC (permalink / raw)
  To: Jiawen Wu, netdev
  Cc: Duanqiang Wen, Mengyuan Lou, Andrew Lunn, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
	Kees Cook, Przemek Kitszel
In-Reply-To: <069DF89AA8029189+20260713060441.276612-1-jiawenwu@trustnetic.com>

On 7/12/2026 11:04 PM, Jiawen Wu wrote:
> The current hardware does not support TX VLAN offload for packets with
> three or more VLAN tags. When such packets are transmitted with hardware
> VLAN offload enabled, the hardware may malfunction or produce corrupted
> frames.
> 
> Add a check in wx_features_check() to parse the VLAN depth of the
> skb. If more than two VLAN tags are detected (including both the
> hardware tag and in-band tags), strip NETIF_F_HW_VLAN_CTAG_TX and
> NETIF_F_HW_VLAN_STAG_TX from the feature set. This forces the
> kernel networking stack to handle VLAN insertion in software for
> these specific packets, ensuring correct transmission.
> 
> Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>


Is there a reason this was targeted at net-next instead of as a bug fix
to net with a Fixes tag to the commit which first introduced VLAN tagging?

Thanks,
Jake

> ---
> v2:
> - Remove redundant 'parse_depth'.
> - Optimize the loop.
> 
> v1: https://lore.kernel.org/all/C1BF77C0E073A40C+20260710071831.210196-1-jiawenwu@trustnetic.com
> ---
>  drivers/net/ethernet/wangxun/libwx/wx_lib.c | 24 +++++++++++++++++++++
>  1 file changed, 24 insertions(+)
> 
> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
> index 814d88d2aee4..34542b3dc884 100644
> --- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c
> +++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
> @@ -3228,6 +3228,30 @@ netdev_features_t wx_features_check(struct sk_buff *skb,
>  				    netdev_features_t features)
>  {
>  	struct wx *wx = netdev_priv(netdev);
> +	__be16 type = skb->protocol;
> +	u16 vlan_depth = ETH_HLEN;
> +	u32 vlan_num = 0;
> +
> +	if (skb_vlan_tag_present(skb))
> +		vlan_num++;
> +
> +	while (eth_type_vlan(type)) {
> +		struct vlan_hdr vhdr, *vh;
> +
> +		vh = skb_header_pointer(skb, vlan_depth, sizeof(vhdr), &vhdr);
> +		if (unlikely(!vh))
> +			break;
> +
> +		type = vh->h_vlan_encapsulated_proto;
> +		vlan_depth += VLAN_HLEN;
> +		vlan_num++;
> +
> +		if (vlan_num > 2) {
> +			features &= ~(NETIF_F_HW_VLAN_CTAG_TX |
> +				      NETIF_F_HW_VLAN_STAG_TX);
> +			break;
> +		}
> +	}
>  
>  	if (!skb->encapsulation)
>  		return features;


^ permalink raw reply

* Re: [PATCH mlx5-next 0/2] mlx5-next updates 2026-07-13
From: Jacob Keller @ 2026-07-15  0:29 UTC (permalink / raw)
  To: Tariq Toukan, Leon Romanovsky, linux-rdma, Mark Bloch, netdev,
	Saeed Mahameed
  Cc: Alexei Lazar, Alex Vesker, Andrew Lunn, Cosmin Ratiu,
	David S. Miller, Dragos Tatulea, Eric Dumazet, Feng Liu,
	Jakub Kicinski, Kees Cook, linux-kernel, Paolo Abeni,
	Parav Pandit, Shay Drory, Simon Horman, Yevgeny Kliteynik
In-Reply-To: <20260713084320.1015240-1-tariqt@nvidia.com>

On 7/13/2026 1:43 AM, Tariq Toukan wrote:
> Hi,
> 
> This series contains mlx5 shared updates.
> 
> Regards,
> Tariq
> 
> Cosmin Ratiu (1):
>   net/mlx5: ifc: Add PSP related fields
> 
> Shay Drory (1):
>   net/mlx5: Drop redundant esw_cap, reuse e_switch_cap
> 
>  .../net/ethernet/mellanox/mlx5/core/fs_core.h | 12 +-----
>  .../mellanox/mlx5/core/steering/hws/cmd.c     |  6 +--
>  include/linux/mlx5/device.h                   |  1 +
>  include/linux/mlx5/mlx5_ifc.h                 | 38 ++++++++++---------
>  4 files changed, 25 insertions(+), 32 deletions(-)
> 
> 
> base-commit: ddbddbf8aee54bee038149187270c93a45478473

For the series:
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>

^ permalink raw reply

* Re: [PATCH net] net: txgbe: fix FDIR filter leak on remove
From: Jacob Keller @ 2026-07-15  0:30 UTC (permalink / raw)
  To: Chenguang Zhao, jiawenwu, mengyuanlou, andrew+netdev, davem,
	edumazet, kuba, pabeni
  Cc: netdev, Chenguang Zhao
In-Reply-To: <20260713091911.1614795-1-chenguang.zhao@linux.dev>

On 7/13/2026 2:19 AM, Chenguang Zhao wrote:
> From: Chenguang Zhao <zhaochenguang@kylinos.cn>
> 
> Perfect FDIR filters can be added while the interface is down and are
> kept on the software list for later restore. unregister_netdev() only
> calls ndo_stop when the device is up, so txgbe_fdir_filter_exit() in
> txgbe_close() is skipped in that case and the filters are leaked on
> driver remove. Free the filter list from txgbe_remove() as well.
> 
> Fixes: 4bdb441105dc ("net: txgbe: support Flow Director perfect filters")
> Signed-off-by: Chenguang Zhao <zhaochenguang@kylinos.cn>
> ---
> Reproduction:
>  1. Load the driver (interface remains down after probe).
>  2. Enable ntuple filters: ethtool -K <dev> ntuple on
>  3. Add a perfect FDIR rule while the interface is down:
>    ethtool -N <dev> flow-type ...
>  4. Keep the interface down (do not bring it up).
>  5. Unload the driver (rmmod / PCI unbind).
>    unregister_netdev() skips ndo_stop because the device is not IFF_UP,
>    and without freeing the software filter list in remove, each rule
>    leaks sizeof(struct txgbe_fdir_filter).
> 

Appreciate the reproduction steps here. Helps detail the way the leak
sneaks in.

Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>

>  drivers/net/ethernet/wangxun/txgbe/txgbe_main.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
> index 20c5a295c6c2..c277863baf67 100644
> --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
> +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
> @@ -945,6 +945,7 @@ static void txgbe_remove(struct pci_dev *pdev)
>  	netdev = wx->netdev;
>  	wx_disable_sriov(wx);
>  	unregister_netdev(netdev);
> +	txgbe_fdir_filter_exit(wx);
>  
>  	timer_shutdown_sync(&wx->service_timer);
>  	cancel_work_sync(&wx->service_task);


^ permalink raw reply

* Re: [PATCH net] net: txgbe: fix heap overflow when reading module EEPROM
From: Jacob Keller @ 2026-07-15  0:31 UTC (permalink / raw)
  To: Chenguang Zhao, jiawenwu, mengyuanlou, andrew+netdev, davem,
	edumazet, kuba, pabeni
  Cc: maxime.chevallier, netdev, Chenguang Zhao
In-Reply-To: <20260713085111.1481884-1-chenguang.zhao@linux.dev>

On 7/13/2026 1:51 AM, Chenguang Zhao wrote:
> From: Chenguang Zhao <zhaochenguang@kylinos.cn>
> 
> txgbe_read_eeprom_hostif() always copies round_up(length, 4) bytes
> into the caller buffer, which ethtool allocates with exactly 'length'
> bytes. A non-4-aligned length therefore causes an out-of-bounds write.
> Copy only the remaining bytes on the final dword instead.
> 
> Signed-off-by: Chenguang Zhao <zhaochenguang@kylinos.cn>
> ---

Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>

>  drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c
> index affea1a364ef..26d0cfc58ee2 100644
> --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c
> +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c
> @@ -96,11 +96,13 @@ int txgbe_read_eeprom_hostif(struct wx *wx,
>  	dword_len = round_up(length, 4) >> 2;
>  
>  	for (i = 0; i < dword_len; i++) {
> +		u32 copy_len = min_t(u32, 4, length - i * 4);
> +
>  		value = rd32a(wx, WX_FW2SW_MBOX, i + offset);
>  		le32_to_cpus(&value);
>  
> -		memcpy(data, &value, 4);
> -		data += 4;
> +		memcpy(data, &value, copy_len);
> +		data += copy_len;
>  	}
>  
>  	return 0;


^ permalink raw reply

* Re: [PATCH] mctp: check register_netdevice_notifier() error in mctp_device_init()
From: Jeremy Kerr @ 2026-07-15  0:37 UTC (permalink / raw)
  To: Minhong He, netdev; +Cc: Matt Johnston
In-Reply-To: <20260713073918.419422-1-heminhong@kylinos.cn>

Hi,

> [PATCH] mctp: check register_netdevice_notifier() error in mctp_device_init()

Please include the target tree in the subject prefix. SInce this is for
the net tree, you want something like:

  [PATCH net] mctp: check ...

> mctp_device_init() handles errors from rtnl_af_register() and
> rtnl_register_many(), but ignores the return value of
> register_netdevice_notifier(). If notifier registration fails, init
> can still return success while the module is only partially initialized.
> 
> Check the notifier registration error and fail module init early.

The change itself looks good, thanks.

> Fixes: d51705614f66 ("mctp: Handle error of rtnl_register_module().")

... but no newline between the fixes and signed-off-by (and other tags).

Also, make sure you CC all the necessary maintainers; you're getting a
nipa CI failure due to that.

With those addressed:

Acked-by: Jeremy Kerr <jk@codeconstruct.com.au>

Cheers,


Jeremy

^ permalink raw reply

* Re: [PATCH v4 net-next 1/7] ptp: Add ioctls for PHC timestamps with quality attributes
From: Jacob Keller @ 2026-07-15  0:45 UTC (permalink / raw)
  To: Arthur Kiyanovski, David Miller, Jakub Kicinski, netdev
  Cc: Richard Cochran, Eric Dumazet, Paolo Abeni, David Woodhouse,
	Thomas Gleixner, Miroslav Lichvar, Andrew Lunn, Wen Gu, Xuan Zhuo,
	David Woodhouse, Yonatan Sarna, Zorik Machulsky,
	Alexander Matushevsky, Saeed Bshara, Matt Wilson, Anthony Liguori,
	Nafea Bshara, Evgeny Schmeilin, Netanel Belgazal, Ali Saidi,
	Benjamin Herrenschmidt, Noam Dagan, David Arinzon,
	Evgeny Ostrovsky, Ofir Tabachnik, Amit Bernstein, linux-kselftest,
	linux-doc, shuah, Jonathan Corbet, Shuah Khan, Simon Horman,
	vadim.fedorenko
In-Reply-To: <20260714020340.25014-2-akiyano@amazon.com>

On 7/13/2026 7:03 PM, Arthur Kiyanovski wrote:
> Introduce two new ioctls that extend existing PTP timestamp interfaces
> with clock quality information:
> 
> - PTP_SYS_OFFSET_EXTENDED_ATTRS: Extends PTP_SYS_OFFSET_EXTENDED
> - PTP_SYS_OFFSET_PRECISE_ATTRS: Extends PTP_SYS_OFFSET_PRECISE
> 
> These ioctls provide quality attributes alongside timestamps:
> 
> 1. error_bound: Maximum deviation from true time (nanoseconds), based
>    on device's internal clock state
> 2. clock_status: Synchronization state (unknown, initializing,
>    synchronized, free-running, unreliable)
> 3. timescale: Time reference (TAI, UTC, etc.)
> 4. counter_value: Raw system counter (e.g. TSC ticks) captured by the
>    timekeeping core alongside each system timestamp
> 5. counter_id: Identifies the counter source (e.g. TSC, ARM arch counter)
> 
> This supports three use cases:
> 
> 1. Managed PHC devices (e.g., ENA, vmclock) that maintain their own
>    synchronization and can report quality metrics directly to userspace
>    without requiring ptp4l
> 
> 2. Applications that need complete time quality information in a single
>    call, regardless of how the PHC is synchronized
> 
> 3. VMMs that need raw system counter values paired
>    with PTP timestamps for feed-forward clock calibration, avoiding the
>    feedback loop inherent in NTP-style synchronization
> 

I'm also wondering if this can expose device-known error bounds on
timestamps even for devices which are operated as synchronized by ptp4l..

> Timescale definitions use a Continuity/Discipline framework to describe
> timeline properties and steering behavior consistently across all
> entries.
> 
> This implementation is based on the original RFC and the UAPI design
> discussion linked below.
> 

Not a dig against this patch set, nor a request that you work to
implement anything else, but I am beginning to wonder if/when it would
make sense to transition from ioctl-based implementation to genetlink or
something. We did something similar for ethtool ioctls a few years ago.
I know the maintainer for PTP has some distaste for netlink and prefers
the simplicity of the ioctls.. but I think we're moving past where the
ioctls are "simple". Now that we have ynl tools, it has gotten easier to
implement properly. It makes extending the API much easier for the
future vs the array of ioctls we now carry for legacy implementations.

> 
> diff --git a/include/uapi/linux/ptp_clock.h b/include/uapi/linux/ptp_clock.h
> index 46d45f902486..88c2da6bc8c6 100644
> --- a/include/uapi/linux/ptp_clock.h
> +++ b/include/uapi/linux/ptp_clock.h
> @@ -79,6 +79,137 @@
>   */
>  #define PTP_PEROUT_V1_VALID_FLAGS	(0)
>  
> +/*
> + * Clock status values for struct ptp_clock_attrs.status
> + */
> +enum ptp_clock_status {
> +	/* Clock synchronization status cannot be reliably determined */
> +	PTP_CLOCK_STATUS_UNKNOWN      = 0,
> +
> +	/* Clock is acquiring synchronization */
> +	PTP_CLOCK_STATUS_INITIALIZING = 1,
> +
> +	/* Clock is synchronized and maintained accurately by the device */
> +	PTP_CLOCK_STATUS_SYNCED       = 2,
> +
> +	/* Clock is drifting but remains within acceptable error bounds */
> +	PTP_CLOCK_STATUS_HOLDOVER     = 3,
> +
> +	/* Clock is drifting without adjustments or synchronization */
> +	PTP_CLOCK_STATUS_FREE_RUNNING = 4,
> +
> +	/* Clock is unreliable, the error_bound value cannot be trusted */
> +	PTP_CLOCK_STATUS_UNRELIABLE   = 5
> +};

Do you have any thought on how ptp4l synchronizing the clock should
impact the clock status here? Is this intended purely for device/drivers
which have their own synchronization and not for ones which expose a
clock that is synchronized by userspace? Would it make sense to have a
mode that is something like "this clock has been modified by userspace"
after any call to the .adjtime or .adjfreq is made?

> +
> +/*
> + * Clock timescale values for struct ptp_clock_attrs.timescale.
> + *
> + * These definitions describe the mathematical properties and reference
> + * epochs of the timescale provided by the PHC.
> + *
> + * Discipline: Describes the frequency/phase steering behavior.
> + * Continuity: Describes whether the timeline is uninterrupted.
> + */
> +enum ptp_clock_timescale {
> +	/* Unknown or unspecified timescale */
> +	PTP_TIMESCALE_UNKNOWN = 0,
> +
> +	/********************* Absolute Atomic Timescales *********************
> +	 * These timescales are continuous, monotonic standards based on atomic
> +	 * physics. They do not experience phase jumps.
> +	 **********************************************************************/
> +
> +	/**
> +	 * International Atomic Time (TAI)
> +	 * Epoch: 1958-01-01 00:00:00.
> +	 * Continuity: Strictly monotonic and continuous; no leap seconds.
> +	 * Discipline: Primary atomic reference; no phase jumps.
> +	 */
> +	PTP_TIMESCALE_TAI = 1,
> +
> +	/**
> +	 * Terrestrial Time (TT)
> +	 * Epoch: 1958-01-01 00:00:00.
> +	 * Continuity: Strictly monotonic and continuous; no leap seconds.
> +	 * Discipline: Defined as TAI + 32.184s constant offset.
> +	 */
> +	PTP_TIMESCALE_TT = 2,
> +
> +	/**
> +	 * Global Positioning System (GPS) Time
> +	 * Epoch: 1980-01-06 00:00:00.
> +	 * Continuity: Strictly monotonic and continuous; no leap seconds.
> +	 * Discipline: Defined by the GPS constellation; fixed offset from TAI.
> +	 */
> +	PTP_TIMESCALE_GPS = 3,
> +
> +	/****************** UTC-Based Timescales (Civil Time) *****************
> +	 * These timescales are derived from TAI but adjusted to align with
> +	 * the Earth's rotation, primarily through leap seconds.
> +	 **********************************************************************/
> +
> +	/**
> +	 * Coordinated Universal Time (UTC) - Wall-clock (CLOCK_REALTIME)
> +	 * Epoch: 1970-01-01 00:00:00 (Unix epoch).
> +	 * Continuity: Discontinuous; subject to 1-second leap second
> +	 *             phase jumps.
> +	 * Discipline: Frequency steered; incorporates leap second corrections.
> +	 *
> +	 * Note: Leap-smeared UTC MUST NOT be advertised as PTP_TIMESCALE_UTC.
> +	 * Smear algorithms are not standardized and the resulting timescale
> +	 * is ambiguous. Implementations using smeared UTC MUST advertise
> +	 * PTP_TIMESCALE_UNKNOWN or PTP_TIMESCALE_PROPRIETARY instead.
> +	 */
> +	PTP_TIMESCALE_UTC = 4,
> +
> +	/**
> +	 * POSIX Time (Unix Time)
> +	 * Epoch: 1970-01-01 00:00:00.
> +	 * Continuity: Discontinuous; leap seconds handled by
> +	 *             repeating/skipping values.
> +	 * Discipline: Follows UTC frequency steering and phase jumps.
> +	 */
> +	PTP_TIMESCALE_POSIX = 5,
> +
> +	/****************** System-Relative Monotonic Clocks ******************
> +	 * These timescales are relative to a system event (like boot)
> +	 * and are not synchronized to an external atomic standard.
> +	 **********************************************************************/
> +
> +	/**
> +	 * Monotonic System Clock (CLOCK_MONOTONIC)
> +	 * Epoch: Arbitrary (System boot time).
> +	 * Continuity: Strictly monotonic; no leap seconds.
> +	 * Discipline: Frequency steered to match system reference;
> +	 *             does not advance during suspend.
> +	 */
> +	PTP_TIMESCALE_MONOTONIC = 6,
> +
> +	/**
> +	 * Raw Monotonic System Clock (CLOCK_MONOTONIC_RAW)
> +	 * Epoch: Arbitrary (System boot time).
> +	 * Continuity: Strictly monotonic; no leap seconds.
> +	 * Discipline: Raw hardware oscillator; no frequency steering
> +	 *             or discipline.
> +	 */
> +	PTP_TIMESCALE_MONOTONIC_RAW = 7,
> +
> +	/**
> +	 * Boot Time System Clock (CLOCK_BOOTTIME)
> +	 * Epoch: Arbitrary (System boot time).
> +	 * Continuity: Strictly monotonic and continuous; no leap seconds.
> +	 * Discipline: Frequency steered to match system reference;
> +	 *             advances during suspend.
> +	 */
> +	PTP_TIMESCALE_BOOTTIME = 8,
> +
> +	/********************** Vendor-Specific Timescale *********************/
> +
> +	/* A proprietary or vendor-specific timescale with custom rules. */
> +	PTP_TIMESCALE_PROPRIETARY = 9,
> +};

I appreciate the detailed explanations here as it helps to disambiguate
the modes.

> @@ -106,7 +350,11 @@ struct ptp_clock_caps {
>  	/* Whether the clock supports adjust phase */
>  	int adjust_phase;
>  	int max_phase_adj; /* Maximum phase adjustment in nanoseconds. */
> -	int rsv[11];       /* Reserved for future use. */
> +	/* Whether the clock supports extended timestamps with attributes */
> +	int extended_attrs;
> +	/* Whether the clock supports precise cross-timestamps with attributes */
> +	int precise_attrs;
> +	int rsv[9];       /* Reserved for future use. */

I do kind of wish we had opted for bit flags here given the number of
ints being used as booleans.. :( A lot of wasted reserved space.

>  };
>  
>  struct ptp_extts_request {
> @@ -252,6 +500,10 @@ struct ptp_pin_desc {
>  	_IOWR(PTP_CLK_MAGIC, 21, struct ptp_sys_offset_precise)
>  #define PTP_SYS_OFFSET_EXTENDED_CYCLES \
>  	_IOWR(PTP_CLK_MAGIC, 22, struct ptp_sys_offset_extended)
> +#define PTP_SYS_OFFSET_PRECISE_ATTRS \
> +	_IOWR(PTP_CLK_MAGIC, 23, struct ptp_sys_offset_attrs)
> +#define PTP_SYS_OFFSET_EXTENDED_ATTRS \
> +	_IOWR(PTP_CLK_MAGIC, 24, struct ptp_sys_offset_attrs)
>  
>  struct ptp_extts_event {
>  	struct ptp_clock_time t; /* Time event occurred. */


^ permalink raw reply

* Re: [PATCH net] net: mctp i3c: clean up notifier and buses if driver register fails
From: Jeremy Kerr @ 2026-07-15  0:46 UTC (permalink / raw)
  To: Myeonghun Pak, Matt Johnston
  Cc: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, netdev, linux-kernel, Ijae Kim
In-Reply-To: <20260714081025.89163-1-mhun512@gmail.com>

Hi,

> mctp_i3c_mod_init() registers the I3C bus notifier and then walks the
> existing buses with i3c_for_each_bus_locked(mctp_i3c_bus_add_new, NULL)
> before registering the I3C device driver.  If i3c_driver_register()
> fails, the function returns the error directly, leaving the notifier
> registered and every mctp_i3c_bus object created for the existing buses
> allocated.  The notifier is left pointing into the module that failed to
> load and the bus list is leaked.
> 
> Mirror the module exit path on this failure: unregister the notifier and
> tear down the buses that were added before returning the error.

Looks good, but we probably want to remove the unneeded
i3c_driver_unregister in the notify registration failure path too.

Also, you're missing Horms from the CC; more out of curiosity, but
how did you generate the CC list here?

Cheers,


Jeremy

^ permalink raw reply

* Re: [PATCH v4 net-next 7/7] net: ena: Implement gettimexattrs64 callback for PTP attributes
From: Jacob Keller @ 2026-07-15  0:47 UTC (permalink / raw)
  To: Arthur Kiyanovski, David Miller, Jakub Kicinski, netdev
  Cc: Richard Cochran, Eric Dumazet, Paolo Abeni, David Woodhouse,
	Thomas Gleixner, Miroslav Lichvar, Andrew Lunn, Wen Gu, Xuan Zhuo,
	David Woodhouse, Yonatan Sarna, Zorik Machulsky,
	Alexander Matushevsky, Saeed Bshara, Matt Wilson, Anthony Liguori,
	Nafea Bshara, Evgeny Schmeilin, Netanel Belgazal, Ali Saidi,
	Benjamin Herrenschmidt, Noam Dagan, David Arinzon,
	Evgeny Ostrovsky, Ofir Tabachnik, Amit Bernstein, linux-kselftest,
	linux-doc, shuah, Jonathan Corbet, Shuah Khan, Simon Horman,
	vadim.fedorenko
In-Reply-To: <20260714020340.25014-8-akiyano@amazon.com>

On 7/13/2026 7:03 PM, Arthur Kiyanovski wrote:
> Implement the gettimexattrs64 callback in the ENA driver to support
> the PTP_SYS_OFFSET_EXTENDED_ATTRS ioctl.
> 
> This enables applications to retrieve PHC timestamps with quality
> attributes through the standard PTP ioctl interface.
> 
> The ENA device currently reports only error_bound (valid bit set).
> Other attributes are not reported (valid bits unset).

Typically it would be a policy not to introduce new attributes which are
not yet used, and add the other attributes once a user appears. However,
I think it makes sense to have the full set of desired attributes
especially given the ioctl interface limitations which would otherwise
require a lot of reserved space or new ioctl numbers. Especially given
the uAPI here has been discussed and changed heavily from previous patch
iterations.

^ permalink raw reply

* Re: [PATCHv3 net-next 3/9] net: usb: usbnet: add cdc_state to struct usbnet
From: Andrew Lunn @ 2026-07-15  1:18 UTC (permalink / raw)
  To: Oliver Neukum
  Cc: andrew+netdev, davem, edumazet, kuba, pabeni, manuelebner, netdev,
	linux-kernel
In-Reply-To: <20260714114429.1073434-3-oneukum@suse.com>

On Tue, Jul 14, 2026 at 01:44:23PM +0200, Oliver Neukum wrote:
> This allows centralisation of code using cdc_state in usbnet, reducing
> code duplication. No functional change intended.
> 
> Signed-off-by: Oliver Neukum <oneukum@suse.com>

I gave a Reviewed-by to v2 of this patch. You are supposed to attach
them here on the next version. b4 collect them and add them for you,
if you use it.

   Andrew

^ permalink raw reply

* Re: [PATCH net-next v3 4/4] net: stmmac: dwmac-socfpga: Add support for Agilex5 TSN GMAC with FPGA converter
From: Andrew Lunn @ 2026-07-15  1:22 UTC (permalink / raw)
  To: muhammad.nazim.amirul.nazle.asmade
  Cc: dinguyen, maxime.chevallier, rmk+kernel, krzk+dt, conor+dt, robh,
	davem, edumazet, kuba, pabeni, andrew+netdev, devicetree,
	linux-arm-kernel, netdev, linux-kernel
In-Reply-To: <20260714021303.30042-5-muhammad.nazim.amirul.nazle.asmade@altera.com>

On Mon, Jul 13, 2026 at 07:13:03PM -0700, muhammad.nazim.amirul.nazle.asmade@altera.com wrote:
> From: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
> 
> The Agilex5 SoCDK TSN Config2 board uses a GMII-to-RGMII converter
> implemented as FPGA soft IP between gmac1 and its PHY. This converter
> provides the RGMII TX/RX clock delays, so the MAC interface selector
> must be configured for GMII while the PHY is configured without delays.
> 
> Add the "altr,socfpga-stmmac-agilex5-tsn" compatible to the match table
> and detect it in probe to force GMII for the MAC interface selector and
> strip the delay bits from phy_interface so the PHY is not configured to
> add delays already provided by the FPGA converter.
> 
> Signed-off-by: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>

Reviewed-by: Andrew Lunn <andrew@lunn.ch>

    Andrew

^ permalink raw reply

* Re: [PATCH net-next v3 3/3] net: dsa: motorcomm: Add LED support
From: Andrew Lunn @ 2026-07-15  1:25 UTC (permalink / raw)
  To: David Yang
  Cc: netdev, Vladimir Oltean, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, linux-kernel
In-Reply-To: <20260701155519.273212-4-mmyangfl@gmail.com>

On Wed, Jul 01, 2026 at 11:54:06PM +0800, David Yang wrote:
> LEDs can be described in the device tree using the same format as qca8k.
> Each port can configure up to 3 LEDs.
> 
> Currently, only parallel mode and strict 1:1 mapping are supported.
> 
> Signed-off-by: David Yang <mmyangfl@gmail.com>

Reviewed-by: Andrew Lunn <andrew@lunn.ch>

    Andrew

^ permalink raw reply

* RE: [PATCH net-next v2] net: libwx: disable TX VLAN offload for packets with >2 VLAN tags
From: Jiawen Wu @ 2026-07-15  1:41 UTC (permalink / raw)
  To: 'Jacob Keller', netdev
  Cc: 'Duanqiang Wen', 'Mengyuan Lou',
	'Andrew Lunn', 'David S. Miller',
	'Eric Dumazet', 'Jakub Kicinski',
	'Paolo Abeni', 'Simon Horman',
	'Kees Cook', 'Przemek Kitszel'
In-Reply-To: <6ab773c8-6c43-4c53-86ed-46bbaecb8073@intel.com>

On Wed, Jul 15, 2026 8:27 AM, Jacob Keller wrote:
> On 7/12/2026 11:04 PM, Jiawen Wu wrote:
> > The current hardware does not support TX VLAN offload for packets with
> > three or more VLAN tags. When such packets are transmitted with hardware
> > VLAN offload enabled, the hardware may malfunction or produce corrupted
> > frames.
> >
> > Add a check in wx_features_check() to parse the VLAN depth of the
> > skb. If more than two VLAN tags are detected (including both the
> > hardware tag and in-band tags), strip NETIF_F_HW_VLAN_CTAG_TX and
> > NETIF_F_HW_VLAN_STAG_TX from the feature set. This forces the
> > kernel networking stack to handle VLAN insertion in software for
> > these specific packets, ensuring correct transmission.
> >
> > Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
> 
> 
> Is there a reason this was targeted at net-next instead of as a bug fix
> to net with a Fixes tag to the commit which first introduced VLAN tagging?
> 
> Thanks,
> Jake

Probably because I couldn't find a Fixes tag for it...

> 
> > ---
> > v2:
> > - Remove redundant 'parse_depth'.
> > - Optimize the loop.
> >
> > v1: https://lore.kernel.org/all/C1BF77C0E073A40C+20260710071831.210196-1-jiawenwu@trustnetic.com
> > ---
> >  drivers/net/ethernet/wangxun/libwx/wx_lib.c | 24 +++++++++++++++++++++
> >  1 file changed, 24 insertions(+)
> >
> > diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
> > index 814d88d2aee4..34542b3dc884 100644
> > --- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c
> > +++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
> > @@ -3228,6 +3228,30 @@ netdev_features_t wx_features_check(struct sk_buff *skb,
> >  				    netdev_features_t features)
> >  {
> >  	struct wx *wx = netdev_priv(netdev);
> > +	__be16 type = skb->protocol;
> > +	u16 vlan_depth = ETH_HLEN;
> > +	u32 vlan_num = 0;
> > +
> > +	if (skb_vlan_tag_present(skb))
> > +		vlan_num++;
> > +
> > +	while (eth_type_vlan(type)) {
> > +		struct vlan_hdr vhdr, *vh;
> > +
> > +		vh = skb_header_pointer(skb, vlan_depth, sizeof(vhdr), &vhdr);
> > +		if (unlikely(!vh))
> > +			break;
> > +
> > +		type = vh->h_vlan_encapsulated_proto;
> > +		vlan_depth += VLAN_HLEN;
> > +		vlan_num++;
> > +
> > +		if (vlan_num > 2) {
> > +			features &= ~(NETIF_F_HW_VLAN_CTAG_TX |
> > +				      NETIF_F_HW_VLAN_STAG_TX);
> > +			break;
> > +		}
> > +	}
> >
> >  	if (!skb->encapsulation)
> >  		return features;
> 
> 


^ permalink raw reply

* [PATCH net v3 1/2] sctp: avoid auth_enable sysctl UAF during netns teardown
From: Ren Wei @ 2026-07-15  1:50 UTC (permalink / raw)
  To: linux-sctp, netdev
  Cc: marcelo.leitner, lucien.xin, davem, edumazet, pabeni, horms,
	matttbe, yuantan098, yifanwucs, tomapufckgml, bird, tpluszz77,
	roxy520tt, n05ec, sashiko-bot
In-Reply-To: <cover.1784033357.git.roxy520tt@gmail.com>

From: Zhiling Zou <roxy520tt@gmail.com>

proc_sctp_do_auth() updates the SCTP control socket after changing
net.sctp.auth_enable. The handler gets the per-net SCTP state from
ctl->data, so an already opened sysctl file can still target a network
namespace while that namespace is being torn down.

SCTP previously registered its per-net sysctls from sctp_defaults_init(),
while the control socket is created later from sctp_ctrlsock_init(). This
exposed a window during initialization where auth_enable was writable
before net->sctp.ctl_sock existed, and a teardown window where auth_enable
stayed writable after inet_ctl_sock_destroy() had released the control
socket.

Move the per-net SCTP sysctl registration into sctp_ctrlsock_init() after
sctp_ctl_sock_init() succeeds, and unregister the sysctl table before
destroying the control socket in sctp_ctrlsock_exit(). If sysctl
registration fails after the control socket was created, destroy the
control socket in the same init path.

Make sctp_sysctl_net_unregister() tolerate a missing header and clear the
saved pointer so init-error and exit paths can safely share the unregister
helper.

Fixes: 15649fd5415e ("sctp: sysctl: auth_enable: avoid using current->nsproxy")
Cc: stable@vger.kernel.org
Reported-by: Yuan Tan <yuantan098@gmail.com>
Reported-by: Yifan Wu <yifanwucs@gmail.com>
Reported-by: Juefei Pu <tomapufckgml@gmail.com>
Reported-by: Xin Liu <bird@lzu.edu.cn>
Co-developed-by: Qi Tang <tpluszz77@gmail.com>
Signed-off-by: Qi Tang <tpluszz77@gmail.com>
Signed-off-by: Zhiling Zou <roxy520tt@gmail.com>
Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
---
Changes in v3:
- Follow Xin Long's suggestion and return immediately when
  sctp_ctl_sock_init() fails.
- Keep per-net SCTP sysctl registration in a separate success path after
  the control socket has been created.

 net/sctp/protocol.c | 20 ++++++++++++--------
 net/sctp/sysctl.c   |  9 +++++++--
 2 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index cf335494bffe..49d9740b1e0f 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -1383,10 +1383,6 @@ static int __net_init sctp_defaults_init(struct net *net)
 	net->sctp.l3mdev_accept = 1;
 #endif
 
-	status = sctp_sysctl_net_register(net);
-	if (status)
-		goto err_sysctl_register;
-
 	/* Allocate and initialise sctp mibs.  */
 	status = init_sctp_mibs(net);
 	if (status)
@@ -1420,8 +1416,6 @@ static int __net_init sctp_defaults_init(struct net *net)
 	cleanup_sctp_mibs(net);
 #endif
 err_init_mibs:
-	sctp_sysctl_net_unregister(net);
-err_sysctl_register:
 	return status;
 }
 
@@ -1436,7 +1430,6 @@ static void __net_exit sctp_defaults_exit(struct net *net)
 	net->sctp.proc_net_sctp = NULL;
 #endif
 	cleanup_sctp_mibs(net);
-	sctp_sysctl_net_unregister(net);
 }
 
 static struct pernet_operations sctp_defaults_ops = {
@@ -1450,16 +1443,27 @@ static int __net_init sctp_ctrlsock_init(struct net *net)
 
 	/* Initialize the control inode/socket for handling OOTB packets.  */
 	status = sctp_ctl_sock_init(net);
-	if (status)
+	if (status) {
 		pr_err("Failed to initialize the SCTP control sock\n");
+		return status;
+	}
+
+	status = sctp_sysctl_net_register(net);
+	if (status) {
+		inet_ctl_sock_destroy(net->sctp.ctl_sock);
+		net->sctp.ctl_sock = NULL;
+	}
 
 	return status;
 }
 
 static void __net_exit sctp_ctrlsock_exit(struct net *net)
 {
+	sctp_sysctl_net_unregister(net);
+
 	/* Free the control endpoint.  */
 	inet_ctl_sock_destroy(net->sctp.ctl_sock);
+	net->sctp.ctl_sock = NULL;
 }
 
 static struct pernet_operations sctp_ctrlsock_ops = {
diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c
index 15e7db9a3ab2..fca840484ebf 100644
--- a/net/sctp/sysctl.c
+++ b/net/sctp/sysctl.c
@@ -615,11 +615,16 @@ int sctp_sysctl_net_register(struct net *net)
 
 void sctp_sysctl_net_unregister(struct net *net)
 {
+	struct ctl_table_header *header = net->sctp.sysctl_header;
 	const struct ctl_table *table;
 
-	table = net->sctp.sysctl_header->ctl_table_arg;
-	unregister_net_sysctl_table(net->sctp.sysctl_header);
+	if (!header)
+		return;
+
+	table = header->ctl_table_arg;
+	unregister_net_sysctl_table(header);
 	kfree(table);
+	net->sctp.sysctl_header = NULL;
 }
 
 static struct ctl_table_header *sctp_sysctl_header;
-- 
2.43.0


^ permalink raw reply related

* [PATCH net v3 2/2] sctp: close UDP tunnel sockets during netns teardown
From: Ren Wei @ 2026-07-15  1:50 UTC (permalink / raw)
  To: linux-sctp, netdev
  Cc: marcelo.leitner, lucien.xin, davem, edumazet, pabeni, horms,
	matttbe, yuantan098, yifanwucs, tomapufckgml, bird, tpluszz77,
	roxy520tt, n05ec, sashiko-bot
In-Reply-To: <cover.1784033357.git.roxy520tt@gmail.com>

From: Zhiling Zou <roxy520tt@gmail.com>

proc_sctp_do_udp_port() starts per-net SCTP UDP tunneling sockets when
net.sctp.udp_port is set, and stops/restarts them when the sysctl value
changes. The netns exit path does not stop these sockets, so a namespace
can be torn down while its SCTP UDP tunnel sockets are still installed.

Close the UDP tunnel sockets from sctp_ctrlsock_exit() after unregistering
the per-net sysctl table. This prevents new sysctl writes from racing in
while the sockets are being released, and closes the sockets before the
control socket is destroyed.

Fixes: 046c052b475e ("sctp: enable udp tunneling socks")
Cc: stable@vger.kernel.org
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/b9f1f02b0780ad6a719e2413f5f0bb8eb7702d94.1782585631.git.roxy520tt%40gmail.com
Signed-off-by: Zhiling Zou <roxy520tt@gmail.com>
Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
---
Changes in v3:
- No code changes.

 net/sctp/protocol.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 49d9740b1e0f..27c26e12f95d 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -1460,6 +1460,7 @@ static int __net_init sctp_ctrlsock_init(struct net *net)
 static void __net_exit sctp_ctrlsock_exit(struct net *net)
 {
 	sctp_sysctl_net_unregister(net);
+	sctp_udp_sock_stop(net);
 
 	/* Free the control endpoint.  */
 	inet_ctl_sock_destroy(net->sctp.ctl_sock);
-- 
2.43.0


^ permalink raw reply related

* [PATCH net-next v3] selftests/net/openvswitch: add SCTP flow key test
From: Minxi Hou @ 2026-07-15  1:54 UTC (permalink / raw)
  To: netdev
  Cc: aconole, echaudro, i.maximets, davem, edumazet, kuba, pabeni,
	horms, shuah, dev, linux-kselftest, linux-kernel, Minxi Hou

Add test_sctp_connect_v4() to verify OVS can match on SCTP flow keys
(sctp src/dst port).

The test sets up client and server namespaces connected through an
OVS bridge, installs port-keyed flows, and verifies:
  - sctp(dst=4443) matches client-to-server INIT
  - sctp(src=4443) matches server-to-client INIT-ACK
  - removing flows drops the connection
  - reinstalling flows restores connectivity

Signed-off-by: Minxi Hou <houminxi@gmail.com>
---
 .../selftests/net/openvswitch/openvswitch.sh  | 105 ++++++++++++++++++
 .../selftests/net/openvswitch/ovs-dpctl.py    |   5 +
 2 files changed, 110 insertions(+)

v2 -> v3:
  - replace ncat with nc for consistency with other tests in the same
    file (per Ilya Maximets' review)
  - add wait for killed daemon processes (per sashiko review)
  - replace 'Ncat: Listening' stderr grep with ss port-based readiness
    check

diff --git a/tools/testing/selftests/net/openvswitch/openvswitch.sh b/tools/testing/selftests/net/openvswitch/openvswitch.sh
index 2954245129a2..0ec9c969cd0a 100755
--- a/tools/testing/selftests/net/openvswitch/openvswitch.sh
+++ b/tools/testing/selftests/net/openvswitch/openvswitch.sh
@@ -32,6 +32,7 @@ tests="
 	dec_ttl					ttl: dec_ttl decrements IP TTL
 	flow_set				flow-set: Flow modify
 	action_set				set: SET action rewrites fields
+	sctp_connect_v4				sctp: SCTP flow key matching
 	psample					psample: Sampling packets with psample"
 
 info() {
@@ -443,6 +444,110 @@ test_action_set() {
 	return 0
 }
 
+# sctp_connect_v4 test
+# - sctp(dst=4443) matches client-to-server INIT
+# - sctp(src=4443) matches server-to-client INIT-ACK
+# - remove flows and verify connection fails, reinstall and recover
+test_sctp_connect_v4() {
+	local t="test_sctp_connect_v4"
+
+	which nc >/dev/null 2>&1 || return $ksft_skip
+	nc --sctp -z 127.0.0.1 1 </dev/null 2>/dev/null || return $ksft_skip
+	modprobe -q sctp 2>/dev/null || return $ksft_skip
+
+	sbx_add "$t" || return $?
+	ovs_add_dp "$t" sctp4 || return 1
+
+	info "create namespaces"
+	for ns in client server; do
+		ovs_add_netns_and_veths "$t" "sctp4" "$ns" \
+		    "${ns:0:1}0" "${ns:0:1}1" || return 1
+	done
+
+	ip netns exec client ip addr add 172.31.110.10/24 dev c1
+	ip netns exec client ip link set c1 up
+	ip netns exec server ip addr add 172.31.110.20/24 dev s1
+	ip netns exec server ip link set s1 up
+
+	# ARP forwarding
+	ovs_add_flow "$t" sctp4 \
+	    'in_port(1),eth(),eth_type(0x0806),arp()' \
+	    '2' || return 1
+	ovs_add_flow "$t" sctp4 \
+	    'in_port(2),eth(),eth_type(0x0806),arp()' \
+	    '1' || return 1
+
+	# SCTP port matching: dst for request, src for reply
+	ovs_add_flow "$t" sctp4 \
+	    'in_port(1),eth(),eth_type(0x0800),ipv4(proto=132),sctp(dst=4443)' \
+	    '2' || return 1
+	ovs_add_flow "$t" sctp4 \
+	    'in_port(2),eth(),eth_type(0x0800),ipv4(proto=132),sctp(src=4443)' \
+	    '1' || return 1
+
+	echo "server" | \
+		ovs_netns_spawn_daemon "$t" "server" \
+				nc --sctp -l 172.31.110.20 -vn 4443
+	local server_pid=$pid
+	ovs_wait ip netns exec server \
+	    ss -lnH sport = :4443 \| grep -q . \
+	    || return 1
+
+	info "verify SCTP association with port-keyed flows"
+	ovs_sbx "$t" ip netns exec client \
+	    nc --sctp -i 1 -zv 172.31.110.20 4443 \
+	    || return 1
+
+	ovs_del_flows "$t" sctp4
+
+	info "verify connection fails without flows"
+	ovs_add_flow "$t" sctp4 \
+	    'in_port(1),eth(),eth_type(0x0806),arp()' \
+	    '2' || return 1
+	ovs_add_flow "$t" sctp4 \
+	    'in_port(2),eth(),eth_type(0x0806),arp()' \
+	    '1' || return 1
+
+	kill -TERM $server_pid 2>/dev/null
+	wait $server_pid 2>/dev/null
+	echo "server2" | \
+		ovs_netns_spawn_daemon "$t" "server" \
+				nc --sctp -l 172.31.110.20 -vn 4443
+	server_pid=$pid
+	ovs_wait ip netns exec server \
+	    ss -lnH sport = :4443 \| grep -q . \
+	    || return 1
+
+	ovs_sbx "$t" ip netns exec client \
+	    nc --sctp -w 2 -zv 172.31.110.20 4443 \
+	    >/dev/null 2>&1 \
+	    && { info "FAIL: connection should fail without flows"
+	         return 1; }
+
+	info "reinstall flows and verify recovery"
+	ovs_add_flow "$t" sctp4 \
+	    'in_port(1),eth(),eth_type(0x0800),ipv4(proto=132),sctp(dst=4443)' \
+	    '2' || return 1
+	ovs_add_flow "$t" sctp4 \
+	    'in_port(2),eth(),eth_type(0x0800),ipv4(proto=132),sctp(src=4443)' \
+	    '1' || return 1
+
+	kill -TERM $server_pid 2>/dev/null
+	wait $server_pid 2>/dev/null
+	echo "server3" | \
+		ovs_netns_spawn_daemon "$t" "server" \
+				nc --sctp -l 172.31.110.20 -vn 4443
+	ovs_wait ip netns exec server \
+	    ss -lnH sport = :4443 \| grep -q . \
+	    || return 1
+
+	ovs_sbx "$t" ip netns exec client \
+	    nc --sctp -i 1 -zv 172.31.110.20 4443 \
+	    || return 1
+
+	return 0
+}
+
 # psample test
 # - use psample to observe packets
 test_psample() {
diff --git a/tools/testing/selftests/net/openvswitch/ovs-dpctl.py b/tools/testing/selftests/net/openvswitch/ovs-dpctl.py
index e1ecfad2c03e..7cfc29ec7e59 100644
--- a/tools/testing/selftests/net/openvswitch/ovs-dpctl.py
+++ b/tools/testing/selftests/net/openvswitch/ovs-dpctl.py
@@ -1982,6 +1982,11 @@ class ovskey(nla):
                 "icmp",
                 ovskey.ovs_key_icmp,
             ),
+            (
+                "OVS_KEY_ATTR_SCTP",
+                "sctp",
+                ovskey.ovs_key_sctp,
+            ),
             (
                 "OVS_KEY_ATTR_TCP_FLAGS",
                 "tcp_flags",
-- 
2.55.0


^ permalink raw reply related

* RE: [PATCH net] tipc: fix infinite loop in __tipc_nl_compat_dumpit
From: Tung Quang Nguyen @ 2026-07-15  2:14 UTC (permalink / raw)
  To: Helen Koike
  Cc: jmaloy@redhat.com, davem@davemloft.net, netdev@vger.kernel.org,
	tipc-discussion@lists.sourceforge.net,
	linux-kernel@vger.kernel.org, kernel-dev@igalia.com
In-Reply-To: <20260713204940.647668-1-koike@igalia.com>

>Subject: [PATCH net] tipc: fix infinite loop in __tipc_nl_compat_dumpit
>
>cmd->dumpit callback can return a negative errno, causing an infinite
>loop due to the while(len) condition. As the loop never terminates,
>genl_mutex is never released, and other tasks waiting on it starve in D state.
>
>Check dumpit's return value, propagate it and jump to err_out on error.
>
>Reported-by: syzbot+85d0bec020d805014a3a@syzkaller.appspotmail.com
>Closes: https://syzkaller.appspot.com/bug?extid=85d0bec020d805014a3a
>Fixes: d0796d1ef63d ("tipc: convert legacy nl bearer dump to nl compat")
>Signed-off-by: Helen Koike <koike@igalia.com>
>---
>
>Tested locally using syzbot reproducer.
>---
> net/tipc/netlink_compat.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
>diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c index
>2a786c56c8c5..d9a4f94ea2d4 100644
>--- a/net/tipc/netlink_compat.c
>+++ b/net/tipc/netlink_compat.c
>@@ -221,6 +221,10 @@ static int __tipc_nl_compat_dumpit(struct
>tipc_nl_compat_cmd_dump *cmd,
> 		int rem;
>
> 		len = (*cmd->dumpit)(buf, &cb);
>+		if (len < 0) {
>+			err = len;
>+			goto err_out;
>+		}
>
> 		nlmsg_for_each_msg(nlmsg, nlmsg_hdr(buf), len, rem) {
> 			err = nlmsg_parse_deprecated(nlmsg, GENL_HDRLEN,
>--
>2.54.0
>
Reviewed-by: Tung Nguyen <tung.quang.nguyen@est.tech

^ permalink raw reply

* RE: [PATCH net] tipc: fix infinite loop in __tipc_nl_compat_dumpit
From: Tung Quang Nguyen @ 2026-07-15  2:17 UTC (permalink / raw)
  To: Helen Koike
  Cc: jmaloy@redhat.com, davem@davemloft.net, netdev@vger.kernel.org,
	tipc-discussion@lists.sourceforge.net,
	linux-kernel@vger.kernel.org, kernel-dev@igalia.com
In-Reply-To: <20260713204940.647668-1-koike@igalia.com>

>Subject: [PATCH net] tipc: fix infinite loop in __tipc_nl_compat_dumpit
>
>cmd->dumpit callback can return a negative errno, causing an infinite
>loop due to the while(len) condition. As the loop never terminates,
>genl_mutex is never released, and other tasks waiting on it starve in D state.
>
>Check dumpit's return value, propagate it and jump to err_out on error.
>
>Reported-by: syzbot+85d0bec020d805014a3a@syzkaller.appspotmail.com
>Closes: https://syzkaller.appspot.com/bug?extid=85d0bec020d805014a3a
>Fixes: d0796d1ef63d ("tipc: convert legacy nl bearer dump to nl compat")
>Signed-off-by: Helen Koike <koike@igalia.com>
>---
>
>Tested locally using syzbot reproducer.
>---
> net/tipc/netlink_compat.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
>diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c index
>2a786c56c8c5..d9a4f94ea2d4 100644
>--- a/net/tipc/netlink_compat.c
>+++ b/net/tipc/netlink_compat.c
>@@ -221,6 +221,10 @@ static int __tipc_nl_compat_dumpit(struct
>tipc_nl_compat_cmd_dump *cmd,
> 		int rem;
>
> 		len = (*cmd->dumpit)(buf, &cb);
>+		if (len < 0) {
>+			err = len;
>+			goto err_out;
>+		}
>
> 		nlmsg_for_each_msg(nlmsg, nlmsg_hdr(buf), len, rem) {
> 			err = nlmsg_parse_deprecated(nlmsg, GENL_HDRLEN,
>--
>2.54.0
>
Reviewed-by: Tung Nguyen <tung.quang.nguyen@est.tech>

^ permalink raw reply

* Re: [PATCH] virtio_net: fix infinite loop in virtnet_poll_cleantx when device is broken
From: Jinqian Yang @ 2026-07-15  2:45 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: jasowang, xuanzhuo, eperezma, andrew+netdev, davem, edumazet,
	kuba, pabeni, netdev, virtualization, linux-kernel, liuyonglong,
	wangzhou1, linuxarm
In-Reply-To: <20260714091622-mutt-send-email-mst@kernel.org>

Hi,

On 2026/7/14 21:17, Michael S. Tsirkin wrote:
> On Mon, Jul 13, 2026 at 09:20:25PM +0800, Jinqian Yang wrote:
>> virtnet_poll_cleantx() contains a do-while loop that cleans up
>> transmitted TX buffers and calls virtqueue_enable_cb_delayed() to check
>> whether more buffers need processing. When the virtio backend stops
>> responding during guest reboot, used->idx is never updated, so
>> virtqueue_enable_cb_delayed() always returns false and the loop never
>> terminates. Then it will block reboot process, and the guest will hang.
>>
>> The problem occurs during guest reboot under network traffic:
>>
>>    1. kernel_restart() -> device_shutdown() traverses the device list
>>    2. virtio_dev_shutdown() calls virtio_break_device() which sets
>>       vq->broken = true
>>    3. virtio_dev_shutdown() then calls virtio_synchronize_cbs() to wait
>>       for in-flight callbacks to complete
>>    4. A virtio interrupt fires, softirq is deferred to ksoftirqd which
>>       calls net_rx_action() -> virtnet_poll() -> virtnet_poll_cleantx()
>>    5. virtnet_poll_cleantx() enters the do-while loop and never exits
>>       because the QEMU backend has stopped updating used->idx, despite
>>       vq->broken having been set to true in step 2.
>>
>> Since the loop runs inside ksoftirqd (a SCHED_OTHER kthread), it is
>> visible to the scheduler and does not trigger a hard lockup. However,
>> the kthread never leaves the loop, so RCU detects it as a CPU stall
>> and reports it periodically. Meanwhile, the reboot process remains
>> blocked in device_shutdown() because virtio_dev_shutdown() cannot
>> complete its synchronization step, and the guest hangs permanently.
>>
>> This can be reproduced on a guest with a virtio-net device: run iperf3
>> traffic in the guest, then trigger reboot. The reboot occasionally hangs
>> permanently with RCU stall on ksoftirqd.
>>
>> Observed on ARM64 KVM guest:
>>
>>    CPU#1 RCU stall (ksoftirqd/1), repeated periodically:
>>      virtqueue_enable_cb_delayed_split <- virtnet_poll <- __napi_poll <-
>>      net_rx_action <- handle_softirqs <- run_ksoftirqd <-
>>      smpboot_thread_fn <- kthread
>>
>> Fix by adding a virtqueue_is_broken() check to the loop condition, so
>> that the loop exits immediately when the device is broken, allowing
>> the device shutdown to proceed.
>>
>> Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com>
> 
> I'd expect lots of drivers have this issue?  Wouldn't it make more sense
> to check virtqueue_is_broken in
> virtqueue_enable_cb_delayed/virtqueue_enable_cb? This way it works for
> all drivers.
> 

In virtqueue_enable_cb->virtqueue_poll, a check for vq->broken is
performed, so other devices do not have this issue.

Indeed, it is more reasonable to check vq->broken inside
virtqueue_enable_cb_delayed. I will make the changes in v2.

Thanks,
Jinqian

> 
> 
>> ---
>>   drivers/net/virtio_net.c | 3 ++-
>>   1 file changed, 2 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
>> index 7d2eeb9b1226..c8d2d420c31d 100644
>> --- a/drivers/net/virtio_net.c
>> +++ b/drivers/net/virtio_net.c
>> @@ -2970,7 +2970,8 @@ static void virtnet_poll_cleantx(struct receive_queue *rq, int budget)
>>   		do {
>>   			virtqueue_disable_cb(sq->vq);
>>   			free_old_xmit(sq, txq, !!budget);
>> -		} while (unlikely(!virtqueue_enable_cb_delayed(sq->vq)));
>> +		} while (!virtqueue_is_broken(sq->vq) &&
>> +			 unlikely(!virtqueue_enable_cb_delayed(sq->vq)));
>>   
>>   		if (sq->vq->num_free >= MAX_SKB_FRAGS + 2)
>>   			virtnet_tx_wake_queue(vi, sq);
>> -- 
>> 2.33.0
> 
> 


^ permalink raw reply

* Re: [Intel-wired-lan] [PATCH iwl-net v1] ice: fix use-after-free in dynamic port cleanup
From: luoxuanqiang @ 2026-07-15  2:58 UTC (permalink / raw)
  To: Marcin Szycik, intel-wired-lan
  Cc: anthony.l.nguyen, przemyslaw.kitszel, andrew+netdev,
	sridhar.samudrala, wojciech.drewek, piotr.raczynski,
	michal.swiatkowski, jacob.e.keller, netdev, Xuanqiang Luo, stable
In-Reply-To: <36c68c94-0382-4d31-b114-fde2a5ad35cf@linux.intel.com>


在 2026/7/14 22:14, Marcin Szycik 写道:
> On 14.07.2026 08:39,xuanqiang.luo@linux.dev wrote:
>> From: Xuanqiang Luo<luoxuanqiang@kylinos.cn>
>>
>> ice_dealloc_dynamic_port() uses dyn_port->vsi->idx to erase the dynamic
>> port from pf->dyn_ports. However, it frees the VSI before reading the
>> index for the erase, resulting in a use-after-free.
>>
>> Follow the reverse of the allocation order in ice_alloc_dynamic_port()
>> by erasing the xarray entry before freeing the VSI.
>>
>> Fixes: eda69d654c7e ("ice: add basic devlink subfunctions support")
>> Cc:stable@vger.kernel.org
>> Signed-off-by: Xuanqiang Luo<luoxuanqiang@kylinos.cn>
> Reviewed-by: Marcin Szycik<marcin.szycik@linux.intel.com>
>
> Thank you!
> I wonder how such a glaring issue survived in the codebase for so long.
> Perhaps ice_vsi_free() exited early for some reason.

Thanks for the review!

Hard to say—maybe the window is quite small and the freed slab still
holds the old idx most of the time, so nothing obvious shows up.

>> ---
>>   drivers/net/ethernet/intel/ice/devlink/port.c | 2 +-
>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/net/ethernet/intel/ice/devlink/port.c b/drivers/net/ethernet/intel/ice/devlink/port.c
>> index 2a2e56777f9f7..3ede246490027 100644
>> --- a/drivers/net/ethernet/intel/ice/devlink/port.c
>> +++ b/drivers/net/ethernet/intel/ice/devlink/port.c
>> @@ -590,8 +590,8 @@ static void ice_dealloc_dynamic_port(struct ice_dynamic_port *dyn_port)
>>   
>>   	xa_erase(&pf->sf_nums, devlink_port->attrs.pci_sf.sf);
>>   	ice_eswitch_detach_sf(pf, dyn_port);
>> -	ice_vsi_free(dyn_port->vsi);
>>   	xa_erase(&pf->dyn_ports, dyn_port->vsi->idx);
>> +	ice_vsi_free(dyn_port->vsi);
>>   	kfree(dyn_port);
>>   }
>>   

^ permalink raw reply

* Re: [PATCH net] mctp: serial: reject zero-length frames to prevent rx buffer overflow
From: Jeremy Kerr @ 2026-07-15  3:23 UTC (permalink / raw)
  To: Doruk Tan Ozturk, matt, andrew+netdev, davem, edumazet, kuba,
	pabeni
  Cc: netdev, linux-kernel, stable
In-Reply-To: <20260714130348.72716-1-doruk@0sec.ai>

Hi Doruk,

Thanks for the report. The analysis looks solid, but I do have a
recommendation for a different fix. One comment inline too.

> The MCTP serial receive state machine reads a frame length byte in
> mctp_serial_push_header() case 2 and validates it upper-bound-only:
> 
> 	if (c > MCTP_SERIAL_FRAME_MTU) {
> 		dev->rxstate = STATE_ERR;
> 	} else {
> 		dev->rxlen = c;
> 		dev->rxpos = 0;
> 		dev->rxstate = STATE_DATA;
> 		...
> 	}
> 
> A length of zero passes this check, so rxlen is set to 0 and the state
> machine advances to STATE_DATA. In mctp_serial_push() STATE_DATA, the
> incoming byte is stored and rxpos incremented before the terminator is
> tested:
> 
> 	dev->rxbuf[dev->rxpos] = c;
> 	dev->rxpos++;
> 	dev->rxstate = STATE_DATA;
> 	if (dev->rxpos == dev->rxlen) {
> 		dev->rxpos = 0;
> 		dev->rxstate = STATE_TRAILER;
> 	}
> 
> With rxlen == 0 the "rxpos == rxlen" terminator can never fire (rxpos is
> already 1 on the first data byte), so subsequent bytes are written past
> the end of the fixed 74-byte rxbuf, which is the last member of the
> netdev private area. Every following data byte is an attacker-controlled
> 1-byte out-of-bounds heap write, and the overflow continues until a
> frame (0x7e) or escape byte resets the parser -- effectively unbounded.
> 
> Reaching this requires CAP_NET_ADMIN to attach the N_MCTP line
> discipline and bring the resulting mctpserialN netdev up, after which
> the bytes arrive via the tty receive path.
> 
> Reject a zero-length frame in the header parser, matching the existing
> upper-bound rejection.
> 
> KASAN, on a frame of 0x7e 0x01 0x00 followed by data bytes:
> 
>   UBSAN: array-index-out-of-bounds in drivers/net/mctp/mctp-serial.c:370
>   index 74 is out of range for type 'u8 [74]'
>   BUG: KASAN: slab-out-of-bounds in mctp_serial_tty_receive_buf
>   Write of size 1 at addr ... by task kworker/u16:0
>    mctp_serial_tty_receive_buf
>    tty_ldisc_receive_buf
>    flush_to_ldisc
>   Allocated by task 152:
>    alloc_netdev_mqs
>    mctp_serial_open
> 
> Found by 0sec (https://0sec.ai).
> Fixes: a0c2ccd9b5ad ("mctp: Add MCTP-over-serial transport binding")
> Cc: stable@vger.kernel.org
> Assisted-by: 0sec

I assume this needs to be in the Assisted-by format.

> Signed-off-by: Doruk Tan Ozturk <doruk@0sec.ai>
> ---
>  drivers/net/mctp/mctp-serial.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)

> diff --git a/drivers/net/mctp/mctp-serial.c b/drivers/net/mctp/mctp-serial.c
> index 26c9a33fd636..1e3d285c0500 100644
> --- a/drivers/net/mctp/mctp-serial.c
> +++ b/drivers/net/mctp/mctp-serial.c
> @@ -313,7 +313,7 @@ static void mctp_serial_push_header(struct mctp_serial *dev, u8 c)
>  		}
>  		break;
>  	case 2:
> -		if (c > MCTP_SERIAL_FRAME_MTU) {
> +		if (c == 0 || c > MCTP_SERIAL_FRAME_MTU) {
>  			dev->rxstate = STATE_ERR;
>  		} else {
>  			dev->rxlen = c;

We probably want to advance directly to STATE_TRAILER instead, in order
to consume the trailer and framing bytes for cases when it's a
legitimate (although somewhat useless) zero-length frame.

Perhaps:

--- a/drivers/net/mctp/mctp-serial.c
+++ b/drivers/net/mctp/mctp-serial.c
@@ -318,7 +318,7 @@ static void mctp_serial_push_header(struct mctp_serial *dev, u8 c)
                } else {
                        dev->rxlen = c;
                        dev->rxpos = 0;
-                       dev->rxstate = STATE_DATA;
+                       dev->rxstate = c > 0 ? STATE_DATA : STATE_TRAILER;
                        dev->rxfcs = crc_ccitt_byte(dev->rxfcs, c);
                }
                break;

We'll still land in STATE_ERROR on incorrect framing, but just during
trailer parse instead.

We could then add an early error path rather than creating a zero-length
skb (which then gets rejected by the MCTP core), but that would be best
done separately.

Cheers,


Jeremy

^ permalink raw reply

* [PATCH net-next 0/7] net: mana: harden the HWC and add dynamic queue depth
From: Long Li @ 2026-07-15  3:29 UTC (permalink / raw)
  To: Long Li, Konstantin Taranov, Jakub Kicinski, David S . Miller,
	Paolo Abeni, Eric Dumazet, Andrew Lunn, Jason Gunthorpe,
	Leon Romanovsky, Haiyang Zhang, K . Y . Srinivasan, Wei Liu,
	Dexuan Cui, shradhagupta, Simon Horman
  Cc: netdev, linux-rdma, linux-hyperv, linux-kernel

This series hardens the MANA Hardware Channel (HWC) control-plane path
and then builds on that to support a dynamic HWC queue depth.

The HWC is the command channel the driver uses to talk to the device.
Today it is created at a fixed depth of one outstanding request, and
several of its lookup and teardown paths predate the RCU and DMA-lifetime
rules they now need to follow.  Raising the queue depth and allowing
concurrent commands makes those latent races reachable, so the fixes come
first and the feature builds on them.

Patches 1-5 are fixes for pre-existing HWC bugs, each with a Fixes: tag:

  1: cq_table was a plain pointer array freed with no grace period while
     the EQ interrupt handler dereferenced it; put it under RCU.
  2: the HWC RQ and SQ were sized with each other's message size, so a
     response could overflow the RQ buffer and the RX slot stride was
     computed with the wrong size.
  3: comp_buf was freed before the EQ was destroyed, so a late completion
     handler could touch freed memory.
  4: the RX path consumed device-supplied lengths and indices without
     validation; validate them before use (this matters for confidential
     VMs, where the DMA buffer is shared with the host).
  5: a failed mana_hwc_establish_channel() could leave live MST entries
     while the driver freed the queue buffers, and destroy_channel() freed
     the TXQ/RXQ before the EQ was quiesced; add a setup_active teardown
     gate and destroy the CQ first.

Patches 6-7 add the feature:

  6: replace the depth-1 semaphore with a slot bitmap and per-slot
     synchronization so several management commands can be in flight,
     with teardown that drains in-flight senders before freeing the HWC.
  7: bootstrap the HWC at depth 1, query the device maximum and, if it is
     larger, tear down and rebuild the queues at that depth.  The reported
     dimensions are validated before they size DMA allocations, and the
     capability is advertised so firmware enables it only when the driver
     supports it.

The fixes are grouped ahead of the feature they enable rather than sent
separately to net, since the HWC runs at depth 1 today and the races are
reached only once the later patches raise the depth.

Long Li (7):
  net: mana: RCU-protect gc->cq_table lookups against concurrent CQ
    destroy
  net: mana: fix HWC RQ/SQ buffer size swap
  net: mana: free HWC comp_buf after destroying the EQ
  net: mana: validate hardware-supplied values in the HWC RX path
  net: mana: fix HWC teardown safety with setup_active flag and destroy
    ordering
  net: mana: support concurrent HWC requests with proper synchronization
  net: mana: add dynamic HWC queue depth with reinit path

 drivers/infiniband/hw/mana/cq.c               |  46 +-
 .../net/ethernet/microsoft/mana/gdma_main.c   |  78 +-
 .../net/ethernet/microsoft/mana/hw_channel.c  | 707 ++++++++++++++++--
 drivers/net/ethernet/microsoft/mana/mana_en.c |  22 +-
 include/net/mana/gdma.h                       |  48 +-
 include/net/mana/hw_channel.h                 |  40 +-
 6 files changed, 849 insertions(+), 92 deletions(-)


base-commit: f6f3b36c15ed44de1fbb44e645e4fae8c4a4453e
-- 
2.43.0


^ permalink raw reply

* [PATCH net-next 1/7] net: mana: RCU-protect gc->cq_table lookups against concurrent CQ destroy
From: Long Li @ 2026-07-15  3:29 UTC (permalink / raw)
  To: Long Li, Konstantin Taranov, Jakub Kicinski, David S . Miller,
	Paolo Abeni, Eric Dumazet, Andrew Lunn, Jason Gunthorpe,
	Leon Romanovsky, Haiyang Zhang, K . Y . Srinivasan, Wei Liu,
	Dexuan Cui, shradhagupta, Simon Horman
  Cc: netdev, linux-rdma, linux-hyperv, linux-kernel
In-Reply-To: <20260715032942.3945317-1-longli@microsoft.com>

The EQ interrupt handler (mana_gd_process_eqe) looks up the completing CQ
in gc->cq_table[cq_id] and runs its callback, concurrently with CQ
teardown on another CPU that clears the slot and frees the CQ.  cq_table
was a plain pointer array freed with no grace period, so the two race
into a use-after-free:

  CPU A (mana_gd_intr, hard IRQ)        CPU B (CQ destroy)
  ----------------------------------    ------------------------------
  cq = gc->cq_table[cq_id];  // valid
                                        gc->cq_table[id] = NULL;
                                        kfree(cq);          // freed
  cq->cq.callback(ctx, cq);  // use-after-free

The handler's existing rcu_read_lock() only guards the per-IRQ EQ list
traversal; cq_table was never under any RCU contract, and a read-side
lock is inert unless the freer also defers the free past a grace period.

Put cq_table under RCU: annotate the base pointer and entries __rcu, read
with rcu_dereference() in the handler, publish with rcu_assign_pointer(),
and on teardown clear the slot then synchronize_rcu() before freeing the
CQ.  The grace period blocks until every in-flight handler has dropped
the old pointer, so the kfree() can no longer race the callback.

Fixes: ca9c54d2d6a5 ("net: mana: Add a driver for Microsoft Azure Network Adapter (MANA)")
Signed-off-by: Long Li <longli@microsoft.com>
---
 drivers/infiniband/hw/mana/cq.c               | 46 ++++++++++++++++---
 .../net/ethernet/microsoft/mana/gdma_main.c   | 25 ++++++++--
 .../net/ethernet/microsoft/mana/hw_channel.c  | 29 ++++++++----
 drivers/net/ethernet/microsoft/mana/mana_en.c | 22 +++++++--
 include/net/mana/gdma.h                       | 21 ++++++++-
 5 files changed, 119 insertions(+), 24 deletions(-)

diff --git a/drivers/infiniband/hw/mana/cq.c b/drivers/infiniband/hw/mana/cq.c
index f2547989f422..2bf4be21cede 100644
--- a/drivers/infiniband/hw/mana/cq.c
+++ b/drivers/infiniband/hw/mana/cq.c
@@ -131,12 +131,20 @@ static void mana_ib_cq_handler(void *ctx, struct gdma_queue *gdma_cq)
 int mana_ib_install_cq_cb(struct mana_ib_dev *mdev, struct mana_ib_cq *cq)
 {
 	struct gdma_context *gc = mdev_to_gc(mdev);
+	struct gdma_queue __rcu **cq_table;
 	struct gdma_queue *gdma_cq;
 
-	if (cq->queue.id >= gc->max_num_cqs)
+	/* No rcu_read_lock(): install/remove run within the IB device
+	 * lifetime, which mana_rdma_remove() (ib_unregister_device) drains
+	 * before the base cq_table can be freed.  See gdma_context::cq_table
+	 * in gdma.h for why "true" is sound.
+	 */
+	cq_table = rcu_dereference_protected(gc->cq_table, true);
+	if (!cq_table || cq->queue.id >= gc->max_num_cqs)
 		return -EINVAL;
+
 	/* Create CQ table entry, sharing a CQ between WQs is not supported */
-	if (gc->cq_table[cq->queue.id])
+	if (rcu_access_pointer(cq_table[cq->queue.id]))
 		return -EINVAL;
 	if (cq->queue.kmem)
 		gdma_cq = cq->queue.kmem;
@@ -149,23 +157,49 @@ int mana_ib_install_cq_cb(struct mana_ib_dev *mdev, struct mana_ib_cq *cq)
 	gdma_cq->type = GDMA_CQ;
 	gdma_cq->cq.callback = mana_ib_cq_handler;
 	gdma_cq->id = cq->queue.id;
-	gc->cq_table[cq->queue.id] = gdma_cq;
+	rcu_assign_pointer(cq_table[cq->queue.id], gdma_cq);
 	return 0;
 }
 
 void mana_ib_remove_cq_cb(struct mana_ib_dev *mdev, struct mana_ib_cq *cq)
 {
 	struct gdma_context *gc = mdev_to_gc(mdev);
+	struct gdma_queue __rcu **cq_table;
+	struct gdma_queue *gdma_cq;
 
-	if (cq->queue.id >= gc->max_num_cqs || cq->queue.id == INVALID_QUEUE_ID)
+	if (cq->queue.id == INVALID_QUEUE_ID)
 		return;
 
 	if (cq->queue.kmem)
 	/* Then it will be cleaned and removed by the mana */
 		return;
 
-	kfree(gc->cq_table[cq->queue.id]);
-	gc->cq_table[cq->queue.id] = NULL;
+	/* No rcu_read_lock(): like mana_ib_install_cq_cb(), this runs within
+	 * the IB device lifetime that mana_rdma_remove() drains before the
+	 * base cq_table can be freed.  See gdma_context::cq_table in gdma.h.
+	 */
+	cq_table = rcu_dereference_protected(gc->cq_table, true);
+	if (!cq_table || cq->queue.id >= gc->max_num_cqs)
+		return;
+	/* Removers for a given CQ are serialized by the IB core, so the slot
+	 * is read and cleared without rcu_read_lock() or atomicity: a CQ is
+	 * never torn down while a live QP references it (cq->usecnt), nor
+	 * while the QP-create that installed the entry is still running (that
+	 * create holds a reference on the CQ uobject across its error path,
+	 * before usecnt is taken).  Any double-remove is therefore sequential
+	 * -- the later caller sees the NULL stored below and returns.
+	 */
+	gdma_cq = rcu_dereference_protected(cq_table[cq->queue.id], true);
+	if (!gdma_cq)
+		return;  /* already removed by a prior teardown path */
+
+	rcu_assign_pointer(cq_table[cq->queue.id], NULL);
+
+	/* Wait for in-flight EQ handlers that may have loaded the old
+	 * pointer via rcu_dereference() to finish before freeing.
+	 */
+	synchronize_rcu();
+	kfree(gdma_cq);
 }
 
 int mana_ib_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c
index aef3b77229c1..c52ef566dc0c 100644
--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
+++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
@@ -761,6 +761,7 @@ static void mana_gd_process_eqe(struct gdma_queue *eq)
 	union gdma_eqe_info eqe_info;
 	enum gdma_eqe_type type;
 	struct gdma_event event;
+	struct gdma_queue __rcu **cq_table;
 	struct gdma_queue *cq;
 	struct gdma_eqe *eqe;
 	u32 cq_id;
@@ -772,10 +773,11 @@ static void mana_gd_process_eqe(struct gdma_queue *eq)
 	switch (type) {
 	case GDMA_EQE_COMPLETION:
 		cq_id = eqe->details[0] & 0xFFFFFF;
-		if (WARN_ON_ONCE(cq_id >= gc->max_num_cqs))
+		cq_table = rcu_dereference(gc->cq_table);
+		if (WARN_ON_ONCE(cq_id >= gc->max_num_cqs || !cq_table))
 			break;
 
-		cq = gc->cq_table[cq_id];
+		cq = rcu_dereference(cq_table[cq_id]);
 		if (WARN_ON_ONCE(!cq || cq->type != GDMA_CQ || cq->id != cq_id))
 			break;
 
@@ -1082,15 +1084,28 @@ static void mana_gd_create_cq(const struct gdma_queue_spec *spec,
 static void mana_gd_destroy_cq(struct gdma_context *gc,
 			       struct gdma_queue *queue)
 {
+	struct gdma_queue __rcu **cq_table;
 	u32 id = queue->id;
 
-	if (id >= gc->max_num_cqs)
+	/* No rcu_read_lock() here: mana_gd_destroy_cq() runs only on the
+	 * CQ-destroy/teardown path, where the base cq_table is stable.  See
+	 * the lifecycle note on gdma_context::cq_table in gdma.h for why the
+	 * "true" predicate is sound.
+	 */
+	cq_table = rcu_dereference_protected(gc->cq_table, true);
+	if (!cq_table || id >= gc->max_num_cqs)
 		return;
 
-	if (!gc->cq_table[id])
+	if (!rcu_access_pointer(cq_table[id]))
 		return;
 
-	gc->cq_table[id] = NULL;
+	rcu_assign_pointer(cq_table[id], NULL);
+
+	/* Wait for in-flight EQ handlers that may have loaded the old
+	 * pointer via rcu_dereference() to finish before the caller
+	 * frees the CQ memory.
+	 */
+	synchronize_rcu();
 }
 
 int mana_gd_create_hwc_queue(struct gdma_dev *gd,
diff --git a/drivers/net/ethernet/microsoft/mana/hw_channel.c b/drivers/net/ethernet/microsoft/mana/hw_channel.c
index e3c24d50dad0..409e20caeccd 100644
--- a/drivers/net/ethernet/microsoft/mana/hw_channel.c
+++ b/drivers/net/ethernet/microsoft/mana/hw_channel.c
@@ -674,6 +674,7 @@ static int mana_hwc_establish_channel(struct gdma_context *gc, u16 *q_depth,
 	struct gdma_queue *sq = hwc->txq->gdma_wq;
 	struct gdma_queue *eq = hwc->cq->gdma_eq;
 	struct gdma_queue *cq = hwc->cq->gdma_cq;
+	struct gdma_queue __rcu **cq_table;
 	int err;
 
 	init_completion(&hwc->hwc_init_eqe_comp);
@@ -698,11 +699,15 @@ static int mana_hwc_establish_channel(struct gdma_context *gc, u16 *q_depth,
 	if (WARN_ON(cq->id >= gc->max_num_cqs))
 		return -EPROTO;
 
-	gc->cq_table = vcalloc(gc->max_num_cqs, sizeof(struct gdma_queue *));
-	if (!gc->cq_table)
+	cq_table = vcalloc(gc->max_num_cqs, sizeof(*cq_table));
+	if (!cq_table)
 		return -ENOMEM;
 
-	gc->cq_table[cq->id] = cq;
+	rcu_assign_pointer(cq_table[cq->id], cq);
+	/* Publish the fully-initialised table last; pairs with the
+	 * rcu_dereference(gc->cq_table) in mana_gd_process_eqe().
+	 */
+	rcu_assign_pointer(gc->cq_table, cq_table);
 
 	return 0;
 }
@@ -811,6 +816,7 @@ int mana_hwc_create_channel(struct gdma_context *gc)
 void mana_hwc_destroy_channel(struct gdma_context *gc)
 {
 	struct hw_channel_context *hwc = gc->hwc.driver_data;
+	struct gdma_queue __rcu **old_cq_table;
 
 	if (!hwc)
 		return;
@@ -818,10 +824,8 @@ void mana_hwc_destroy_channel(struct gdma_context *gc)
 	/* gc->max_num_cqs is set in mana_hwc_init_event_handler(). If it's
 	 * non-zero, the HWC worked and we should tear down the HWC here.
 	 */
-	if (gc->max_num_cqs > 0) {
+	if (gc->max_num_cqs > 0)
 		mana_smc_teardown_hwc(&gc->shm_channel, false);
-		gc->max_num_cqs = 0;
-	}
 
 	if (hwc->txq)
 		mana_hwc_destroy_wq(hwc, hwc->txq);
@@ -832,6 +836,14 @@ void mana_hwc_destroy_channel(struct gdma_context *gc)
 	if (hwc->cq)
 		mana_hwc_destroy_cq(hwc->gdma_dev->gdma_context, hwc->cq);
 
+	/* Reset only after mana_hwc_destroy_cq() above has run with a valid
+	 * max_num_cqs so mana_gd_destroy_cq() clears the CQ table slot and
+	 * waits out in-flight EQ handlers (synchronize_rcu) before the CQ is
+	 * freed.  Clearing it earlier would make that path early-return and
+	 * skip the slot clear, leaving a dangling cq_table entry.
+	 */
+	gc->max_num_cqs = 0;
+
 	kfree(hwc->caller_ctx);
 	hwc->caller_ctx = NULL;
 
@@ -848,8 +860,9 @@ void mana_hwc_destroy_channel(struct gdma_context *gc)
 	gc->hwc.driver_data = NULL;
 	gc->hwc.gdma_context = NULL;
 
-	vfree(gc->cq_table);
-	gc->cq_table = NULL;
+	old_cq_table = rcu_replace_pointer(gc->cq_table, NULL, true);
+	synchronize_rcu();
+	vfree(old_cq_table);
 }
 
 int mana_hwc_send_request(struct hw_channel_context *hwc, u32 req_len,
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index 89e7f59f635d..05b33a1a374d 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -2637,6 +2637,7 @@ static int mana_create_txq(struct mana_port_context *apc,
 	struct mana_obj_spec cq_spec;
 	struct gdma_queue_spec spec;
 	struct gdma_context *gc;
+	struct gdma_queue __rcu **cq_table;
 	struct mana_txq *txq;
 	struct mana_cq *cq;
 	u32 txq_size;
@@ -2742,12 +2743,18 @@ static int mana_create_txq(struct mana_port_context *apc,
 
 		cq->gdma_id = cq->gdma_cq->id;
 
-		if (WARN_ON(cq->gdma_id >= gc->max_num_cqs)) {
+		/* No rcu_read_lock(): mana_create_txq runs under RTNL during
+		 * netdev bring-up, inside the netdev lifetime that
+		 * mana_remove() drains before the base cq_table can be freed.
+		 * See gdma_context::cq_table in gdma.h for why "true" is sound.
+		 */
+		cq_table = rcu_dereference_protected(gc->cq_table, true);
+		if (WARN_ON(!cq_table || cq->gdma_id >= gc->max_num_cqs)) {
 			err = -EINVAL;
 			goto out;
 		}
 
-		gc->cq_table[cq->gdma_id] = cq->gdma_cq;
+		rcu_assign_pointer(cq_table[cq->gdma_id], cq->gdma_cq);
 
 		mana_create_txq_debugfs(apc, i);
 
@@ -2975,6 +2982,7 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc,
 	struct gdma_queue_spec spec;
 	struct mana_cq *cq = NULL;
 	struct gdma_context *gc;
+	struct gdma_queue __rcu **cq_table;
 	u32 cq_size, rq_size;
 	struct mana_rxq *rxq;
 	int err;
@@ -3064,12 +3072,18 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc,
 	if (err)
 		goto out;
 
-	if (WARN_ON(cq->gdma_id >= gc->max_num_cqs)) {
+	/* No rcu_read_lock(): mana_create_rxq runs under RTNL during netdev
+	 * bring-up, inside the netdev lifetime that mana_remove() drains
+	 * before the base cq_table can be freed.  See gdma_context::cq_table
+	 * in gdma.h for why "true" is sound.
+	 */
+	cq_table = rcu_dereference_protected(gc->cq_table, true);
+	if (WARN_ON(!cq_table || cq->gdma_id >= gc->max_num_cqs)) {
 		err = -EINVAL;
 		goto out;
 	}
 
-	gc->cq_table[cq->gdma_id] = cq->gdma_cq;
+	rcu_assign_pointer(cq_table[cq->gdma_id], cq->gdma_cq);
 
 	netif_napi_add_weight_locked(ndev, &cq->napi, mana_poll, 1);
 
diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h
index 8529cef0d7c4..da52701e7816 100644
--- a/include/net/mana/gdma.h
+++ b/include/net/mana/gdma.h
@@ -430,7 +430,26 @@ struct gdma_context {
 
 	/* This maps a CQ index to the queue structure. */
 	unsigned int		max_num_cqs;
-	struct gdma_queue	**cq_table;
+	/* Both the base pointer and each entry are RCU-managed.  The fast
+	 * path (mana_gd_process_eqe) reads the base via rcu_dereference()
+	 * under rcu_read_lock(), so the table is freed with
+	 * rcu_assign_pointer(NULL) + synchronize_rcu() and an in-flight
+	 * reader can never observe freed memory.
+	 *
+	 * The slow paths -- mana_gd_destroy_cq() and the CQ install/remove
+	 * callers (mana_create_txq/_rxq, mana_ib_install/remove_cq_cb) --
+	 * instead read the base with rcu_dereference_protected(cq_table,
+	 * true).  The bare "true" is justified by teardown ordering, not by
+	 * a lock: the base table is replaced+freed only by
+	 * mana_hwc_destroy_channel() (and the create-time reinit), and every
+	 * teardown path first runs mana_remove() + mana_rdma_remove(), which
+	 * synchronously drain the netdev and the IB device
+	 * (unregister_netdevice / ib_unregister_device) that bound all
+	 * install/remove callers; the reinit case runs before either
+	 * consumer is probed.  So no slow-path caller can run while the base
+	 * table is being freed.
+	 */
+	struct gdma_queue	__rcu * __rcu *cq_table;
 
 	/* Protect eq_test_event and test_event_eq_id  */
 	struct mutex		eq_test_event_mutex;
-- 
2.43.0


^ permalink raw reply related

* [PATCH net-next 2/7] net: mana: fix HWC RQ/SQ buffer size swap
From: Long Li @ 2026-07-15  3:29 UTC (permalink / raw)
  To: Long Li, Konstantin Taranov, Jakub Kicinski, David S . Miller,
	Paolo Abeni, Eric Dumazet, Andrew Lunn, Jason Gunthorpe,
	Leon Romanovsky, Haiyang Zhang, K . Y . Srinivasan, Wei Liu,
	Dexuan Cui, shradhagupta, Simon Horman
  Cc: netdev, linux-rdma, linux-hyperv, linux-kernel
In-Reply-To: <20260715032942.3945317-1-longli@microsoft.com>

The HWC RQ receives responses and the SQ sends requests, but
mana_hwc_init_queues() sized the RQ with max_req_msg_size and the SQ with
max_resp_msg_size -- backwards.  A response larger than the undersized RQ
buffer could overflow it, and mana_hwc_rx_event_handler() recovered the
RX slot index by dividing by the wrong size (max_req_msg_size).

Size the RQ by max_resp_msg_size and the SQ by max_req_msg_size, store
max_resp_msg_size in hw_channel_context, and use it as the RX slot
stride.

Fixes: ca9c54d2d6a5 ("net: mana: Add a driver for Microsoft Azure Network Adapter (MANA)")
Signed-off-by: Long Li <longli@microsoft.com>
---
 drivers/net/ethernet/microsoft/mana/hw_channel.c | 7 ++++---
 include/net/mana/hw_channel.h                    | 1 +
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/microsoft/mana/hw_channel.c b/drivers/net/ethernet/microsoft/mana/hw_channel.c
index 409e20caeccd..3f011ebbe7b3 100644
--- a/drivers/net/ethernet/microsoft/mana/hw_channel.c
+++ b/drivers/net/ethernet/microsoft/mana/hw_channel.c
@@ -263,7 +263,7 @@ static void mana_hwc_rx_event_handler(void *ctx, u32 gdma_rxq_id,
 
 	/* Select the RX work request for virtual address and for reposting. */
 	rq_base_addr = hwc_rxq->msg_buf->mem_info.dma_handle;
-	rx_req_idx = (sge->address - rq_base_addr) / hwc->max_req_msg_size;
+	rx_req_idx = (sge->address - rq_base_addr) / hwc->max_resp_msg_size;
 
 	if (rx_req_idx >= hwc_rxq->msg_buf->num_reqs) {
 		dev_err(hwc->dev, "HWC RX: wrong rx_req_idx=%llu, num_reqs=%u\n",
@@ -733,14 +733,14 @@ static int mana_hwc_init_queues(struct hw_channel_context *hwc, u16 q_depth,
 		goto out;
 	}
 
-	err = mana_hwc_create_wq(hwc, GDMA_RQ, q_depth, max_req_msg_size,
+	err = mana_hwc_create_wq(hwc, GDMA_RQ, q_depth, max_resp_msg_size,
 				 hwc->cq, &hwc->rxq);
 	if (err) {
 		dev_err(hwc->dev, "Failed to create HWC RQ: %d\n", err);
 		goto out;
 	}
 
-	err = mana_hwc_create_wq(hwc, GDMA_SQ, q_depth, max_resp_msg_size,
+	err = mana_hwc_create_wq(hwc, GDMA_SQ, q_depth, max_req_msg_size,
 				 hwc->cq, &hwc->txq);
 	if (err) {
 		dev_err(hwc->dev, "Failed to create HWC SQ: %d\n", err);
@@ -749,6 +749,7 @@ static int mana_hwc_init_queues(struct hw_channel_context *hwc, u16 q_depth,
 
 	hwc->num_inflight_msg = q_depth;
 	hwc->max_req_msg_size = max_req_msg_size;
+	hwc->max_resp_msg_size = max_resp_msg_size;
 
 	return 0;
 out:
diff --git a/include/net/mana/hw_channel.h b/include/net/mana/hw_channel.h
index 16feb39616c1..73671f479399 100644
--- a/include/net/mana/hw_channel.h
+++ b/include/net/mana/hw_channel.h
@@ -181,6 +181,7 @@ struct hw_channel_context {
 
 	u16 num_inflight_msg;
 	u32 max_req_msg_size;
+	u32 max_resp_msg_size;
 
 	u16 hwc_init_q_depth_max;
 	u32 hwc_init_max_req_msg_size;
-- 
2.43.0


^ permalink raw reply related

* [PATCH net-next 3/7] net: mana: free HWC comp_buf after destroying the EQ
From: Long Li @ 2026-07-15  3:29 UTC (permalink / raw)
  To: Long Li, Konstantin Taranov, Jakub Kicinski, David S . Miller,
	Paolo Abeni, Eric Dumazet, Andrew Lunn, Jason Gunthorpe,
	Leon Romanovsky, Haiyang Zhang, K . Y . Srinivasan, Wei Liu,
	Dexuan Cui, shradhagupta, Simon Horman
  Cc: netdev, linux-rdma, linux-hyperv, linux-kernel
In-Reply-To: <20260715032942.3945317-1-longli@microsoft.com>

mana_hwc_destroy_cq() freed hwc_cq->comp_buf before destroying the CQ and
EQ.  comp_buf is dereferenced by mana_hwc_comp_event(), which the EQ
interrupt handler invokes; freeing it while the EQ was still registered
let a late handler touch freed memory.

Destroy the CQ and EQ first -- the EQ teardown deregisters the IRQ and
fences in-flight handlers -- then free comp_buf and hwc_cq.

Fixes: ca9c54d2d6a5 ("net: mana: Add a driver for Microsoft Azure Network Adapter (MANA)")
Signed-off-by: Long Li <longli@microsoft.com>
---
 drivers/net/ethernet/microsoft/mana/hw_channel.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/microsoft/mana/hw_channel.c b/drivers/net/ethernet/microsoft/mana/hw_channel.c
index 3f011ebbe7b3..2239fdeda57c 100644
--- a/drivers/net/ethernet/microsoft/mana/hw_channel.c
+++ b/drivers/net/ethernet/microsoft/mana/hw_channel.c
@@ -384,14 +384,20 @@ static void mana_hwc_comp_event(void *ctx, struct gdma_queue *q_self)
 
 static void mana_hwc_destroy_cq(struct gdma_context *gc, struct hwc_cq *hwc_cq)
 {
-	kfree(hwc_cq->comp_buf);
-
 	if (hwc_cq->gdma_cq)
 		mana_gd_destroy_queue(gc, hwc_cq->gdma_cq);
 
+	/* comp_buf is reached only by mana_hwc_comp_event(), which the
+	 * EQ handler invokes via cq_table[id].  The CQ destroy above
+	 * already cleared that slot and ran synchronize_rcu(), so no
+	 * handler can reach comp_buf once it returns.  Destroying the EQ
+	 * here additionally tears down the IRQ (defense in depth) before
+	 * comp_buf and hwc_cq are freed below.
+	 */
 	if (hwc_cq->gdma_eq)
 		mana_gd_destroy_queue(gc, hwc_cq->gdma_eq);
 
+	kfree(hwc_cq->comp_buf);
 	kfree(hwc_cq);
 }
 
-- 
2.43.0


^ permalink raw reply related

* [PATCH net-next 4/7] net: mana: validate hardware-supplied values in the HWC RX path
From: Long Li @ 2026-07-15  3:29 UTC (permalink / raw)
  To: Long Li, Konstantin Taranov, Jakub Kicinski, David S . Miller,
	Paolo Abeni, Eric Dumazet, Andrew Lunn, Jason Gunthorpe,
	Leon Romanovsky, Haiyang Zhang, K . Y . Srinivasan, Wei Liu,
	Dexuan Cui, shradhagupta, Simon Horman
  Cc: netdev, linux-rdma, linux-hyperv, linux-kernel
In-Reply-To: <20260715032942.3945317-1-longli@microsoft.com>

mana_hwc_rx_event_handler() and mana_hwc_handle_resp() consumed lengths
and indices taken straight from device DMA without validation.  A buggy
firmware or a malicious host (in a confidential VM, where the DMA buffer
is shared) could drive a wrong or reused in-flight request to completion
or index out of bounds.  Validate before use:

  - match the SGE address against the address the driver posted for that
    slot, not just an in-range index -- an in-range but wrong SGE would
    otherwise truncate onto a neighbouring slot and read a stale response;
  - require the response to cover a full gdma_resp_hdr before reading
    hwc_msg_id, so a short response cannot complete a slot with stale
    bytes left by the buffer's previous occupant;
  - bounds-check hwc_msg_id in mana_hwc_handle_resp() before indexing the
    inflight bitmap and caller_ctx;
  - reject a resp_len larger than the RX buffer.

Repost the RX WQE on every validation early-return so a rejected response
does not permanently shrink the posted RQ depth.  The one path that
cannot identify the slot (SGE mismatch) intentionally leaks a single WQE
rather than risk reposting the wrong one.

Fixes: ca9c54d2d6a5 ("net: mana: Add a driver for Microsoft Azure Network Adapter (MANA)")
Signed-off-by: Long Li <longli@microsoft.com>
---
 .../net/ethernet/microsoft/mana/hw_channel.c  | 58 +++++++++++++++++--
 1 file changed, 54 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/microsoft/mana/hw_channel.c b/drivers/net/ethernet/microsoft/mana/hw_channel.c
index 2239fdeda57c..68236727aee8 100644
--- a/drivers/net/ethernet/microsoft/mana/hw_channel.c
+++ b/drivers/net/ethernet/microsoft/mana/hw_channel.c
@@ -83,6 +83,17 @@ static void mana_hwc_handle_resp(struct hw_channel_context *hwc, u32 resp_len,
 	struct hwc_caller_ctx *ctx;
 	int err;
 
+	/* Validate msg_id is in range before using it to index bitmap
+	 * and caller_ctx array.  Malicious firmware could send
+	 * out-of-range msg_id causing out-of-bounds access.
+	 */
+	if (msg_id >= hwc->num_inflight_msg) {
+		dev_err(hwc->dev, "hwc_rx: msg_id %u >= max %u\n",
+			msg_id, hwc->num_inflight_msg);
+		mana_hwc_post_rx_wqe(hwc->rxq, rx_req);
+		return;
+	}
+
 	if (!test_bit(msg_id, hwc->inflight_msg_res.map)) {
 		dev_err(hwc->dev, "hwc_rx: invalid msg_id = %u\n", msg_id);
 		mana_hwc_post_rx_wqe(hwc->rxq, rx_req);
@@ -90,6 +101,18 @@ static void mana_hwc_handle_resp(struct hw_channel_context *hwc, u32 resp_len,
 	}
 
 	ctx = hwc->caller_ctx + msg_id;
+
+	/* Reject responses larger than the RX DMA buffer — the SGE
+	 * limits what hardware can DMA, so an oversized resp_len
+	 * indicates a firmware bug.  Fail rather than silently
+	 * truncating.
+	 */
+	if (resp_len > rx_req->buf_len) {
+		dev_err(hwc->dev, "HWC RX: resp_len %u > buf_len %u\n",
+			resp_len, rx_req->buf_len);
+		resp_len = 0;
+	}
+
 	err = mana_hwc_verify_resp_msg(ctx, resp_msg, resp_len);
 	if (err)
 		goto out;
@@ -261,19 +284,45 @@ static void mana_hwc_rx_event_handler(void *ctx, u32 gdma_rxq_id,
 
 	sge = (struct gdma_sge *)(wqe + 8 + dma_oob->inline_oob_size_div4 * 4);
 
-	/* Select the RX work request for virtual address and for reposting. */
+	/* Recover the originating RX slot from the SGE address.  Of the three
+	 * terms here only sge->address lives in device-accessible RQ memory;
+	 * rq_base_addr and max_resp_msg_size are driver-private constants.  An
+	 * in-range but wrong/unaligned SGE (corrupted WQE, or a malicious host
+	 * in a CVM) would otherwise truncate onto a neighbouring slot, letting
+	 * us read a stale response that could complete the wrong, reused
+	 * in-flight request.  Require the index to be in range AND the address
+	 * to exactly match the value the driver posted for that slot.
+	 */
 	rq_base_addr = hwc_rxq->msg_buf->mem_info.dma_handle;
 	rx_req_idx = (sge->address - rq_base_addr) / hwc->max_resp_msg_size;
 
-	if (rx_req_idx >= hwc_rxq->msg_buf->num_reqs) {
-		dev_err(hwc->dev, "HWC RX: wrong rx_req_idx=%llu, num_reqs=%u\n",
-			rx_req_idx, hwc_rxq->msg_buf->num_reqs);
+	if (rx_req_idx >= hwc_rxq->queue_depth ||
+	    sge->address != (u64)hwc_rxq->msg_buf->reqs[rx_req_idx].buf_sge_addr) {
+		/* Cannot trust which WQE this is, so we cannot safely repost
+		 * it; leak one RX WQE and bail.  This permanently leaks one
+		 * RX WQE but indicates a corrupted SGE from hardware (or host
+		 * tampering), which is an unrecoverable device error.
+		 */
+		dev_err(hwc->dev, "HWC RX: invalid SGE address %llx (idx=%llu)\n",
+			sge->address, rx_req_idx);
 		return;
 	}
 
 	rx_req = &hwc_rxq->msg_buf->reqs[rx_req_idx];
 	resp = (struct gdma_resp_hdr *)rx_req->buf_va;
 
+	/* Validate resp_len covers the response header before reading
+	 * hwc_msg_id.  A short response leaves stale data from the
+	 * previous buffer occupant, which could match a live slot and
+	 * complete the wrong request.
+	 */
+	if (rx_oob->tx_oob_data_size < sizeof(*resp)) {
+		dev_err(hwc->dev, "HWC RX: short resp_len=%u\n",
+			rx_oob->tx_oob_data_size);
+		mana_hwc_post_rx_wqe(hwc_rxq, rx_req);
+		return;
+	}
+
 	/* Read msg_id once from DMA buffer to prevent TOCTOU:
 	 * DMA memory is shared/unencrypted in CVMs - host can
 	 * modify it between reads.
@@ -281,6 +330,7 @@ static void mana_hwc_rx_event_handler(void *ctx, u32 gdma_rxq_id,
 	msg_id = READ_ONCE(resp->response.hwc_msg_id);
 	if (msg_id >= hwc->num_inflight_msg) {
 		dev_err(hwc->dev, "HWC RX: wrong msg_id=%u\n", msg_id);
+		mana_hwc_post_rx_wqe(hwc_rxq, rx_req);
 		return;
 	}
 
-- 
2.43.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox