6.18.42-rc1 review
Subsystems (2)
Greg Kroah-Hartman
maintainerPATCH 530/675 iomap: fix out-of-bounds bitmap_set() with zero-length range
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhang Yi <[email protected]>
commit 9c7d8f7c8994c790fca501dc45ce66e7356cbe05 upstream.
ifs_set_range_dirty() and ifs_set_range_uptodate() compute last_blk as (off + len - 1) >> i_blkbits. When off is 0 and len is 0, the unsigned subtraction underflows to SIZE_MAX, producing a huge last_blk and nr_blks value that causes bitmap_set() to write far beyond the ifs->state allocation.
Regarding ifs_set_range_uptodate(), it is temporarily safe because len cannot be passed in as 0. However, for ifs_set_range_dirty() this is reachable from __iomap_write_end(): when copy_folio_from_iter_atomic() returns 0 (e.g. user buffer fault) and the folio is already uptodate, the guard at the top of __iomap_write_end() does not trigger because !folio_test_uptodate() is false, and iomap_set_range_dirty() is called with copied == 0.
Add a !len guard to both functions before the computation, so that a zero-length range is a no-op.
--- fs/iomap/buffered-io.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-)
fs/iomap/buffered-io.c +14 -8
@@ -47,11 +47,13 @@ static bool ifs_set_range_uptodate(struc struct iomap_folio_state *ifs, size_t off, size_t len) { struct inode *inode = folio->mapping->host; -unsigned int first_blk = off >> inode->i_blkbits; -unsigned int last_blk = (off + len -1 ) >> inode->i_blkbits; -unsigned int nr_blks = last_blk - first_blk +1 ; +unsigned int first_blk, last_blk; -bitmap_set (ifs->state, first_blk, nr_blks); +if (len) { + first_blk = off >> inode->i_blkbits; + last_blk = (off + len -1 ) >> inode->i_blkbits; +bitmap_set (ifs->state, first_blk, last_blk - first_blk +1 ); + }return ifs_is_fully_uptodate (folio, ifs); }
@@ -154,13 +156,17 @@ static void ifs_set_range_dirty(struct f {struct inode *inode = folio->mapping->host;unsigned int blks_per_folio =i_blocks_per_folio (inode, folio); -unsigned int first_blk = (off >> inode->i_blkbits); -unsigned int last_blk = (off + len -1 ) >> inode->i_blkbits; -unsigned int nr_blks = last_blk - first_blk +1 ; +unsigned int first_blk, last_blk;unsigned long flags; +if (!len) +return ; + + first_blk = off >> inode->i_blkbits; + last_blk = (off + len -1 ) >> inode->i_blkbits;spin_lock_irqsave (&ifs->state_lock, flags); -bitmap_set (ifs->state, first_blk + blks_per_folio, nr_blks); +bitmap_set (ifs->state, first_blk + blks_per_folio, + last_blk - first_blk +1 );spin_unlock_irqrestore (&ifs->state_lock, flags); }
Greg Kroah-Hartman
maintainerPATCH 531/675 iommu/vt-d: Disallow SVA if page walk is not coherent
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lu Baolu <[email protected]>
commit 780dfed688622ea01be3c9c2c55eec2207f05e04 upstream.
Hardware implementations report Scalable-Mode Page-walk Coherency Support via the SMPWCS field in the extended capability register. If the hardware does not support page-walk coherency, a clflush is required every time the page table entries (which are walked by the IOMMU hardware) are updated.
In the SVA case, page tables are managed by the CPU mm core, not by the IOMMU driver. Because the IOMMU driver has no way of knowing whether the CPU page table management code has ensured coherency via clflush, the driver must deny SVA if the hardware does not support coherent paging.
--- drivers/iommu/intel/svm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iommu/intel/svm.c +1 -1
@@ -27,7 +27,7 @@void intel_svm_check (struct intel_iommu *iommu) { -if (!pasid_supported (iommu)) +if (!pasid_supported (iommu) || !ecap_smpwc (iommu->ecap))return ; if (cpu_feature_enabled(X86_FEATURE_GBPAGES) &&
Greg Kroah-Hartman
maintainerPATCH 532/675 net: stmmac: intel: skip SerDes reconfig when rate is unchanged
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Markus Breitenberger <[email protected]>
commit 0ab78ead2481adb52f9eb5b403865c529f6f2348 upstream.
intel_mac_finish() is registered as the phylink mac_finish() callback for the Elkhart Lake SGMII ports. phylink calls it at the end of every major link reconfiguration, including the initial one during probe.
The callback selects the PMC ModPHY LCPLL programming for the requested MAC-side interface and then power-cycles the SerDes. On Elkhart Lake that ModPHY is also used by the on-die AHCI SATA PHY. Reapplying the programming during the initial boot-time link-up disturbs the shared analog block while it is still driving SATA, so the SATA link fails to train:
ata1: SATA link down (SStatus 1 SControl 300)
The disk carrying the root filesystem is never detected and the system hangs at rootwait. Ethernet itself comes up normally, which makes the failure look unrelated to the network driver.
Before mac_finish() runs, the legacy SerDes power-up path has already programmed SERDES_GCR0 for the current interface. The 1G and 2.5G ModPHY tables selected by mac_finish() correspond to the SerDes lane rate, so read that rate back from SERDES_GCR0 and skip the PMC reprogramming and SerDes power-cycle when it already matches the selected interface.
This keeps the disruptive reprogramming out of the boot path when the SerDes is configured correctly, while preserving the previous behavior when a real SGMII/1000BASE-X to 2500BASE-X rate change is needed. If the register read fails, reconfigure as before.
--- drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+)
drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c +31 -0
@@ -524,6 +524,32 @@ static int intel_set_reg_access(const streturn ret; } +/* +* Return true if the SerDes lane rate must change to serve @interface. +* If the current rate cannot be determined, reconfigure as before. +*/ +static bool intel_serdes_needs_reconfig (struct stmmac_priv *priv, +struct intel_priv_data *intel_priv, +phy_interface_t interface) +{ +u32 cur_rate, want_rate; +int data; + +if (!intel_priv->mdio_adhoc_addr) +return true; + + data =mdiobus_read (priv->mii, intel_priv->mdio_adhoc_addr, +SERDES_GCR0 ); +if (data <0 ) +return true; + + cur_rate = (data &SERDES_RATE_MASK ) >>SERDES_RATE_PCIE_SHIFT ; + want_rate = interface ==PHY_INTERFACE_MODE_2500BASEX ? +SERDES_RATE_PCIE_GEN2 :SERDES_RATE_PCIE_GEN1 ; + +return cur_rate != want_rate; +} + static int intel_mac_finish(struct net_device *ndev, void *intel_data, unsigned int mode,
@@ -535,6 +561,11 @@ static int intel_mac_finish(struct net_dint max_regs =0 ;int ret =0 ; +if (!intel_serdes_needs_reconfig (priv, intel_priv, interface)) { + priv->plat->phy_interface = interface; +return 0 ; + } + ret =intel_tsn_lane_is_available (ndev, intel_priv);if (ret <0 ) {netdev_info (priv->dev,"No TSN lane available to set the registers.\n" );
Greg Kroah-Hartman
maintainerPATCH 533/675 phonet: pep: fix use-after-free in pep_get_sb()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
commit 0f71f852a96af9685858ce59fda34ecbf85c283d upstream.
pep_get_sb() doesn't consider that pskb_may_pull() might have relocated the skb data, and continue to access the older pointer, causing UAF.
Reproduced under KASAN:
BUG: KASAN: slab-use-after-free in pep_get_sb+0x234/0x3b0 Read of size 1 at addr ff11000105510f50 by task repro/157 pep_get_sb+0x234/0x3b0 pipe_handler_do_rcv+0x5f7/0xa10 pep_do_rcv+0x203/0x410 __sk_receive_skb+0x471/0x4a0 phonet_rcv+0x5b3/0x6c0 __netif_receive_skb+0xcc/0x1d0
Refetch the header with skb_header_pointer() after pskb_may_pull(), so the possibly stale pointer is no longer dereferenced. There are better ways to solve this, but, this is the less instrusive one.
--- net/phonet/pep.c | 2 ++ 1 file changed, 2 insertions(+)
net/phonet/pep.c +2 -0
@@ -55,6 +55,8 @@ static unsigned char *pep_get_sb(struct ph =skb_header_pointer (skb,0 ,2 , &h);if (ph ==NULL || ph->sb_len <2 || !pskb_may_pull (skb, ph->sb_len))return NULL ; +/* pskb_may_pull() may have reallocated the head; refetch ph. */ + ph =skb_header_pointer (skb,0 ,2 , &h); ph->sb_len -=2 ; *ptype = ph->sb_type; *plen = ph->sb_len;
Greg Kroah-Hartman
maintainerPATCH 534/675 vxlan: require CAP_NET_ADMIN in the device netns for changelink
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Doruk Tan Ozturk <[email protected]>
commit 3a61bd9637f3d929aa846e4eb3d98b48c26fcb0e upstream.
A tunnel changelink() operates on at most two netns, dev_net(dev) and the sticky underlay netns vxlan->net. They differ once the device is created in or moved to a netns other than the one the request runs in. The rtnl changelink path checks CAP_NET_ADMIN only against dev_net(dev), so a caller privileged there but not in vxlan->net can rewrite a vxlan device whose underlay lives in vxlan->net.
vxlan_changelink() validates and applies the new configuration against vxlan->net (vxlan_config_validate(vxlan->net, ...)) and can reopen the underlay socket in that netns, so the same reasoning as the tunnel changelink series applies here.
Gate vxlan_changelink() with rtnl_dev_link_net_capable(), at the top of the op before any attribute is parsed, matching ipgre_changelink() and the rest of the "require CAP_NET_ADMIN in the device netns for changelink" series.
Found by 0sec automated security-research tooling (https://0sec.ai).
--- drivers/net/vxlan/vxlan_core.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/vxlan/vxlan_core.c +3 -0
@@ -4415,6 +4415,9 @@ static int vxlan_changelink(struct net_dstruct vxlan_rdst *dst;int err; +if (!rtnl_dev_link_net_capable (dev, vxlan->net)) +return -EPERM ; + dst = &vxlan->default_dst; err =vxlan_nl2conf (tb, data, dev, &conf, true, extack);if (err)
Greg Kroah-Hartman
maintainerPATCH 535/675 net: slip: serialize receive against buffer reallocation
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sungmin Kang <[email protected]>
commit ee7f9bb9320add61f7b367d7e6cd55e3a3a4d65d upstream.
sl_realloc_bufs() replaces rbuff and updates buffsize while holding sl->lock. slip_receive_buf() reads those fields and writes through rbuff without holding the lock.
An MTU change can therefore race with receive processing. An MTU shrink can expose the new smaller rbuff with the old larger bound, causing an out-of-bounds write. A receive callback which already loaded the old rbuff can instead continue writing after that buffer has been freed.
Serialize receive processing with sl_realloc_bufs() by holding sl->lock while consuming each receive batch.
--- drivers/net/slip/slip.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/net/slip/slip.c +4 -0
@@ -693,6 +693,8 @@ static void slip_receive_buf(struct tty_if (!sl || sl->magic !=SLIP_MAGIC || !netif_running (sl->dev))return ; +spin_lock_bh (&sl->lock); +/* Read the characters out of the buffer */ while (count--) {if (fp && *fp++) {
@@ -708,6 +710,8 @@ static void slip_receive_buf(struct tty_#endif slip_unesc (sl, *cp++); } + +spin_unlock_bh (&sl->lock); }/************************************
Greg Kroah-Hartman
maintainerPATCH 536/675 geneve: require CAP_NET_ADMIN in the device netns for changelink
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Doruk Tan Ozturk <[email protected]>
commit 8efb8f8bbb353b8f2fdf4f37534c6d96c9f69e01 upstream.
A tunnel changelink() operates on at most two netns, dev_net(dev) and the sticky underlay netns geneve->net. They differ once the device is created in or moved to a netns other than the one the request runs in. The rtnl changelink path checks CAP_NET_ADMIN only against dev_net(dev), so a caller privileged there but not in geneve->net can rewrite a geneve device whose underlay lives in geneve->net.
geneve_changelink() applies the new configuration against geneve->net:geneve_link_config() and the geneve_quiesce()/geneve_unquiesce() pair reopen the underlay sockets in that netns (geneve_sock_add() uses geneve->net), so the same reasoning as the tunnel changelink series applies here.
Gate geneve_changelink() with rtnl_dev_link_net_capable(), at the top of the op before any attribute is parsed, matching ipgre_changelink() and the rest of the "require CAP_NET_ADMIN in the device netns for changelink" series.
Found by 0sec automated security-research tooling (https://0sec.ai).
--- drivers/net/geneve.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/geneve.c +3 -0
@@ -1736,6 +1736,9 @@ static int geneve_changelink(struct net_struct geneve_config cfg;int err; +if (!rtnl_dev_link_net_capable (dev, geneve->net)) +return -EPERM ; +/* If the geneve device is configured for metadata (or externally * controlled, for example, OVS), then nothing can be changed. */
Greg Kroah-Hartman
maintainerPATCH 537/675 net/af_iucv: fix NULL deref in afiucv_hs_callback_syn()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hidayath Khan <[email protected]>
commit 47a5116e56a6b6fe1e909f244e39cd0fc26ceee4 upstream.
afiucv_hs_callback_syn() allocates the child socket with GFP_ATOMIC. If the allocation fails, nsk is NULL.
The connection-refused path is entered when the listen state check fails, the accept backlog is full, or nsk is NULL. The code unconditionally calls iucv_sock_kill(nsk) in that path.
iucv_sock_kill() does not accept a NULL socket pointer and immediately dereferences sk via sock_flag(sk, SOCK_ZAPPED). When nsk is NULL, calling iucv_sock_kill(nsk) results in a NULL pointer dereference.
Only call iucv_sock_kill() when a child socket was successfully allocated.
--- net/iucv/af_iucv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/iucv/af_iucv.c +2 -1
@@ -1872,7 +1872,8 @@ static int afiucv_hs_callback_syn(structafiucv_swap_src_dest (skb); trans_hdr->flags =AF_IUCV_FLAG_SYN |AF_IUCV_FLAG_FIN ; err =dev_queue_xmit (skb); -iucv_sock_kill (nsk); +if (nsk) +iucv_sock_kill (nsk);bh_unlock_sock (sk); goto out; }
Greg Kroah-Hartman
maintainerPATCH 538/675 net/iucv: fix use-after-free of a severed iucv_path
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit be7cc4656eb1f54029610e82d1f0fdd3f9b5ec0a upstream.
af_iucv queues not-yet-received message notifications on iucv->message_q, each holding a raw pointer to the connection's iucv_path. When the peer severs the connection, iucv_sever_path() frees that path with iucv_path_free() but leaves the notifications queued. A later recvmsg() drains message_q via iucv_process_message_q() and hands the stale path to message_receive() -- a use-after-free of the freed iucv_path.
Drop the queued notifications when the path is severed; once the path is gone they can no longer be received. This also frees the notifications leaked when a socket is closed with messages still queued.
--- net/iucv/af_iucv.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
net/iucv/af_iucv.c +14 -0
@@ -335,6 +335,7 @@ static void iucv_sever_path(struct sockunsigned char user_data[16 ];struct iucv_sock *iucv =iucv_sk (sk);struct iucv_path *path = iucv->path; +struct sock_msg_q *p, *n;/* Whoever resets the path pointer, must sever and free it. */ if (xchg (&iucv->path,NULL )) {
@@ -346,6 +347,19 @@ static void iucv_sever_path(struct sock }else pr_iucv->path_sever (path,NULL );iucv_path_free (path); + +/* +* Message notifications queued on message_q still reference +* the now freed path; drop them, otherwise a later recvmsg() +* would pass the freed iucv_path to message_receive() via +* iucv_process_message_q(). +*/ +spin_lock_bh (&iucv->message_q.lock); +list_for_each_entry_safe (p, n, &iucv->message_q.list, list) { +list_del (&p->list); +kfree (p); + } +spin_unlock_bh (&iucv->message_q.lock); } }
Greg Kroah-Hartman
maintainerPATCH 539/675 net/mlx5e: Use sender devcom for MPV master-up
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manjunath Patil <[email protected]>
commit e32649b4bad90a6216d8e93cd7dd050af8ac9740 upstream.
After PCIe DPC recovery, mlx5 reloads the affected functions and replays multiport affiliation events. In the reported failure, the first relevant device error was:
pcieport 0000:10:01.1: DPC: containment event
pcieport 0000:10:01.1: PCIe Bus Error: severity=Uncorrected (Fatal)
pcieport 0000:10:01.1: [ 5] SDES (First)
mlx5 recovered the PCI functions and resumed 0000:11:00.1. During that resume, RDMA multiport binding replayed MLX5_DRIVER_EVENT_AFFILIATION_DONE and mlx5e sent MPV_DEVCOM_MASTER_UP. The host then panicked with:
BUG: kernel NULL pointer dereference, address: 0000000000000010 RIP: mlx5_devcom_comp_set_ready+0x5/0x40 [mlx5_core] RDI: 0000000000000000
Call trace included:
mlx5_devcom_comp_set_ready
mlx5e_devcom_event_mpv
mlx5_devcom_send_event
mlx5_ib_bind_slave_port
mlx5r_mp_probe
mlx5_pci_resume
MPV devcom registration publishes mlx5e private data to the component peer list before mlx5e_devcom_init_mpv() stores the returned component device in priv->devcom. A concurrent master-up event can therefore reach a peer whose private data is visible but whose priv->devcom backpointer is still NULL.
MPV_DEVCOM_MASTER_UP already carries the sender/master mlx5e private data as event_data. The ready bit is stored on the shared devcom component, not on an individual peer. Use the sender devcom when marking the MPV component ready.
This preserves the readiness transition while avoiding a NULL dereference of the peer devcom pointer during affiliation replay after PCI error recovery.
--- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/en_main.c +2 -2
@@ -211,11 +211,11 @@ static void mlx5e_disable_async_events(sstatic int mlx5e_devcom_event_mpv (int event,void *my_data,void *event_data) { -struct mlx5e_priv *slave_priv = my_data; +struct mlx5e_priv *master_priv = event_data;switch (event) {case MPV_DEVCOM_MASTER_UP : -mlx5_devcom_comp_set_ready (slave_priv->devcom, true); +mlx5_devcom_comp_set_ready (master_priv->devcom, true);break ;case MPV_DEVCOM_MASTER_DOWN :/* no need for comp set ready false since we unregister after
Greg Kroah-Hartman
maintainerPATCH 540/675 net/x25: fix use-after-free in x25_kill_by_neigh()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Lee <[email protected]>
commit 5499e0602d2faafd42c580d25f615903c3fbe11b upstream.
x25_kill_by_neigh() walks the global X.25 socket list looking for sockets attached to a terminating neighbour. x25_list_lock protects list membership while the lookup is in progress, but it does not pin a socket's lifetime after the lock is dropped.
The function currently drops x25_list_lock before calling lock_sock(s). A concurrent close can run x25_release(), remove the same socket from x25_list, and drop the last socket reference in that window. The neighbour teardown path can then lock or inspect a freed struct sock/struct x25_sock.
Take sock_hold(s) while x25_list_lock still proves that the list entry is live, then drop the temporary reference after the socket has been locked, rechecked, and released. Recheck x25_sk(s)->neighbour after lock_sock(), because another path may have disconnected the socket before this path acquired the socket lock. Restart the list walk after each disconnect because the list lock was dropped and the previous iterator state may no longer be valid.
A QEMU/KASAN run against origin/master reproduced a slab-use-after-free in x25_kill_by_neigh().
--- net/x25/af_x25.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
net/x25/af_x25.c +6 -2
@@ -1772,15 +1772,19 @@ void x25_kill_by_neigh(struct x25_neigh {struct sock *s; +again:write_lock_bh (&x25_list_lock);sk_for_each (s, &x25_list) {if (x25_sk (s)->neighbour == nb) { +sock_hold (s);write_unlock_bh (&x25_list_lock);lock_sock (s); -x25_disconnect (s,ENETUNREACH ,0 ,0 ); +if (x25_sk (s)->neighbour == nb) +x25_disconnect (s,ENETUNREACH ,0 ,0 );release_sock (s); -write_lock_bh (&x25_list_lock); +sock_put (s); + goto again; } }write_unlock_bh (&x25_list_lock);
Greg Kroah-Hartman
maintainerPATCH 541/675 net: gro: fix double aggregation of flush-marked skbs
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shiming Cheng <[email protected]>
commit e751256486d0ded20f5a9f9863467f1dce65142f upstream.
Commit 0ab03f353d36 ("net-gro: Fix GRO flush when receiving a GSO packet.") added a flush check to skb_gro_receive(), but skb_gro_receive_list() lacks the same validation.
As a result, packets marked with NAPI_GRO_CB(skb)->flush may still be re-aggregated.
This allows already-GRO'd packets with existing frag_list to be re-aggregated into a new GRO session, corrupting the frag_list chain structure. When skb_segment() attempts to unpack these malformed packets, it encounters invalid state and triggers a kernel panic.
Scenario (Tethering/Device forwarding):
1. Driver: Generated aggregated packet P1 via LRO with frag_list
2. Dev A: Receives aggregated fraglist packet and flush flag set
3. Dev A: Re-enters GRO, skb_gro_receive_list() is called
4. Missing flush check allows re-aggregation despite flush flag
5. Frag_list chain becomes corrupted (loops or dangling refs)
6. Dev B: TX path calls skb_segment(), crashes on corrupted frag_list
Root cause in skb_segment():
The check at line ~4891:
if (hsize <= 0 && i >= nfrags && skb_headlen(list_skb) &&
(skb_headlen(list_skb) == len || sg)) { When frag_list is corrupted by double aggregation, when list_skb is a NULL pointer from skb->next, skb_headlen(list_skb) dereference NULL/corrupted pointers occurs.
Call Trace: skb_headlen(NULL skb) skb_segment tcp_gso_segment tcp4_gso_segment inet_gso_segment skb_mac_gso_segment __skb_gso_segment skb_gso_segment validate_xmit_skb validate_xmit_skb_list sch_direct_xmit qdisc_restart __qdisc_run qdisc_run net_tx_action
Fix: Add NAPI_GRO_CB(skb)->flush validation to the early-return check in skb_gro_receive_list(), matching the defensive programming pattern of skb_gro_receive().
--- net/core/gro.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
net/core/gro.c +3 -1
@@ -231,7 +231,9 @@ done:int skb_gro_receive_list (struct sk_buff *p,struct sk_buff *skb) { -if (unlikely (p->len + skb->len >=65536 )) +/* make sure to check flush flag and to not merge */ +if (unlikely (p->len + skb->len >=65536 || +NAPI_GRO_CB (skb)->flush))return -E2BIG ;if (!pskb_may_pull (skb,skb_gro_offset (skb))) {
Greg Kroah-Hartman
maintainerPATCH 542/675 net: hip04: fix RX buffer leak on build_skb failure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
commit 14fa65d10f5696b063a7d8d26e8291ea84a2c6ed upstream.
When build_skb() fails in hip04_rx_poll(), the driver jumps to the refill path without releasing the current RX buffer and its DMA mapping. Installing a replacement buffer then overwrites the slot references and leaks both resources.
Keep the current slot intact and return budget so NAPI retries the same buffer. Also free a newly allocated RX fragment when dma_map_single() fails.
This issue was found by an in-house static analysis tool.
--- drivers/net/ethernet/hisilicon/hip04_eth.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/net/ethernet/hisilicon/hip04_eth.c +8 -3
@@ -594,7 +594,11 @@ static int hip04_rx_poll(struct napi_str skb =build_skb (buf, priv->rx_buf_size);if (unlikely (!skb)) {net_dbg_ratelimited ("build_skb failed\n" ); - goto refill; +/* Retain the slot; return budget so NAPI retries this +* buffer. Refill would overwrite rx_buf[]/rx_phys[] +* and leak them. +*/ +return budget; } dma_unmap_single(priv->dev, priv->rx_phys[priv->rx_head],
@@ -622,14 +626,15 @@ static int hip04_rx_poll(struct napi_str rx++; } -refill: buf =netdev_alloc_frag (priv->rx_buf_size);if (!buf) goto done; phys =dma_map_single (priv->dev, buf,RX_BUF_SIZE ,DMA_FROM_DEVICE ); -if (dma_mapping_error (priv->dev, phys)) +if (dma_mapping_error (priv->dev, phys)) { +skb_free_frag (buf); goto done; + } priv->rx_buf[priv->rx_head] = buf; priv->rx_phys[priv->rx_head] = phys;hip04_set_recv_desc (priv, phys);
Greg Kroah-Hartman
maintainerPATCH 543/675 net: pcs: xpcs: fix SGMII state reading
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Coia Prant <[email protected]>
commit def9a4745e105145133e442dd8a1c126caf0f553 upstream.
Commit 2a22b7ae2fa3 ("net: pcs: xpcs: adapt Wangxun NICs for SGMII mode") added a path in xpcs_get_state_c37_sgmii() that reads speed/duplex from BMCR after AN completes. However, BMCR does not reflect the negotiated result on the hardware where this has been tested:
- On RK3568 (MAC side SGMII), BMCR returns a fixed hardware reset value
- Wangxun engineer Jiawen Wu confirmed that on their side, "BMCR looks like it only wants to be return as 0" [0]
The correct information is available in CL37_ANSGM_STS, which contains the actual link status and negotiated speed/duplex.
This bug was previously masked by phylink core, which overrides the PCS link state with the PHY state when a PHY is present:
/* If we have a phy, the "up" state is the union of both the
* PHY and the MAC
*/
if (phy)
link_state.link &= pl->phy_state.link;Thus, when the link is down, the PHY's link_down state is applied on top of whatever the PCS reports, hiding the broken PCS state reading path.
Modify xpcs_get_state_c37_sgmii() to:
1. Read link state from CL37_ANSGM_STS
2. If link is up, report speed/duplex from CL37_ANSGM_STS
3. Remove the broken BMCR reading path entirely
Also properly set state->an_complete to reflect the AN completion status, and clear CL37_ANCMPLT_INTR when link is down to avoid stale state.
[0] https://lore.kernel.org/all/[email protected]/
--- drivers/net/pcs/pcs-xpcs.c | 32 +++++++------------------------- 1 file changed, 7 insertions(+), 25 deletions(-)
drivers/net/pcs/pcs-xpcs.c +7 -25
@@ -958,6 +958,7 @@ static int xpcs_get_state_c37_sgmii(stru/* Reset link_state */ state->link = false; + state->an_complete = false; state->speed =SPEED_UNKNOWN ; state->duplex =DUPLEX_UNKNOWN ; state->pause =0 ;
@@ -969,6 +970,8 @@ static int xpcs_get_state_c37_sgmii(struif (ret <0 )return ret; + state->an_complete = ret &DW_VR_MII_AN_STS_C37_ANCMPLT_INTR ; +if (ret &DW_VR_MII_C37_ANSGM_SP_LNKSTS ) {int speed_value;
@@ -986,34 +989,13 @@ static int xpcs_get_state_c37_sgmii(stru state->duplex =DUPLEX_FULL ; else state->duplex = DUPLEX_HALF; - }else if (ret ==DW_VR_MII_AN_STS_C37_ANCMPLT_INTR ) { -int speed, duplex; - - state->link = true; - - speed =xpcs_read (xpcs,MDIO_MMD_VEND2 ,MII_BMCR ); -if (speed <0 ) -return speed; - speed &=BMCR_SPEED100 |BMCR_SPEED1000 ; -if (speed ==BMCR_SPEED1000 ) - state->speed =SPEED_1000 ; -else if (speed ==BMCR_SPEED100 ) - state->speed =SPEED_100 ; -else if (speed ==0 ) - state->speed =SPEED_10 ; - - duplex =xpcs_read (xpcs,MDIO_MMD_VEND2 ,MII_ADVERTISE ); -if (duplex <0 ) -return duplex; - -if (duplex &ADVERTISE_1000XFULL ) - state->duplex =DUPLEX_FULL ; -else if (duplex &ADVERTISE_1000XHALF ) - state->duplex =DUPLEX_HALF ; +return 0 ; + } +/* Clear AN complete status or interrupt */ +if (state->an_complete)xpcs_write (xpcs,MDIO_MMD_VEND2 ,DW_VR_MII_AN_INTR_STS ,0 ); - }return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 544/675 proc: Fix broken error paths for namespace links
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jann Horn <[email protected]>
commit 425224c2d700391729be7fe6929a88ef4e2d7a4e upstream.
Don't return the return value of down_read_killable() (0) when a ptrace access check fails, return -EACCES as intended.
--- fs/proc/namespaces.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/proc/namespaces.c +3 -1
@@ -46,7 +46,7 @@ static const char *proc_ns_get_link(struconst struct proc_ns_operations *ns_ops =PROC_I (inode)->ns_ops;struct task_struct *task;struct path ns_path; -int error = -EACCES ; +int error;if (!dentry)return ERR_PTR (-ECHILD );
@@ -59,6 +59,7 @@ static const char *proc_ns_get_link(struif (error) goto out_put_task; + error = -EACCES ;if (!ptrace_may_access (task,PTRACE_MODE_READ_FSCREDS )) goto out;
@@ -90,6 +91,7 @@ static int proc_ns_readlink(struct dentrif (res) goto out_put_task; + res = -EACCES ;if (ptrace_may_access (task,PTRACE_MODE_READ_FSCREDS )) { res =ns_get_name (name,sizeof (name), task, ns_ops);if (res >=0 )
Greg Kroah-Hartman
maintainerPATCH 545/675 ptp: ptp_s390: Add missing facility check
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Schnelle <[email protected]>
commit e78f1ac37afcb16cb6fef8a2c92591eab6558956 upstream.
Only register the physical clock when facility 28 is installed and PTFF QAF returns that PTFF QPT is available.
--- drivers/ptp/ptp_s390.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/ptp/ptp_s390.c +5 -1
@@ -107,6 +107,9 @@ static __init int ptp_s390_init(void)if (IS_ERR (ptp_stcke_clock))return PTR_ERR (ptp_stcke_clock); +if (!test_facility (28 ) || !ptff_query (PTFF_QPT )) +return 0 ; + ptp_qpt_clock =ptp_clock_register (&ptp_s390_qpt_info,NULL );if (IS_ERR (ptp_qpt_clock)) {ptp_clock_unregister (ptp_stcke_clock);
@@ -117,7 +120,8 @@ static __init int ptp_s390_init(void) static __exit void ptp_s390_exit(void) { -ptp_clock_unregister (ptp_qpt_clock); +if (ptp_qpt_clock) +ptp_clock_unregister (ptp_qpt_clock);ptp_clock_unregister (ptp_stcke_clock); }
Greg Kroah-Hartman
maintainerPATCH 546/675 ice: fix PTP Call Trace during PTP release
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Greenwalt <[email protected]>
commit f6a7e00b81e35ef1325234925f2fe1e53b466f92 upstream.
If a PF reset occurs when the PTP state is ICE_PTP_UNINIT, then ice_ptp_rebuild() will update the state to ICE_PTP_ERROR. This will result in the following PTP release call trace during driver unload:
kernel BUG at lib/list_debug.c:52!
ice_ptp_release+0x332/0x3c0 [ice]
ice_deinit_features.part.0+0x10e/0x120 [ice]
ice_remove+0x100/0x220 [ice]This was observed when passing PF1 through to a VM. ice_ptp_init() fails because ctrl_pf is NULL and sets the state to ICE_PTP_UNINIT.
Fix by detecting the ICE_PTP_UNINIT state in ice_ptp_rebuild() and returning without error, preventing the invalid state transition to ICE_PTP_ERROR. The only valid path to ICE_PTP_ERROR is from ICE_PTP_RESETTING after a failed rebuild.
--- drivers/net/ethernet/intel/ice/ice_ptp.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/net/ethernet/intel/ice/ice_ptp.c +5 -0
@@ -2994,6 +2994,11 @@ void ice_ptp_rebuild(struct ice_pf *pf,struct ice_ptp *ptp = &pf->ptp;int err; +if (ptp->state ==ICE_PTP_UNINIT ) { +dev_dbg (ice_pf_to_dev (pf),"PTP was not initialized, skipping rebuild\n" ); +return ; + } +if (ptp->state ==ICE_PTP_READY ) {ice_ptp_prepare_for_reset (pf, reset_type); }else if (ptp->state !=ICE_PTP_RESETTING ) {
Greg Kroah-Hartman
maintainerPATCH 547/675 selftests/ftrace: Reset triggers at top level before instance loop
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
commit 1a087033a6bad73b4140020b40e819b0933aafc3 upstream.
When running instance tests, 'ftracetest' creates a new ftrace instance and runs the tests inside it. Before starting each test, it executes 'initialize_system()' to reset the ftrace state to initial-state.
However, since 'initialize_system()' is executed in the context of the instance directory, it only cleans up triggers and filters of that instance.
Any triggers or dynamic events left behind in the top-level instance by previous failed top-level tests, are left completely untouched. These top-level leftovers can cause subsequent instance-based tests to fail or even crash the kernel.
Fix this by executing 'initialize_system()' in the top-level tracing directory once before entering the instance loop.
--- tools/testing/selftests/ftrace/ftracetest | 1 + 1 file changed, 1 insertion(+)
tools/testing/selftests/ftrace/ftracetest +1 -0
@@ -483,6 +483,7 @@ for t in $TEST_CASES; do done # Test on instance loop +(cd $TRACING_DIR; initialize_system) INSTANCE=" (instance) " for t in $TEST_CASES; do test_on_instance $t || continue
Greg Kroah-Hartman
maintainerPATCH 548/675 super: fix emergency thaw deadlock on frozen block devices
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
commit 749d7aa0377aae32af8c0a4ad43371e7bf830ab5 upstream.
do_thaw_all_callback() calls bdev_thaw() while holding sb->s_umount exclusively. If the block device was frozen via bdev_freeze() dropping the last block layer freeze reference calls fs_bdev_thaw() which reacquires s_umount:
do_thaw_all_callback(sb)
super_lock_excl(sb) # holds sb->s_umount
bdev_thaw(sb->s_bdev)
mutex_lock(&bdev->bd_fsfreeze_mutex)
# bd_fsfreeze_count drops 1 -> 0
bd_holder_ops->thaw == fs_bdev_thaw
get_bdev_super(bdev)
bdev_super_lock(bdev, true)
super_lock(sb, true)
down_write(&sb->s_umount) # same task: deadlockThe emergency thaw worker deadlocks against itself holding both s_umount and bd_fsfreeze_mutex. That fscks any subsequent unmount, freeze, or thaw of that filesystem and block device.
[ 81.878470] sysrq: Show Blocked State [ 81.880140] task:kworker/0:1 state:D stack:0 pid:11 tgid:11 ppid:2 task_flags:0x4208060 flags:0x00080000 [ 81.884876] Workqueue: events do_thaw_all [ 81.886656] Call Trace: [ 81.887759] <TASK> [ 81.888763] __schedule+0x579/0x1420 [ 81.890372] schedule+0x3a/0x100 [ 81.891794] schedule_preempt_disabled+0x15/0x30 [ 81.893848] rwsem_down_write_slowpath+0x1ea/0x900 [ 81.895191] ? __pfx_do_thaw_all_callback+0x10/0x10 [ 81.896528] down_write+0xbd/0xc0 [ 81.897505] super_lock+0x91/0x180 [ 81.898457] ? __mutex_lock+0xa99/0x1140 [ 81.900748] ? __mutex_unlock_slowpath+0x1f/0x400 [ 81.902069] bdev_super_lock+0x5b/0x150 [ 81.903132] get_bdev_super+0x10/0x60 [ 81.904042] fs_bdev_thaw+0x23/0xf0 [ 81.904755] bdev_thaw+0x82/0x100 [ 81.905484] do_thaw_all_callback+0x2c/0x50 [ 81.906298] __iterate_supers+0x5d/0x130 [ 81.907067] do_thaw_all+0x20/0x40 [ 81.907739] process_one_work+0x206/0x5e0 [ 81.908545] worker_thread+0x1e2/0x3c0 [ 81.909339] ? __pfx_worker_thread+0x10/0x10 [ 81.910171] kthread+0xf4/0x130 [ 81.910799] ? __pfx_kthread+0x10/0x10 [ 81.911528] ret_from_fork+0x2e2/0x3b0 [ 81.912259] ? __pfx_kthread+0x10/0x10 [ 81.913010] ret_from_fork_asm+0x1a/0x30 [ 81.913806] </TASK>
bdev_super_lock() even documents the violated requirement with lockdep_assert_not_held(&sb->s_umount).
Acquiring bd_fsfreeze_mutex under s_umount also inverts the bd_fsfreeze_mutex vs. s_umount ordering established by bdev_{freeze,thaw}() and can thus ABBA against a concurrent block-layer freeze even when the recursive path isn't hit.
Fix this by not holding s_umount around the bdev_thaw() loop at all. Pin the superblock with an active reference instead as filesystems_freeze_callback() does. The active reference keeps the superblock from being shut down and so ->s_bdev stays valid without holding s_umount. The block-layer-held freeze is dropped by fs_bdev_thaw() with FREEZE_MAY_NEST | FREEZE_HOLDER_USERSPACE exactly as a regular unfreeze would and thaw_super_locked() handles filesystem-level freezes as before.
The emergency thaw path has deadlocked like this in one form or another for a long long time but the current exclusively-held shape dates back to commit [1] where thaw_bdev() already ended in thaw_super() with s_umount held by do_thaw_all_callback().
--- fs/super.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-)
fs/super.c +16 -13
@@ -1139,16 +1139,30 @@ void emergency_remount(void) } } +static inline bool get_active_super (struct super_block *sb) +{ +bool active = false; + +if (super_lock_excl (sb)) { + active =atomic_inc_not_zero (&sb->s_active); +super_unlock_excl (sb); + } +return active; +} +static void do_thaw_all_callback (struct super_block *sb,void *unused) { -if (!super_lock_excl (sb)) +if (!get_active_super (sb))return ; +/* fs_bdev_thaw() acquires s_umount so it must not be held here */ if (IS_ENABLED (CONFIG_BLOCK ))while (sb->s_bdev && !bdev_thaw (sb->s_bdev))pr_warn ("Emergency Thaw on %pg\n" , sb->s_bdev); -thaw_super_locked (sb,FREEZE_HOLDER_USERSPACE ,NULL ); +if (super_lock_excl (sb)) +thaw_super_locked (sb,FREEZE_HOLDER_USERSPACE ,NULL ); +deactivate_super (sb); }static void do_thaw_all (struct work_struct *work)
@@ -1174,17 +1188,6 @@ void emergency_thaw_all(void) } } -static inline bool get_active_super (struct super_block *sb) -{ -bool active = false; - -if (super_lock_excl (sb)) { - active =atomic_inc_not_zero (&sb->s_active); -super_unlock_excl (sb); - } -return active; -} -static const char *filesystems_freeze_ptr ="filesystems_freeze" ;static void filesystems_freeze_callback (struct super_block *sb,void *freeze_all_ptr)
Greg Kroah-Hartman
maintainerPATCH 549/675 rbd: Reset positive result codes to zero in object map update path
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Raphael Zimmer <[email protected]>
commit a6c4250b81bd30beae94e1b7a4b26fa1193ad2e4 upstream.
In a reply message to an RBD request, a positive result code indicates a data payload, which is not allowed for writes. While rbd_osd_req_callback() already resets a positive result code for writes to zero, rbd_object_map_callback() does not. This allows a corrupted reply to an object map update to trigger the rbd_assert(*result < 0) in __rbd_obj_handle_request(). This happens, because rbd_object_map_callback() calls rbd_obj_handle_request() -> __rbd_obj_handle_request() and passes this positive result code. From __rbd_obj_handle_request(), rbd_obj_advance_write() is called, which leaves the positive result code unchanged and returns true. Therefore, the if(done && *result) branch is executed in __rbd_obj_handle_request() and the assertion triggers.
This patch fixes the issue by adjusting the logic in the rbd_object_map_callback() path. A positive result code for an object map update is now reset to zero (similar to rbd_osd_req_callback()), and the message is subsequently handled the same way as if the result code was zero from the beginning. Additionally, a WARN_ON_ONCE() is added for this case.
--- drivers/block/rbd.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/block/rbd.c +6 -1
@@ -1957,10 +1957,15 @@ static int rbd_object_map_update_finish(bool has_current_state;void *p; -if (osd_req->r_result) +if (osd_req->r_result <0 )return osd_req->r_result;/* +* Writes aren't allowed to return a data payload. +*/ +WARN_ON_ONCE (osd_req->r_result >0 ); + +/* * Nothing to do for a snapshot object map. */ if (osd_req->r_num_ops ==1 )
Greg Kroah-Hartman
maintainerPATCH 550/675 smb: client: handle STATUS_STOPPED_ON_SYMLINK responses without a symlink target
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Carl Johnson <[email protected]>
commit 2eb74eef4b7eda8df593d22fb48e94ef959ec8a5 upstream.
The macOS built-in SMB server returns STATUS_STOPPED_ON_SYMLINK for a CREATE on a path whose final component is a symlink, but it does not include a Symbolic Link Error Response in the error data: both ErrorContextCount and ByteCount are zero, so the symlink target is not present in the response at all. Per [MS-SMB2] section 2.2.2 such a response should carry a valid Symbolic Link Error Response, so this is a server bug, but the target can still be retrieved with FSCTL_GET_REPARSE_POINT.
Frame from a capture against macOS 26.5.2 (build 25F84):
SMB2 hdr : Status=0x8000002d STATUS_STOPPED_ON_SYMLINK, Cmd=Create Error Rsp: StructureSize=0x0009
Error Context Count: 0
Byte Count: 0
Error Data: 00
symlink_data() cannot find a struct smb2_symlink_err_rsp in such a response and returns -EINVAL, which parse_create_response() propagates, so smb2_query_path_info() bails out at
if (rc || !data->reparse_point) goto out;
before it can retry with SMB2_OP_GET_REPARSE. stat(), readlink() and ls of any server-side symlink then fail with -EINVAL:
$ ls -la Config l????????? ? ? ? ? ? Config.json $ stat Config/Config.json stat: cannot statx 'Config/Config.json': Invalid argument
A 5.10 client resolves these symlinks correctly against the same server and share, so this is a regression for Apple SMB servers.
Handle it in several places:
- symlink_data() detects the empty response (ErrorContextCount and ByteCount both zero) and returns a distinct -ENODATA, so that "server did not send the target" can be told apart from a genuinely malformed response and only this case is worked around.
- parse_create_response() treats -ENODATA like STATUS_IO_REPARSE_TAG_NOT_HANDLED, which does not carry the target
either: leave the reparse tag unset and clear rc, so the existing SMB2_OP_GET_REPARSE path retrieves the target.
- smb2_query_path_info() only fixes up the symlink target type when the target is already known. SMB2_OP_GET_REPARSE sets data->reparse.tag but does not parse the target out of the reparse buffer; that happens later, in reparse_info_to_fattr(). Without this check smb2_fix_symlink_target_type() is called with a NULL target and returns -EIO. This could not happen with servers that send the target inline and therefore skip SMB2_OP_GET_REPARSE.
- smb2_open_file() maps -ENODATA to -EIO, matching STATUS_IO_REPARSE_TAG_NOT_HANDLED, so its callers retrieve the target with SMB2_OP_GET_REPARSE as well.
Tested on Debian 13, kernel 6.18.38 (armv7), against macOS 26.5.2:
symlinks now resolve, including relative, parent-traversing and directory symlinks, and reads through symlinks succeed.
--- fs/smb/client/smb2file.c | 21 +++++++++++++++++++++ fs/smb/client/smb2inode.c | 23 ++++++++++++++++++++--- 2 files changed, 41 insertions(+), 3 deletions(-)
fs/smb/client/smb2file.c +21 -0
@@ -30,6 +30,19 @@ static struct smb2_symlink_err_rsp *symlu8 *end = (u8 *)err + iov->iov_len;u32 len; +/* +* Per [MS-SMB2] section 2.2.2, a STATUS_STOPPED_ON_SYMLINK response has to +* carry a Symbolic Link Error Response, so ByteCount cannot be zero. Some +* servers (e.g. the macOS built-in SMB server) violate this and return an +* empty error response, with both ErrorContextCount and ByteCount set to +* zero, i.e. without the symlink target. Detect this and return -ENODATA +* so that callers can tell "server did not send the target" apart from a +* malformed response, and retrieve the target with FSCTL_GET_REPARSE_POINT +* instead. +*/ +if (!err->ErrorContextCount && !le32_to_cpu (err->ByteCount)) +return ERR_PTR (-ENODATA ); +if (err->ErrorContextCount) {struct smb2_error_context_rsp *p;
@@ -200,6 +213,14 @@ int smb2_open_file(const unsigned int xi rc =smb2_parse_symlink_response (oparms->cifs_sb, &err_iov, oparms->path, &data->symlink_target); +/* +* If smb2_parse_symlink_response returned -ENODATA then the +* symlink_target was not sent. Treat this as if the SMB2_open() +* failed with STATUS_IO_REPARSE_TAG_NOT_HANDLED status, which is +* indicated by the -EIO errno. +*/ +if (rc == -ENODATA ) + rc = -EIO ;if (!rc) {memset (smb2_data,0 ,sizeof (*smb2_data)); oparms->create_options |=OPEN_REPARSE_POINT ;
fs/smb/client/smb2inode.c +20 -3
@@ -896,9 +896,19 @@ static int parse_create_response(struct rc =smb2_parse_symlink_response (cifs_sb, iov, full_path, &data->symlink_target); -if (rc) +if (rc !=0 && rc != -ENODATA )return rc; - tag =IO_REPARSE_TAG_SYMLINK ; +/* +* -ENODATA means that the response was parsed but did not contain +* the symlink target at all (see symlink_data()). Treat it like +* STATUS_IO_REPARSE_TAG_NOT_HANDLED, which does not contain it +* either: leave the tag unset and clear rc, so that the caller +* retrieves the target with SMB2_OP_GET_REPARSE. +*/ +if (rc == -ENODATA ) + rc =0 ; +else + tag =IO_REPARSE_TAG_SYMLINK ; reparse_point = true;break ;case STATUS_SUCCESS :
@@ -1091,7 +1101,14 @@ int smb2_query_path_info(const unsigned rc = -EOPNOTSUPP ; } -if (data->reparse.tag ==IO_REPARSE_TAG_SYMLINK && !rc) { +/* +* If the symlink was already parsed in create response then it is needed to fix +* its type now (after the second call with OPEN_REPARSE_POINT which filled the +* data->fi.Attributes). If the symlink was not parsed in create response then +* the data->symlink_target was not filled yet and then the type will be fixed +* later after data->symlink_target is filled. +*/ +if (data->reparse.tag ==IO_REPARSE_TAG_SYMLINK && !rc && data->symlink_target) {bool directory =le32_to_cpu (data->fi.Attributes) &ATTR_DIRECTORY ; rc =smb2_fix_symlink_target_type (&data->symlink_target, directory, cifs_sb); }
Greg Kroah-Hartman
maintainerPATCH 551/675 ksmbd: defer destroy_previous_session() until after NTLM authentication
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Montgomery <[email protected]>
commit c74801ee524f477c174a1899782b6c3b6918d407 upstream.
In ntlm_authenticate(), destroy_previous_session() is called using a user pointer resolved from the client-supplied NTLM blob username field before the NTLMv2 response is validated. An authenticated attacker can set the NTLM blob username to match a victim account and set PreviousSessionId to the victim's session ID; destroy_previous_session() destroys the victim's session while ksmbd_decode_ntlmssp_auth_blob() subsequently rejects the request with -EPERM.
Move destroy_previous_session() and the prev_id assignment to after ksmbd_decode_ntlmssp_auth_blob() returns success and use sess->user rather than the pre-authentication lookup result. This matches the ordering already used by krb5_authenticate(), where destroy_previous_session() is called only after ksmbd_krb5_authenticate() returns success.
--- fs/smb/server/smb2pdu.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
fs/smb/server/smb2pdu.c +4 -5
@@ -1492,11 +1492,6 @@ static int ntlm_authenticate(struct ksmbreturn -EPERM ; } -/* Check for previous session */ - prev_id =le64_to_cpu (req->PreviousSessionId); -if (prev_id && prev_id != sess->id) -destroy_previous_session (conn, user, prev_id); -if (sess->state ==SMB2_SESSION_VALID ) {/* * Reuse session if anonymous try to connect
@@ -1534,6 +1529,10 @@ static int ntlm_authenticate(struct ksmb } } + prev_id =le64_to_cpu (req->PreviousSessionId); +if (prev_id && prev_id != sess->id) +destroy_previous_session (conn, sess->user, prev_id); +/* * If session state is SMB2_SESSION_VALID, We can assume * that it is reauthentication. And the user/password
Greg Kroah-Hartman
maintainerPATCH 552/675 gve: fix Rx queue stall on alloc failure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eddie Phillips <[email protected]>
commit b65352a1bac64442ad95e64f385b40ccb9f1b0db upstream.
When the system is under extreme memory pressure, page allocations can fail during the Rx buffer refill loop. If the number of buffers posted to hardware falls below a critical low threshold and the refill loop exits due to allocation failures, the queue can stall:
1. The device drops incoming packets because there are no descriptors.
2. Since no packets are processed, no Rx completions are generated.
3. Because no completions occur, NAPI is never scheduled, preventing the refill loop from running again even after memory is freed.
This results in a permanent queue stall.
Resolve this by introducing a starvation recovery timer for each Rx queue. If the number of buffers posted to hardware falls below a critical low threshold, start a timer to periodically reschedule NAPI. Once NAPI runs and successfully refills the queue above the threshold, the timer is not rescheduled.
The threshold is set to 32 because a single maximum-sized Receive Segment Coalescing (RSC) packet can consume up to 19 descriptors in the Rx path. Lower thresholds (such as 8 or 16) would be insufficient to process a complete maximum-sized RSC packet, risking packet drops or unexpected hardware behavior under memory pressure. Setting the threshold to 32 guarantees a safe margin to handle at least one full RSC packet.
--- drivers/net/ethernet/google/gve/gve.h | 3 ++ drivers/net/ethernet/google/gve/gve_rx_dqo.c | 34 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+)
drivers/net/ethernet/google/gve/gve.h +3 -0
@@ -13,6 +13,7 @@#include <linux/netdevice.h> #include <linux/net_tstamp.h> #include <linux/pci.h> +#include <linux/timer.h> #include <linux/ptp_clock_kernel.h> #include <linux/u64_stats_sync.h> #include <net/page_pool/helpers.h>
@@ -41,6 +42,7 @@/* Interval to schedule a stats report update, 20000ms. */ #define GVE_STATS_REPORT_TIMER_PERIOD 20000 +#define GVE_RX_NAPI_RESCHED_MS 20/* msecs */ /* Numbers of NIC tx/rx stats in stats report. */ #define NIC_TX_STATS_REPORT_NUM 0
@@ -338,6 +340,7 @@ struct gve_rx_ring {struct xdp_rxq_info xdp_rxq;struct xsk_buff_pool *xsk_pool;struct page_frag_cache page_cache;/* Page cache to allocate XDP frames */ +struct timer_list starvation_timer;/* for queue starvation recovery */ };/* A TX desc ring entry */
drivers/net/ethernet/google/gve/gve_rx_dqo.c +34 -0
@@ -18,6 +18,16 @@#include <net/tcp.h> #include <net/xdp_sock_drv.h> +static void gve_rx_starvation_timer (struct timer_list *t) +{ +struct gve_rx_ring *rx =timer_container_of (rx, t, starvation_timer); +struct gve_priv *priv = rx->gve; +struct gve_notify_block *block; + + block = &priv->ntfy_blocks[rx->ntfy_id]; +napi_schedule (&block->napi); +} +static void gve_rx_free_hdr_bufs (struct gve_priv *priv,struct gve_rx_ring *rx) {struct device *hdev = &priv->pdev->dev;
@@ -120,6 +130,7 @@ void gve_rx_stop_ring_dqo(struct gve_priif (rx->dqo.page_pool)page_pool_disable_direct_recycling (rx->dqo.page_pool); +timer_shutdown_sync (&rx->starvation_timer);gve_remove_napi (priv, ntfy_idx);gve_rx_remove_from_block (priv, idx);gve_rx_reset_ring_dqo (priv, idx);
@@ -208,8 +219,10 @@ static int gve_rx_alloc_hdr_bufs(structvoid gve_rx_start_ring_dqo (struct gve_priv *priv,int idx) {int ntfy_idx =gve_rx_idx_to_ntfy (priv, idx); +struct gve_rx_ring *rx = &priv->rx[idx];gve_rx_add_to_block (priv, idx); +timer_setup (&rx->starvation_timer, gve_rx_starvation_timer,0 );gve_add_napi (priv, ntfy_idx, gve_napi_poll_dqo); }
@@ -363,6 +376,7 @@ void gve_rx_post_buffers_dqo(struct gve_struct gve_rx_compl_queue_dqo *complq = &rx->dqo.complq;struct gve_rx_buf_queue_dqo *bufq = &rx->dqo.bufq;struct gve_priv *priv = rx->gve; +u32 num_bufs_avail_to_hw;u32 num_avail_slots;u32 num_full_slots;u32 num_posted =0 ;
@@ -398,6 +412,26 @@ void gve_rx_post_buffers_dqo(struct gve_ } rx->fill_cnt += num_posted; + +/* If the queue has fewer than GVE_RX_BUF_THRESH_DQO descriptors +* visible to the hardware, the hardware is in danger of starving +* and cannot trigger interrupts. +* +* We use a threshold of 32 because a single maximum-sized RSC +* packet can consume up to 19 descriptors in the Rx path. Lower +* thresholds (e.g., 8 or 16) would be unsafe as they could cause +* the device to drop/stall on a maximum-sized RSC packet. +* +* Start the timer to periodically reschedule NAPI and recover. +*/ + num_bufs_avail_to_hw = + ((bufq->tail & ~(GVE_RX_BUF_THRESH_DQO -1 )) - + bufq->head) & bufq->mask; + +if (num_bufs_avail_to_hw <GVE_RX_BUF_THRESH_DQO ) { +mod_timer (&rx->starvation_timer, + jiffies +msecs_to_jiffies (GVE_RX_NAPI_RESCHED_MS )); + } } static void gve_rx_skb_csum(struct sk_buff *skb,
Greg Kroah-Hartman
maintainerPATCH 553/675 ice: reject out-of-range ptype in ice_parser_profile_init
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aleksandr Loktionov <[email protected]>
commit 59abb87159c53605c063f6e2ceb215b5eba43ee6 upstream.
set_bit(rslt->ptype, prof->ptypes) operates on a DECLARE_BITMAP of ICE_FLOW_PTYPE_MAX (1024) bits. Nothing prevents a malicious VF from providing ptype >= 1024 through VIRTCHNL, resulting in a write past the end of the bitmap and a kernel page fault.
Reproduced with a custom kernel module injecting a crafted VIRTCHNL_OP_ADD_RSS_CFG on E810-C QSFP (8086:1592), FW 4.91 0x800214af 1.3909.0, ICE COMMS DDP 1.3.53.0, kernel 7.1.0-rc1.
crash_parser: ice_parser_profile_init @ ffffffffc0d61b60crash_parser: setting ptype=0xffff (max valid=1023)crash_parser: calling ice_parser_profile_init -- expect OOB crash!
BUG: kernel NULL pointer dereference, address: 0000000000000000 Oops: Oops: 0002 [#1] SMP NOPTI CPU: 56 UID: 0 PID: 165011 Comm: insmod Kdump: loaded Tainted: G S U OE 7.1.0-rc1 #1 Hardware name: Intel Corporation S2600BPB/S2600BPB RIP: 0010:ice_parser_profile_init+0x2d/0x1d0 [ice] Call Trace: <TASK> ? __pfx_ice_parser_profile_init+0x10/0x10 [ice] crash_init+0x127/0xff0 [crash_parser] do_one_initcall+0x45/0x310 do_init_module+0x64/0x270 init_module_from_file+0xcc/0xf0 idempotent_init_module+0x17b/0x280 __x64_sys_finit_module+0x6e/0xe0
Bail out early with -EINVAL when ptype is out of range.
--- drivers/net/ethernet/intel/ice/ice_parser.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/ethernet/intel/ice/ice_parser.c +3 -0
@@ -2368,6 +2368,9 @@ int ice_parser_profile_init(struct ice_pu16 proto_off =0 ;u16 off; +if (rslt->ptype >=ICE_FLOW_PTYPE_MAX ) +return -EINVAL ; +memset (prof,0 ,sizeof (*prof));set_bit (rslt->ptype, prof->ptypes);if (blk ==ICE_BLK_SW ) {
Greg Kroah-Hartman
maintainerPATCH 554/675 ice: use READ_ONCE() to access cached PHC time
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sergey Temerkhanov <[email protected]>
commit 2915681b89f817677ab9f1166d95b595bc144f5f upstream.
ptp.cached_phc_time is a 64-bit value updated by a periodic work item on one CPU and read locklessly on another. On 32-bit or non-atomic architectures this can result in a torn read. Use READ_ONCE() to enforce a single atomic load.
--- drivers/net/ethernet/intel/ice/ice_ptp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/intel/ice/ice_ptp.c +1 -1
@@ -350,7 +350,7 @@ static u64 ice_ptp_extend_40b_ts(structreturn 0 ; } -return ice_ptp_extend_32b_ts (pf->ptp.cached_phc_time, +return ice_ptp_extend_32b_ts (READ_ONCE (pf->ptp.cached_phc_time), (in_tstamp >>8 ) & mask); }
Greg Kroah-Hartman
maintainerPATCH 555/675 ila: reload IPv6 header after pskb_may_pull in checksum adjust
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit 92d3817649df2b0b6a008a686c8275c88d7ef594 upstream.
ila_csum_adjust_transport() caches ip6h = ipv6_hdr(skb) before calling pskb_may_pull(). On a non-linear skb whose transport header sits in a page fragment, pskb_may_pull() can call __pskb_pull_tail() / pskb_expand_head() and free the old skb head, leaving ip6h dangling; the following get_csum_diff(ip6h, p) then reads freed memory. ila_update_ipv6_locator() uses ip6h (and the iaddr derived from it) again after the csum-adjust call and additionally writes the new locator through that pointer.
Impact: a remote IPv6 packet routed through a configured ILA csum-adjust-transport route or receive-side mapping triggers a slab-use-after-free in ila_update_ipv6_locator() (KASAN). The route or mapping requires CAP_NET_ADMIN to configure, but trigger packets are unauthenticated once it exists.
Reload ip6h after each pskb_may_pull() in ila_csum_adjust_transport() before the csum-diff read. In ila_update_ipv6_locator() only the ILA_CSUM_ADJUST_TRANSPORT case pulls the skb, so reload ip6h and iaddr in that case alone before the destination-address write; the neutral-map modes never pull and keep their cached pointers.
--- net/ipv6/ila/ila_common.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
net/ipv6/ila/ila_common.c +12 -0
@@ -84,6 +84,7 @@ static void ila_csum_adjust_transport(ststruct tcphdr *th = (struct tcphdr *) (skb_network_header (skb) + nhoff); + ip6h =ipv6_hdr (skb); diff =get_csum_diff (ip6h, p);inet_proto_csum_replace_by_diff (&th->check, skb, diff, true, true);
@@ -95,6 +96,7 @@ static void ila_csum_adjust_transport(st (skb_network_header (skb) + nhoff);if (uh->check || skb->ip_summed ==CHECKSUM_PARTIAL ) { + ip6h =ipv6_hdr (skb); diff =get_csum_diff (ip6h, p);inet_proto_csum_replace_by_diff (&uh->check, skb, diff, true, true);
@@ -109,6 +111,7 @@ static void ila_csum_adjust_transport(ststruct icmp6hdr *ih = (struct icmp6hdr *) (skb_network_header (skb) + nhoff); + ip6h =ipv6_hdr (skb); diff =get_csum_diff (ip6h, p);inet_proto_csum_replace_by_diff (&ih->icmp6_cksum, skb, diff, true, true);
@@ -126,6 +129,15 @@ void ila_update_ipv6_locator(struct sk_bswitch (p->csum_mode) {case ILA_CSUM_ADJUST_TRANSPORT :ila_csum_adjust_transport (skb, p); +/* +* ila_csum_adjust_transport() calls pskb_may_pull(), which can +* reallocate the skb head and leave ip6h (and the iaddr derived +* from it) dangling; reload both before the write below. The +* other csum modes do not pull, so their cached pointers stay +* valid. +*/ + ip6h =ipv6_hdr (skb); + iaddr =ila_a2i (&ip6h->daddr);break ;case ILA_CSUM_NEUTRAL_MAP :if (sir2ila) {
Greg Kroah-Hartman
maintainerPATCH 556/675 mac802154: hold an interface reference across the scan worker
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ibrahim Hashimov <[email protected]>
commit 234e5e898b713bc0b3a631b6f002897f43d046c8 upstream.
mac802154_scan_worker() captures the scanning sub-interface under RCU and then keeps dereferencing sdata->dev after rcu_read_unlock() and outside the rtnl -- in the failure traces, in mac802154_transmit_beacon_req() (skb->dev = sdata->dev), and in the end_scan cleanup. Nothing keeps that netdev alive across the worker iteration.
A concurrent DEL_INTERFACE or PHY removal can unregister the interface once the worker drops the rtnl between its two drv_set_channel() sections. unregister_netdevice() frees the netdev asynchronously from netdev_run_todo() with the rtnl already dropped, so neither holding the rtnl nor the per-PHY IEEE802154_IS_SCANNING flag prevents a stale worker iteration from dereferencing the freed netdev -- a KASAN slab-use-after-free, reachable by racing TRIGGER_SCAN against DEL_INTERFACE (both CAP_NET_ADMIN).
Pin the netdev with netdev_hold() while the RCU read lock is still held, and release it at every worker exit.
--- net/mac802154/scan.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
net/mac802154/scan.c +11 -0
@@ -179,6 +179,7 @@ void mac802154_scan_worker(struct work_senum nl802154_scan_types scan_req_type;struct ieee802154_sub_if_data *sdata;unsigned int scan_duration =0 ; +netdevice_tracker dev_tracker;struct wpan_phy *wpan_phy;u8 scan_req_duration;u8 page, channel;
@@ -209,6 +210,14 @@ void mac802154_scan_worker(struct work_sreturn ; } +/* +* sdata->dev is dereferenced below after rcu_read_unlock() and outside +* the rtnl, and a concurrent DEL_INTERFACE / PHY teardown can free it +* asynchronously from netdev_run_todo(). Pin it with a reference taken +* while the RCU read lock is still held, and drop it at every exit. +*/ +netdev_hold (sdata->dev, &dev_tracker,GFP_ATOMIC ); + wpan_phy = scan_req->wpan_phy; scan_req_type = scan_req->type; scan_req_duration = scan_req->duration;
@@ -262,12 +271,14 @@ void mac802154_scan_worker(struct work_s"Scan page %u channel %u for %ums\n" , page, channel, jiffies_to_msecs(scan_duration));queue_delayed_work (local->mac_wq, &local->scan_work, scan_duration); +netdev_put (sdata->dev, &dev_tracker);return ; end_scan:rtnl_lock ();mac802154_scan_cleanup_locked (local, sdata, false);rtnl_unlock (); +netdev_put (sdata->dev, &dev_tracker); } int mac802154_trigger_scan_locked(struct ieee802154_sub_if_data *sdata,
Greg Kroah-Hartman
maintainerPATCH 557/675 mac802154: llsec: reject frames shorter than the authentication tag
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Doruk Tan Ozturk <[email protected]>
commit fd3a3f28ed60c6af4b2a39933b151d6b27842c3b upstream.
llsec_do_decrypt_auth() computes the associated-data length for the AEAD request as
assoclen += datalen - authlen;
where datalen is the number of bytes after the MAC header and authlen (4, 8 or 16) is the length of the authentication tag. Nothing verifies that the frame actually carries at least authlen payload bytes. A secured frame whose payload is shorter than the tag makes datalen - authlen negative; assoclen is then passed to aead_request_set_ad() as an unsigned value close to 4 GiB, so crypto_aead_decrypt() walks far off the end of the scatterlist that only spans the real frame.
The frame is fully attacker-controlled and reaches this path from any IEEE 802.15.4 peer in radio range. Reject frames whose payload is shorter than the authentication tag before the subtraction.
Dynamically reproduced on a KASAN kernel as a general-protection-fault in the AEAD scatterwalk, and the fix confirmed.
--- net/mac802154/llsec.c | 5 +++++ 1 file changed, 5 insertions(+)
net/mac802154/llsec.c +5 -0
@@ -891,6 +891,11 @@ llsec_do_decrypt_auth(struct sk_buff *sk data =skb_mac_header (skb) + skb->mac_len; datalen =skb_tail_pointer (skb) - data; +if (datalen < authlen) { +kfree_sensitive (req); +return -EBADMSG ; + } +sg_init_one (&sg,skb_mac_header (skb), assoclen + datalen);if (!(hdr->sec.level &IEEE802154_SCF_SECLEVEL_ENC )) {
Greg Kroah-Hartman
maintainerPATCH 558/675 mctp: serial: handle zero-length frames to prevent rx buffer overflow
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Doruk Tan Ozturk <[email protected]>
commit 793b9b729f1e8de57be8c8daf1a9838be96cabed upstream.
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.
Route a zero-length frame straight to STATE_TRAILER instead of STATE_DATA. The trailer/framing bytes are still consumed, and the frame resolves to a zero-length skb that the MCTP core rejects; the parser never enters STATE_DATA with rxlen == 0, so the out-of-bounds write can no longer occur.
KASAN, on a frame of 0x7e 0x01 0x00 followed by data bytes (before this change):
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
v2: route zero-length frames to STATE_TRAILER instead of STATE_ERR so
the trailer/framing bytes are still consumed (Jeremy Kerr).
Found by 0sec automated security-research tooling (https://0sec.ai).
--- drivers/net/mctp/mctp-serial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/mctp/mctp-serial.c +1 -1
@@ -318,7 +318,7 @@ static void mctp_serial_push_header(stru }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 ;
Greg Kroah-Hartman
maintainerPATCH 559/675 openvswitch: fix GSO userspace truncation underflow
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kyle Zeng <[email protected]>
commit 4032f8ed10fcb84d41c508dfb04be96589f78dfe upstream.
OVS_ACTION_ATTR_TRUNC currently stores a delta from the original skb length in OVS_CB(skb)->cutlen. When a later userspace action segments a GSO skb, queue_gso_packets() reuses that delta for each smaller segment. A segment can then reach queue_userspace_packet() with cutlen greater than skb->len, underflowing the length passed to skb_zerocopy().
Store the maximum preserved length instead and bound each consumer against the current skb length. Use U32_MAX as the no-truncation sentinel so the value remains valid if skb geometry changes before a consumer handles it.
--- net/openvswitch/actions.c | 19 +++++++------------ net/openvswitch/datapath.c | 25 ++++++++++++++----------- net/openvswitch/datapath.h | 2 +- net/openvswitch/vport.c | 2 +- 4 files changed, 23 insertions(+), 25 deletions(-)
net/openvswitch/actions.c +7 -12
@@ -836,12 +836,8 @@ static void do_output(struct datapath *du16 mru =OVS_CB (skb)->mru;u32 cutlen =OVS_CB (skb)->cutlen; -if (unlikely (cutlen >0 )) { -if (skb->len - cutlen >ovs_mac_header_len (key)) -pskb_trim (skb, skb->len - cutlen); -else -pskb_trim (skb,ovs_mac_header_len (key)); - } +if (unlikely (cutlen < skb->len)) +pskb_trim (skb,max (cutlen,ovs_mac_header_len (key)));if (likely (!mru || (skb->len <= mru + vport->dev->hard_header_len))) {
@@ -1233,7 +1229,7 @@ static void execute_psample(struct datap psample_group.net =ovs_dp_get_net (dp); md.in_ifindex =OVS_CB (skb)->input_vport->dev->ifindex; - md.trunc_size = skb->len -OVS_CB (skb)->cutlen; + md.trunc_size =min (skb->len,OVS_CB (skb)->cutlen); md.rate_as_probability =1 ; rate =OVS_CB (skb)->probability ?OVS_CB (skb)->probability :U32_MAX ;
@@ -1283,22 +1279,21 @@ static int do_execute_actions(struct dat clone =skb_clone (skb,GFP_ATOMIC );if (clone)do_output (dp, clone, port, key); -OVS_CB (skb)->cutlen =0 ; +OVS_CB (skb)->cutlen =U32_MAX ;break ; }case OVS_ACTION_ATTR_TRUNC : {struct ovs_action_trunc *trunc =nla_data (a); -if (skb->len > trunc->max_len) -OVS_CB (skb)->cutlen = skb->len - trunc->max_len; +OVS_CB (skb)->cutlen = trunc->max_len;break ; }case OVS_ACTION_ATTR_USERSPACE :output_userspace (dp, skb, key, a, attr, len,OVS_CB (skb)->cutlen); -OVS_CB (skb)->cutlen =0 ; +OVS_CB (skb)->cutlen =U32_MAX ;if (nla_is_last (a, rem)) {consume_skb (skb);return 0 ;
@@ -1452,7 +1447,7 @@ static int do_execute_actions(struct datcase OVS_ACTION_ATTR_PSAMPLE :execute_psample (dp, skb, a); -OVS_CB (skb)->cutlen =0 ; +OVS_CB (skb)->cutlen =U32_MAX ;if (nla_is_last (a, rem)) {consume_skb (skb);return 0 ;
net/openvswitch/datapath.c +14 -11
@@ -276,7 +276,7 @@ void ovs_dp_process_packet(struct sk_buf upcall.portid =ovs_vport_find_upcall_portid (p, skb); upcall.mru =OVS_CB (skb)->mru; - error =ovs_dp_upcall (dp, skb, key, &upcall,0 ); + error =ovs_dp_upcall (dp, skb, key, &upcall,U32_MAX );switch (error) {case 0 :case -EAGAIN :
@@ -457,7 +457,8 @@ static int queue_userspace_packet(structstruct sk_buff *nskb =NULL ;struct sk_buff *user_skb =NULL ;/* to be queued to userspace */ struct nlattr *nla; -size_t len; +size_t msg_size; +size_t skb_len;unsigned int hlen;int err, dp_ifindex;u64 hash;
@@ -478,7 +479,8 @@ static int queue_userspace_packet(struct skb = nskb; } -if (nla_attr_size (skb->len) >USHRT_MAX ) { + skb_len =min (skb->len, cutlen); +if (nla_attr_size (skb_len) >USHRT_MAX ) { err = -EFBIG ; goto out; }
@@ -493,13 +495,13 @@ static int queue_userspace_packet(struct* padding logic. Only perform zerocopy if padding is not required. */ if (dp->user_features &OVS_DP_F_UNALIGNED ) - hlen =skb_zerocopy_headlen (skb); + hlen =min (skb_zerocopy_headlen (skb), cutlen);else - hlen = skb->len; + hlen = skb_len; - len =upcall_msg_size (upcall_info, hlen - cutlen, -OVS_CB (skb)->acts_origlen); - user_skb =genlmsg_new (len,GFP_ATOMIC ); + msg_size =upcall_msg_size (upcall_info, hlen, +OVS_CB (skb)->acts_origlen); + user_skb =genlmsg_new (msg_size,GFP_ATOMIC );if (!user_skb) { err = -ENOMEM ; goto out;
@@ -560,7 +562,7 @@ static int queue_userspace_packet(struct }/* Add OVS_PACKET_ATTR_LEN when packet is truncated */ -if (cutlen >0 && +if (skb_len < skb->len &&nla_put_u32 (user_skb,OVS_PACKET_ATTR_LEN , skb->len)) { err = -ENOBUFS ; goto out;
@@ -585,9 +587,9 @@ static int queue_userspace_packet(struct err = -ENOBUFS ; goto out; } - nla->nla_len =nla_attr_size (skb->len - cutlen); + nla->nla_len =nla_attr_size (skb_len); - err =skb_zerocopy (user_skb, skb, skb->len - cutlen, hlen); + err =skb_zerocopy (user_skb, skb, skb_len, hlen);if (err) goto out;
@@ -644,6 +646,7 @@ static int ovs_packet_cmd_execute(struct packet->ignore_df =1 ; }OVS_CB (packet)->mru = mru; +OVS_CB (packet)->cutlen =U32_MAX ;if (a[OVS_PACKET_ATTR_HASH ]) { hash =nla_get_u64 (a[OVS_PACKET_ATTR_HASH ]);
net/openvswitch/datapath.h +1 -1
@@ -118,7 +118,7 @@ struct datapath {* @mru: The maximum received fragement size; 0 if the packet is not * fragmented. * @acts_origlen: The netlink size of the flow actions applied to this skb. -* @cutlen: The number of bytes from the packet end to be removed. +* @cutlen: The number of bytes in the packet to preserve on output. * @probability: The sampling probability that was applied to this skb; 0 means * no sampling has occurred; U32_MAX means 100% probability. * @upcall_pid: Netlink socket PID to use for sending this packet to userspace;
net/openvswitch/vport.c +1 -1
@@ -503,7 +503,7 @@ int ovs_vport_receive(struct vport *vporOVS_CB (skb)->input_vport = vport;OVS_CB (skb)->mru =0 ; -OVS_CB (skb)->cutlen =0 ; +OVS_CB (skb)->cutlen =U32_MAX ;OVS_CB (skb)->probability =0 ;OVS_CB (skb)->upcall_pid =0 ;if (unlikely (dev_net (skb->dev) !=ovs_dp_get_net (vport->dp))) {
Greg Kroah-Hartman
maintainerPATCH 560/675 ovpn: fix peer refcount leak in TCP error paths
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pavitra Jha <[email protected]>
commit 63bbe18fc03062f483c627838a566a707b62da79 upstream.
When either the TCP RX or TX error path calls ovpn_peer_hold() followed by schedule_work(&peer->tcp.defer_del_work), and the work item is already pending from the other path, schedule_work() returns false and the work runs only once. Since ovpn_tcp_peer_del_work() calls ovpn_peer_put() exactly once, the extra reference taken by the losing path is never dropped, leaking the peer object.
The race window:
CPU0 (strparser/RX error): CPU1 (tcp_tx_work/TX error):
ovpn_peer_hold() <- refcnt+1 ovpn_peer_hold() <- refcnt+2
schedule_work() <- queued schedule_work() <- NO-OP
(work already pending)
ovpn_tcp_peer_del_work runs:
ovpn_peer_del()
ovpn_peer_put() <- refcnt+1
<- peer never freedFix by checking the return value of schedule_work() in both paths and calling ovpn_peer_put() to drop the extra reference if the work was already pending. ovpn_peer_hold() is kept unconditional in the TX path as it cannot fail at that point.
--- drivers/net/ovpn/tcp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/net/ovpn/tcp.c +4 -2
@@ -151,7 +151,8 @@ static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff *skb)/* take reference for deferred peer deletion. should never fail */ if (WARN_ON (!ovpn_peer_hold (peer))) goto err_nopeer; -schedule_work (&peer->tcp.defer_del_work); +if (!schedule_work (&peer->tcp.defer_del_work)) +ovpn_peer_put (peer);ovpn_dev_dstats_rx_dropped (peer->ovpn->dev); err_nopeer:kfree_skb (skb);
@@ -283,7 +284,8 @@ static void ovpn_tcp_send_sock(struct ovpn_peer *peer, struct sock *sk)* stream therefore we abort the connection */ ovpn_peer_hold (peer); -schedule_work (&peer->tcp.defer_del_work); +if (!schedule_work (&peer->tcp.defer_del_work)) +ovpn_peer_put (peer);/* we bail out immediately and keep tx_in_progress set * to true. This way we prevent more TX attempts
Signature · 1 line
2.55.0
Greg Kroah-Hartman
maintainerPATCH 561/675 ovpn: hold peer before scheduling keepalive work
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuvam Pandey <[email protected]>
commit a4710ae2e7e322fdaefb4be8604228279cfaf48c upstream.
ovpn_peer_keepalive_send() passes its peer reference to ovpn_xmit_special(), which ultimately drops it. The keepalive scheduler currently queues the work first and takes the reference only after schedule_work() reports that the work was queued.
Once schedule_work() queues the item, another CPU may run the worker before the caller gets to ovpn_peer_hold(). In that case the worker can consume a reference that was not acquired for it, corrupting the peer lifetime accounting.
Take the peer reference before queueing the work and drop it again when the work was already pending.
--- drivers/net/ovpn/peer.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/net/ovpn/peer.c +4 -2
@@ -1280,8 +1280,10 @@ static time64_t ovpn_peer_keepalive_worknetdev_dbg (peer->ovpn->dev,"sending keepalive to peer %u\n" , peer->id); -if (schedule_work (&peer->keepalive_work)) -ovpn_peer_hold (peer); +if (WARN_ON (!ovpn_peer_hold (peer))) +return 0 ; +if (!schedule_work (&peer->keepalive_work)) +ovpn_peer_put (peer); }if (next_run1 < next_run2)
Greg Kroah-Hartman
maintainerPATCH 562/675 pppoe: reload header pointer after dev_hard_header()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Asim Viladi Oglu Manizada <[email protected]>
commit e9c238f6fe42fb1b4dba3a578277de32cb487937 upstream.
pppoe_sendmsg() saves a pointer to the PPPoE header before calling dev_hard_header(). Device header callbacks are allowed to reallocate the skb head, invalidating pointers into it.
This can happen when a send is blocked in copy_from_user() while the first non-Ethernet port is added to an empty team device. The team's delegated GRE header callback then expands the skb head. PPPoE subsequently writes six bytes through the stale pointer into the freed head.
Reload the PPPoE header through the skb's network-header offset after device header creation. pskb_expand_head() updates that offset when it relocates the head.
--- drivers/net/ppp/pppoe.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ppp/pppoe.c +1 -0
@@ -903,6 +903,7 @@ static int pppoe_sendmsg(struct socket *dev_hard_header (skb, dev,ETH_P_PPP_SES , po->pppoe_pa.remote,NULL , total_len); + ph =pppoe_hdr (skb);memcpy (ph, &hdr,sizeof (struct pppoe_hdr )); ph->length =htons (total_len);
Greg Kroah-Hartman
maintainerPATCH 563/675 rtase: Workaround for TX hang caused by hardware packet parsing
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Justin Lai <[email protected]>
commit 1c50efa1faf3a1a96e100b07ec7a2f3164d90bee upstream.
The hardware performs packet parsing before packet transmission. Parsing incomplete IPv4, IPv6, TCP, or UDP headers may trigger a TX hang because the hardware parser expects additional protocol header data that is not present in the packet.
The hardware performs additional PTP parsing on UDP packets identified by destination ports 319/320 at the expected UDP destination port offset.
If such a packet has transport data smaller than RTASE_MIN_PAD_LEN, the hardware parser expects additional packet data and may trigger a TX hang.
To avoid these hardware issues, the driver applies the following workarounds.
Drop malformed packets that may trigger this hardware issue before transmission.
For IPv4 non-initial fragments, the hardware does not check the fragment offset before parsing the expected transport header location. As a result, these packets are still subject to transport header parsing even though they do not contain a transport header. If the transport data is shorter than the minimum transport header required by the hardware parser, pad the transport data to the minimum transport header length required by the hardware parser. Packets that also match the hardware PTP parsing conditions continue to follow the corresponding workaround.
For IPv6 fragmented packets, neither of the above hardware issues occurs because the hardware only continues packet parsing when the IPv6 Base Header Next Header field directly indicates UDP. Packets carrying a Fragment Header do not continue through the subsequent packet parsing stages.
For packets identified for hardware PTP parsing, pad the transport data so it reaches RTASE_MIN_PAD_LEN before transmission.
--- drivers/net/ethernet/realtek/rtase/rtase.h | 8 drivers/net/ethernet/realtek/rtase/rtase_main.c | 197 ++++++++++++++++++++++++ 2 files changed, 205 insertions(+)
drivers/net/ethernet/realtek/rtase/rtase.h +8 -0
@@ -188,6 +188,12 @@ enum rtase_sw_flag_content { RTASE_SWF_MSIX_ENABLED = BIT(2), }; +enum rtase_parse_result { +RTASE_PARSE_OK , +RTASE_PARSE_SKIP , +RTASE_PARSE_DROP , +}; +#define RSVD_MASK 0x3FFFC000struct rtase_tx_desc {
@@ -359,4 +365,6 @@ struct rtase_private {#define RTASE_MSS_MASK GENMASK(28, 18) +#define RTASE_MIN_PAD_LEN 47 +#endif /* RTASE_H */
drivers/net/ethernet/realtek/rtase/rtase_main.c +197 -0
215 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 564/675 tcp: initialize standalone TCP-AO response padding
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yizhou Zhao <[email protected]>
commit e1a9d3cc11829c5414a75eb39c704f461936eb24 upstream.
tcp_v4_send_ack() and tcp_v6_send_response() construct standalone TCP responses with TCP-AO options. The option length carries the actual MAC length, but the TCP header length includes the option rounded up to a four-byte boundary.
tcp_ao_hash_hdr() writes the MAC only. Thus, when the MAC length is not four-byte aligned, the one to three bytes after the MAC are left uninitialized and may be transmitted. For the normal TCP-AO hashing mode, those bytes also have to be initialized before computing the MAC.
Initialize only the alignment padding in the TCP-AO branches, before hashing the header. Use TCPOPT_NOP, as in the normal TCP-AO output path. This avoids adding work to non-AO TCP responses while preserving a valid authenticated header.
--- net/ipv4/tcp_ipv4.c | 3 +++ net/ipv6/tcp_ipv6.c | 2 ++ 2 files changed, 5 insertions(+)
net/ipv4/tcp_ipv4.c +3 -0
@@ -998,6 +998,9 @@ static void tcp_v4_send_ack(const struct key->rcv_next); arg.iov[0 ].iov_len +=tcp_ao_len_aligned (key->ao_key); rep.th.doff = arg.iov[0 ].iov_len /4 ; +memset ((u8 *)&rep.opt[offset] +tcp_ao_maclen (key->ao_key), +TCPOPT_NOP ,tcp_ao_len_aligned (key->ao_key) - +tcp_ao_len (key->ao_key)); tcp_ao_hash_hdr(AF_INET, (char *)&rep.opt[offset], key->ao_key, key->traffic_key,
net/ipv6/tcp_ipv6.c +2 -0
@@ -941,6 +941,8 @@ static void tcp_v6_send_response(const s (tcp_ao_len (key->ao_key) <<16 ) | (key->ao_key->sndid <<8 ) | (key->rcv_next)); +memset ((u8 *)topt +tcp_ao_maclen (key->ao_key),TCPOPT_NOP , +tcp_ao_len_aligned (key->ao_key) -tcp_ao_len (key->ao_key)); tcp_ao_hash_hdr(AF_INET6, (char *)topt, key->ao_key, key->traffic_key,
Greg Kroah-Hartman
maintainerPATCH 565/675 tcp: challenge ACK for non-exact RST in SYN-RECEIVED
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuxiang Yang <[email protected]>
commit a28c4fcbf774e23b4779cae468e3497a5ad1f4a1 upstream.
The SYN-RECEIVED request-socket path in tcp_check_req() accepts an in-window RST without requiring SEG.SEQ to exactly match RCV.NXT. A non-exact RST therefore removes the request instead of eliciting a challenge ACK.
RFC 9293 section 3.10.7.4 applies the RFC 5961 reset check in
SYN-RECEIVED: an exact RST resets the connection, while a non-exact in-window RST must trigger a challenge ACK and be dropped.
Apply that check before the ACK-field validation, following the RFC sequence-number, RST, then ACK processing order. Factor the per-netns challenge ACK quota out of tcp_send_challenge_ack() so request sockets can share it. Use the request socket's send_ack() callback and its own out-of-window ACK timestamp to send and rate-limit the response.
--- include/net/tcp.h | 2 + net/ipv4/tcp_input.c | 56 ++++++++++++++++++++++++++++++++++++----------- net/ipv4/tcp_minisocks.c | 12 +++++++++- 3 files changed, 56 insertions(+), 14 deletions(-)
include/net/tcp.h +2 -0
@@ -1878,6 +1878,8 @@ static inline void tcp_fast_path_check(sbool tcp_oow_rate_limited (struct net *net,const struct sk_buff *skb,int mib_idx,u32 *last_oow_ack_time); +void tcp_reqsk_send_challenge_ack (struct sock *sk,struct sk_buff *skb, +struct request_sock *req);static inline void tcp_mib_init (struct net *net) {
net/ipv4/tcp_input.c +43 -13
79 lines not on this page · raw message
net/ipv4/tcp_minisocks.c +11 -1
@@ -822,7 +822,7 @@ struct sock *tcp_check_req(struct sock ** elsewhere and is checked directly against the child socket rather * than req because user data may have been sent out. */ -if ((flg &TCP_FLAG_ACK ) && !fastopen && +if ((flg &TCP_FLAG_ACK ) && !(flg &TCP_FLAG_RST ) && !fastopen && (TCP_SKB_CB (skb)->ack_seq !=tcp_rsk (req)->snt_isn +1 ))return sk;
@@ -861,6 +861,16 @@ struct sock *tcp_check_req(struct sock * flg &= ~TCP_FLAG_SYN ; } +/* RFC 5961 section 3.2, as clarified by RFC 9293 section +* 3.10.7.4, requires a challenge ACK for a non-exact +* in-window RST in SYN-RECEIVED. +*/ +if ((flg &TCP_FLAG_RST ) && +TCP_SKB_CB (skb)->seq !=tcp_rsk (req)->rcv_nxt) { +tcp_reqsk_send_challenge_ack (sk, skb, req); +return NULL ; + } +/* RFC793: "second check the RST bit" and * "fourth, check the SYN bit" */
Greg Kroah-Hartman
maintainerPATCH 566/675 tipc: clear sock->sk on the failed-insert path in tipc_sk_create()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daehyeon Ko <[email protected]>
commit ba0533fc163f905fe817cfabdf8ed4058da44800 upstream.
When tipc_sk_create() fails to insert the new socket (tipc_sk_insert() returns non-zero), its error path frees the sk with sk_free() but leaves sock->sk pointing at the freed object:
if (tipc_sk_insert(tsk)) {
sk_free(sk);
pr_warn("Socket create failed; port number exhausted\n");
return -EINVAL;
}This is harmless for plain socket(): the syscall layer clears sock->ops before releasing, so tipc_release() is never called. It is not harmless on the accept() path. tipc_accept() creates the pre-allocated child socket with tipc_sk_create(net, new_sock, 0, kern); on failure it leaves new_sock->sk dangling and new_sock->ops non-NULL, and do_accept() then fput()s the new file, so __sock_release() -> tipc_release() runs lock_sock(new_sock->sk) on the freed sk -- a use-after-free write of the sk_lock spinlock.
tipc_release() already guards this exact "failed accept() releases a pre-allocated child" case with "if (sk == NULL) return 0;", but the guard is bypassed because tipc_sk_create() left sock->sk non-NULL (dangling) rather than NULL.
Clear sock->sk on the failed-insert path so the existing tipc_release() NULL check fires and the use-after-free is avoided.
The tipc_sk_insert() failure is reached when the per-netns socket rhashtable hits its max_size (tsk_rht_params.max_size = 1048576, ~2M elements) -- i.e. once a netns holds ~2M TIPC sockets every insert returns -E2BIG.
BUG: KASAN: slab-use-after-free in lock_sock_nested (net/core/sock.c:3839) Write of size 8 at addr ffff8880047cdc38 by task init/1 lock_sock_nested (net/core/sock.c:3839) tipc_release (net/tipc/socket.c:638) __sock_release (net/socket.c:710) sock_close (net/socket.c:1501) __fput (fs/file_table.c:512) Allocated by task 1: sk_alloc (net/core/sock.c:2308) tipc_sk_create (net/tipc/socket.c:487) tipc_accept (net/tipc/socket.c:2744) do_accept (net/socket.c:2034) Freed by task 1: __sk_destruct (net/core/sock.c:2391) tipc_sk_create (net/tipc/socket.c:504) tipc_accept (net/tipc/socket.c:2744) do_accept (net/socket.c:2034)
--- net/tipc/socket.c | 1 + 1 file changed, 1 insertion(+)
net/tipc/socket.c +1 -0
@@ -501,6 +501,7 @@ static int tipc_sk_create(struct net *netipc_set_sk_state (sk,TIPC_OPEN );if (tipc_sk_insert (tsk)) {sk_free (sk); + sock->sk =NULL ;pr_warn ("Socket create failed; port number exhausted\n" );return -EINVAL ; }
Greg Kroah-Hartman
maintainerPATCH 567/675 vsock/virtio: collapse receive queue under memory pressure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stefano Garzarella <[email protected]>
commit 2a12c05aef213ff304ecc9e2f351de20731946b8 upstream.
When many small packets accumulate in the receive queue, the skb overhead can exceed buf_alloc even while the payload is within bounds. This causes virtio_transport_inc_rx_pkt() to reject packets, leading to connection resets during large transfers under backpressure.
The issue was reported by Brien, who has a reproducer, but it is also easily reproducible with iperf-vsock [1] using a small packet size:
iperf3 --vsock -c $CID -l 129
which fails immediately without this patch but with commit 059b7dbd20a6 ("vsock/virtio: fix potential unbounded skb queue").
Inspired by TCP's tcp_collapse() which solves a similar problem, add virtio_transport_collapse_rx_queue() that walks the receive queue and re-copies data into compact linear skbs to reduce the overhead.
The collapse is triggered proactively from when the number of skb queued is close to exceeding the overhead budget.
A pre-scan counts the eligible bytes to size each allocation precisely, avoiding waste for isolated small packets. Partially consumed skbs are kept as-is to preserve buf_used/fwd_cnt accounting, EOM-marked skbs to maintain SEQPACKET message boundaries, and skbs already larger than the collapse target because they already have a good data-to-overhead ratio.
Walking a large queue may take a significant amount of time and cache misses, causing traffic burstiness. To limit this, the collapse stops once enough room is freed for this packet and the next one, but may opportunistically free more to fill each collapsed skb to capacity.
[1] https://github.com/stefano-garzarella/iperf-vsock
--- net/vmw_vsock/virtio_transport_common.c | 165 +++++++++++++++++++++++++++++++- 1 file changed, 164 insertions(+), 1 deletion(-)
net/vmw_vsock/virtio_transport_common.c +164 -1
@@ -26,6 +26,13 @@/* Threshold for detecting small packets to copy */ #define GOOD_COPY_LEN 128 +/* Max payload that can be collapsed into a single linear skb, using the same +* allocation threshold as virtio_vsock_alloc_skb() to avoid adding pressure +* on the page allocator. +*/ +#define MAX_COLLAPSE_LEN \ + SKB_MAX_ORDER(VIRTIO_VSOCK_SKB_HEADROOM, PAGE_ALLOC_COSTLY_ORDER) +static void virtio_transport_cancel_close_work (struct vsock_sock *vsk,bool cancel_timeout);static s64 virtio_transport_has_space (struct virtio_vsock_sock *vvs);
@@ -422,6 +429,145 @@ static int virtio_transport_send_pkt_infreturn ret; } +static bool virtio_transport_can_collapse (struct sk_buff *skb) +{ +/* skbs that are partially consumed, mark a SEQPACKET message boundary, +* or are already large enough should not be collapsed: they either +* need special accounting, carry protocol state, or already have a +* good data-to-overhead ratio. +*/ +if (VIRTIO_VSOCK_SKB_CB (skb)->offset) +return false; +if (le32_to_cpu (virtio_vsock_hdr (skb)->flags) &VIRTIO_VSOCK_SEQ_EOM ) +return false; +if (skb->len >=MAX_COLLAPSE_LEN ) +return false; +return true; +} + +/* Iterate through the packets in the queue starting from the current skb to +* count the number of bytes we can collapse. +*/ +static unsigned int +virtio_transport_collapse_size (struct sk_buff *skb,struct sk_buff_head *queue) +{ +unsigned int target = skb->len -VIRTIO_VSOCK_SKB_CB (skb)->offset; + +while ((skb =skb_peek_next (skb, queue)) && +virtio_transport_can_collapse (skb)) { +unsigned int len = skb->len -VIRTIO_VSOCK_SKB_CB (skb)->offset; + +if (len >MAX_COLLAPSE_LEN - target) +return target; + + target += len; + } + +return target; +} + +/* Called under lock_sock to compact the receive queue by merging small skbs. +* @min_to_free: minimum number of skbs to eliminate from the queue. May free +* more to fill each collapsed skb to capacity. +*/ +static void +virtio_transport_collapse_rx_queue (struct virtio_vsock_sock *vvs, +u32 min_to_free) +{ +struct sk_buff *skb, *next_skb, *new_skb =NULL ; +struct sk_buff_head new_queue; +u32 saved =0 ; + +__skb_queue_head_init (&new_queue); + + skb_queue_walk_safe(&vvs->rx_queue, skb, next_skb) { +struct virtio_vsock_hdr *hdr =virtio_vsock_hdr (skb); +u32 src_off =VIRTIO_VSOCK_SKB_CB (skb)->offset; +u32 src_len = skb->len - src_off; +bool keep; + + keep = !virtio_transport_can_collapse (skb); +if (keep) { +/* Finalize pending collapsed skb to preserve packet +* ordering. +*/ +if (new_skb) { +__skb_queue_tail (&new_queue, new_skb); + new_skb =NULL ; + saved--; + } + goto next; + } + +/* Finalize if this packet won't fit in the remaining tailroom, +* so we can allocate a right-sized new_skb. +*/ +if (new_skb && src_len >skb_tailroom (new_skb)) { +__skb_queue_tail (&new_queue, new_skb); + new_skb =NULL ; + saved--; + } + +if (!new_skb) { +unsigned int alloc_size; + +/* Check after finalizing to opportunistically fill +* each collapsed skb to capacity, merging more skbs +* than strictly required. +*/ +if (saved >= min_to_free) +break ; + + alloc_size =virtio_transport_collapse_size (skb, &vvs->rx_queue); + +/* Only this skb's data is eligible, nothing to merge +* with. Keep as-is. +*/ +if (alloc_size <= src_len) { + keep = true; + goto next; + } + + new_skb =virtio_vsock_alloc_linear_skb (alloc_size + +VIRTIO_VSOCK_SKB_HEADROOM ,GFP_KERNEL ); +if (!new_skb) +break ; + +memcpy (virtio_vsock_hdr (new_skb), hdr, +sizeof (struct virtio_vsock_hdr )); +virtio_vsock_hdr (new_skb)->len =0 ; + } + +/* Cannot fail since src_off/src_len are within bounds, but if +* it does, discard new_skb to avoid queuing corrupted data. +*/ +if (WARN_ON_ONCE (skb_copy_bits (skb, src_off, +skb_put (new_skb, src_len), + src_len))) { +kfree_skb (new_skb); + new_skb =NULL ; +break ; + } + +le32_add_cpu (&virtio_vsock_hdr (new_skb)->len, src_len); +virtio_vsock_hdr (new_skb)->flags |= hdr->flags; + +next: +__skb_unlink (skb, &vvs->rx_queue); +if (keep) { +__skb_queue_tail (&new_queue, skb); + }else { +consume_skb (skb); + saved++; + } + } + +if (new_skb) +__skb_queue_tail (&new_queue, new_skb); + +skb_queue_splice (&new_queue, &vvs->rx_queue); +} +static bool virtio_transport_inc_rx_pkt (struct virtio_vsock_sock *vvs,u32 len) {
@@ -1341,12 +1487,29 @@ virtio_transport_recv_enqueue(struct vso {struct virtio_vsock_sock *vvs = vsk->trans;bool can_enqueue, free_pkt = false; +u32 len, queue_max, queue_len;struct virtio_vsock_hdr *hdr; -u32 len; hdr =virtio_vsock_hdr (skb); len =le32_to_cpu (hdr->len); +/* virtio_transport_inc_rx_pkt() rejects packets when the per-skb +* overhead (skb_queue_len * SKB_TRUESIZE(0)) exceeds buf_alloc. +* Proactively collapse the queue before that happens. +* No rx_lock needed: lock_sock is held by caller, preventing +* concurrent enqueue or dequeue. +*/ + queue_max = vvs->buf_alloc /SKB_TRUESIZE (0 ); + queue_len =skb_queue_len (&vvs->rx_queue); +if (queue_len >= queue_max) { +/* Walking a large queue may take a significant amount of time +* and cache misses, causing traffic burstiness. Limit the +* collapse to freeing room for this packet and the next one. +* It may free more to fill each collapsed skb to capacity. +*/ +virtio_transport_collapse_rx_queue (vvs, queue_len +2 - queue_max); + } +spin_lock_bh (&vvs->rx_lock); can_enqueue =virtio_transport_inc_rx_pkt (vvs, len);
Greg Kroah-Hartman
maintainerPATCH 568/675 vxlan: mdb: Fix source list corruption on a failed replace
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Raphael Tiovalen <[email protected]>
commit dcd9b465965422b9654f6026e8a2fa8984f74c3c upstream.
When replacing the source list of an MDB remote entry, all existing sources are first marked for deletion and vxlan_mdb_remote_srcs_add() is then called to add the new source list. Sources present in the new list have their deletion mark cleared, and any sources left marked afterwards are removed.
If vxlan_mdb_remote_srcs_add() fails partway through, its error path deletes all entries on the remote's source list. That rollback is only correct for its other caller, vxlan_mdb_remote_add(), where the remote was just allocated and the list contains solely entries added during the call. On the replace path the list also holds pre-existing sources, so a failed replace tears them down together with their (S, G) forwarding entries instead of leaving the entry unchanged.
This is reachable from an existing (*, G) remote. An EXCLUDE filter that loses sources starts forwarding traffic that should be blocked, while an INCLUDE filter that loses sources drops traffic that should be forwarded.
Mark entries created during the current pass with a new VXLAN_SGRP_F_NEW flag. On failure, delete only those entries and clear the deletion mark on the pre-existing ones, so a failed replace leaves the source list untouched. Retain the flag until the whole operation succeeds and then clear it. Also stop vxlan_mdb_remote_src_add() from deleting a pre-existing entry it only looked up when adding that entry's forwarding entry fails.
--- drivers/net/vxlan/vxlan_mdb.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-)
drivers/net/vxlan/vxlan_mdb.c +18 -12
@@ -42,6 +42,7 @@ struct vxlan_mdb_remote { };#define VXLAN_SGRP_F_DELETE BIT(0) +#define VXLAN_SGRP_F_NEW BIT(1)struct vxlan_mdb_src_entry {struct hlist_node node;
@@ -844,6 +845,7 @@ vxlan_mdb_remote_src_add(const struct vx ent =vxlan_mdb_remote_src_entry_add (remote, &src->addr);if (!ent)return -ENOMEM ; + ent->flags |=VXLAN_SGRP_F_NEW ; }else if (!(cfg->nlflags &NLM_F_REPLACE )) {NL_SET_ERR_MSG_MOD (extack,"Source entry already exists" );return -EEXIST ;
@@ -853,15 +855,16 @@ vxlan_mdb_remote_src_add(const struct vxif (err) goto err_src_del; -/* Clear flags in case source entry was marked for deletion as part of -* replace flow. +/* Clear the deletion mark so the entry survives the replace sweep. +* The new mark is retained until the whole operation succeeds. */ - ent->flags =0 ; + ent->flags &= ~VXLAN_SGRP_F_DELETE ;return 0 ; err_src_del: -vxlan_mdb_remote_src_entry_del (ent); +if (ent->flags &VXLAN_SGRP_F_NEW ) +vxlan_mdb_remote_src_entry_del (ent);return err; }
@@ -889,11 +892,19 @@ static int vxlan_mdb_remote_srcs_add(con goto err_src_del; } +hlist_for_each_entry (ent, &remote->src_list, node) + ent->flags &= ~VXLAN_SGRP_F_NEW ; +return 0 ; err_src_del: -hlist_for_each_entry_safe (ent, tmp, &remote->src_list, node) -vxlan_mdb_remote_src_del (cfg->vxlan, &cfg->group, remote, ent); +hlist_for_each_entry_safe (ent, tmp, &remote->src_list, node) { +if (ent->flags &VXLAN_SGRP_F_NEW ) +vxlan_mdb_remote_src_del (cfg->vxlan, &cfg->group, remote, + ent); +else + ent->flags &= ~VXLAN_SGRP_F_DELETE ; + }return err; }
@@ -1069,7 +1080,7 @@ vxlan_mdb_remote_srcs_replace(const stru err =vxlan_mdb_remote_srcs_add (cfg, remote, extack);if (err) - goto err_clear_delete; +return err;hlist_for_each_entry_safe (ent, tmp, &remote->src_list, node) {if (ent->flags &VXLAN_SGRP_F_DELETE )
@@ -1078,11 +1089,6 @@ vxlan_mdb_remote_srcs_replace(const stru }return 0 ; - -err_clear_delete: -hlist_for_each_entry (ent, &remote->src_list, node) - ent->flags &= ~VXLAN_SGRP_F_DELETE ; -return err; } static int vxlan_mdb_remote_replace(const struct vxlan_mdb_config *cfg,
Greg Kroah-Hartman
maintainerPATCH 569/675 watchdog: s32g_wdt: remove incorrect options in watchdog_info struct
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ethan Nelson-Moore <[email protected]>
commit 2b37415618bfc6a83d4aceb00fd8d6491096f2ed upstream.
The s32g_wdt driver uses two incorrect constants in the options field of its watchdog_info struct. This bit mask should contain WDIOF_* constants, but the driver uses two WDIOC_* ioctl constants (in addition to correct WDIOF_* constants). This causes many incorrect bits to be set in the bit mask. The functionality indicated by these ioctl constants is supported by all drivers using the watchdog framework, so this patch simply removes them.
--- drivers/watchdog/s32g_wdt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/watchdog/s32g_wdt.c +1 -2
@@ -56,8 +56,7 @@ MODULE_PARM_DESC(early_enable,static const struct watchdog_info s32g_wdt_info = { .identity ="s32g watchdog" , - .options =WDIOF_KEEPALIVEPING |WDIOF_SETTIMEOUT |WDIOF_MAGICCLOSE | -WDIOC_GETTIMEOUT |WDIOC_GETTIMELEFT , + .options =WDIOF_KEEPALIVEPING |WDIOF_SETTIMEOUT |WDIOF_MAGICCLOSE , };static struct s32g_wdt_device *wdd_to_s32g_wdt (struct watchdog_device *wdd)
Signature · 1 line
2.55.0
Greg Kroah-Hartman
maintainerPATCH 570/675 drm/amd/pm: fix amdgpu_pm_info power display units
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Wang <[email protected]>
commit 238baca26a6279e688d1a156bd031390b82eb578 upstream.
amdgpu_pm_info displayed power sensor readings with the wrong fractional unit. It treated the low byte of the raw sensor value as the decimal part of watts, while that field represents milliwatts in the decoded value. As a result, debugfs could report misleading SoC power when the remainder was not already a two-digit centiwatt value.
Example with query = 0x00000354:
raw field value
---------------------
query >> 8 3 W query & 0xff 84 mW decoded power 3084 mW
output value
---------------------
before 3.84 W
after 3.08 W
--- drivers/gpu/drm/amd/pm/amdgpu_pm.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-)
drivers/gpu/drm/amd/pm/amdgpu_pm.c +12 -9
@@ -40,6 +40,8 @@#define DEVICE_ATTR_IS (_name) (attr_id == device_attr_id__##_name) +#define power_2_mwatt (power) (((power) >> 8) * 1000 + ((power) & 0xff)) +struct od_attribute {struct kobj_attribute attribute;struct list_head entry;
@@ -3261,7 +3263,6 @@ static int amdgpu_hwmon_get_power(struct enum amd_pp_sensors sensor) {struct amdgpu_device *adev =dev_get_drvdata (dev); -unsigned int uw;u32 query =0 ;int r;
@@ -3270,9 +3271,7 @@ static int amdgpu_hwmon_get_power(structreturn r;/* convert to microwatts */ - uw = (query >>8 ) *1000000 + (query &0xff ) *1000 ; - -return uw; +return power_2_mwatt (query) *1000 ; } static ssize_t amdgpu_hwmon_show_power_avg(struct device *dev,
@@ -4804,7 +4803,7 @@ static int amdgpu_debugfs_pm_info_pp(str {uint32_t mp1_ver =amdgpu_ip_version (adev,MP1_HWIP ,0 );uint32_t gc_ver =amdgpu_ip_version (adev,GC_HWIP ,0 ); -uint32_t value; +uint32_t value, mwatt, centiwatt;uint64_t value64 =0 ;uint32_t query =0 ;int size;
@@ -4829,17 +4828,21 @@ static int amdgpu_debugfs_pm_info_pp(strseq_printf (m,"\t%u mV (VDDNB)\n" , value); size =sizeof (uint32_t );if (!amdgpu_dpm_read_sensor (adev,AMDGPU_PP_SENSOR_GPU_AVG_POWER , (void *)&query, &size)) { + mwatt =power_2_mwatt (query); + centiwatt =DIV_ROUND_CLOSEST (mwatt,10 );if (adev->flags &AMD_IS_APU ) -seq_printf (m,"\t%u.%02u W (average SoC including CPU)\n" , query >>8 , query &0xff ); +seq_printf (m,"\t%u.%02u W (average SoC including CPU)\n" , centiwatt /100 , centiwatt %100 );else -seq_printf (m,"\t%u.%02u W (average SoC)\n" , query >>8 , query &0xff ); +seq_printf (m,"\t%u.%02u W (average SoC)\n" , centiwatt /100 , centiwatt %100 ); } size =sizeof (uint32_t );if (!amdgpu_dpm_read_sensor (adev,AMDGPU_PP_SENSOR_GPU_INPUT_POWER , (void *)&query, &size)) { + mwatt =power_2_mwatt (query); + centiwatt =DIV_ROUND_CLOSEST (mwatt,10 );if (adev->flags &AMD_IS_APU ) -seq_printf (m,"\t%u.%02u W (current SoC including CPU)\n" , query >>8 , query &0xff ); +seq_printf (m,"\t%u.%02u W (current SoC including CPU)\n" , centiwatt /100 , centiwatt %100 );else -seq_printf (m,"\t%u.%02u W (current SoC)\n" , query >>8 , query &0xff ); +seq_printf (m,"\t%u.%02u W (current SoC)\n" , centiwatt /100 , centiwatt %100 ); } size =sizeof (value);seq_printf (m,"\n" );
Greg Kroah-Hartman
maintainerPATCH 571/675 drm/amd/pm: make pp_features read-only when scpm is enabled
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Wang <[email protected]>
commit 53c78ab388bfc1a4d72e756815d0db0a842c812e upstream.
SCPM owns power feature control when enabled.
Make pp_features read-only during sysfs setup by clearing its write bits and store callback.
--- drivers/gpu/drm/amd/pm/amdgpu_pm.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/gpu/drm/amd/pm/amdgpu_pm.c +5 -0
@@ -2619,6 +2619,11 @@ static int default_attr_update(struct am gc_ver != IP_VERSION(9, 4, 3)) || gc_ver < IP_VERSION(9, 0, 0)) *states =ATTR_STATE_UNSUPPORTED ; + +if (adev->scpm_enabled) { + dev_attr->attr.mode &= ~S_IWUGO ; + dev_attr->store =NULL ; + } }else if (DEVICE_ATTR_IS (gpu_metrics)) {if (gc_ver <IP_VERSION (9 ,1 ,0 )) *states =ATTR_STATE_UNSUPPORTED ;
Greg Kroah-Hartman
maintainerPATCH 572/675 drm/amdgpu/gfx10: replace BUG_ON() with WARN_ON()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit d06c4173a7c38c7a39e98859f839ce714c7af2c9 upstream.
There's no need to crash the kernel for these cases.
--- drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-)
drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +5 -8
@@ -4022,7 +4022,7 @@ static void gfx_v10_0_wait_reg_mem(struc WAIT_REG_MEM_ENGINE(eng_sel)));if (mem_space) -BUG_ON (addr0 &0x3 );/* Dword align */ +WARN_ON (addr0 &0x3 );/* Dword align */ amdgpu_ring_write (ring, addr0);amdgpu_ring_write (ring, addr1);amdgpu_ring_write (ring, ref);
@@ -8674,7 +8674,7 @@ static void gfx_v10_0_ring_emit_ib_gfx(s }amdgpu_ring_write (ring, header); -BUG_ON (ib->gpu_addr &0x3 );/* Dword align */ +WARN_ON (ib->gpu_addr &0x3 );/* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) |
@@ -8709,7 +8709,7 @@ static void gfx_v10_0_ring_emit_ib_compu }amdgpu_ring_write (ring,PACKET3 (PACKET3_INDIRECT_BUFFER ,2 )); -BUG_ON (ib->gpu_addr &0x3 );/* Dword align */ +WARN_ON (ib->gpu_addr &0x3 );/* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) |
@@ -8742,9 +8742,9 @@ static void gfx_v10_0_ring_emit_fence(st* aligned if only send 32bit data low (discard data high) */ if (write64bit) -BUG_ON (addr &0x7 ); +WARN_ON (addr &0x7 );else -BUG_ON (addr &0x3 ); +WARN_ON (addr &0x3 );amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));amdgpu_ring_write (ring,lower_32_bits (seq));
@@ -8792,9 +8792,6 @@ static void gfx_v10_0_ring_emit_fence_ki {struct amdgpu_device *adev = ring->adev; -/* we only allocate 32bit for each seq wb address */ -BUG_ON (flags &AMDGPU_FENCE_FLAG_64BIT ); -/* write fence seq to the "addr" */ amdgpu_ring_write (ring,PACKET3 (PACKET3_WRITE_DATA ,3 )); amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
Greg Kroah-Hartman
maintainerPATCH 573/675 drm/amdgpu/gfx11: replace BUG_ON() with WARN_ON()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit 0eebcab1ea2a77f086a04108f386f82ee3496022 upstream.
There's no need to crash the kernel for these cases.
--- drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-)
drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +5 -8
@@ -537,7 +537,7 @@ static void gfx_v11_0_wait_reg_mem(struc WAIT_REG_MEM_ENGINE(eng_sel)));if (mem_space) -BUG_ON (addr0 &0x3 );/* Dword align */ +WARN_ON (addr0 &0x3 );/* Dword align */ amdgpu_ring_write (ring, addr0);amdgpu_ring_write (ring, addr1);amdgpu_ring_write (ring, ref);
@@ -5901,7 +5901,7 @@ static void gfx_v11_0_ring_emit_ib_gfx(s }amdgpu_ring_write (ring, header); -BUG_ON (ib->gpu_addr &0x3 );/* Dword align */ +WARN_ON (ib->gpu_addr &0x3 );/* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) |
@@ -5936,7 +5936,7 @@ static void gfx_v11_0_ring_emit_ib_compu }amdgpu_ring_write (ring,PACKET3 (PACKET3_INDIRECT_BUFFER ,2 )); -BUG_ON (ib->gpu_addr &0x3 );/* Dword align */ +WARN_ON (ib->gpu_addr &0x3 );/* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) |
@@ -5969,9 +5969,9 @@ static void gfx_v11_0_ring_emit_fence(st* aligned if only send 32bit data low (discard data high) */ if (write64bit) -BUG_ON (addr &0x7 ); +WARN_ON (addr &0x7 );else -BUG_ON (addr &0x3 ); +WARN_ON (addr &0x3 );amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));amdgpu_ring_write (ring,lower_32_bits (seq));
@@ -6025,9 +6025,6 @@ static void gfx_v11_0_ring_emit_fence_ki {struct amdgpu_device *adev = ring->adev; -/* we only allocate 32bit for each seq wb address */ -BUG_ON (flags &AMDGPU_FENCE_FLAG_64BIT ); -/* write fence seq to the "addr" */ amdgpu_ring_write (ring,PACKET3 (PACKET3_WRITE_DATA ,3 )); amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
Greg Kroah-Hartman
maintainerPATCH 574/675 drm/amdgpu/gfx12: replace BUG_ON() with WARN_ON()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit cd3b3efa1ced05528d9128755338baa62a6b562d upstream.
There's no need to crash the kernel for these cases.
--- drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-)
drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c +5 -8
@@ -439,7 +439,7 @@ static void gfx_v12_0_wait_reg_mem(struc WAIT_REG_MEM_ENGINE(eng_sel)));if (mem_space) -BUG_ON (addr0 &0x3 );/* Dword align */ +WARN_ON (addr0 &0x3 );/* Dword align */ amdgpu_ring_write (ring, addr0);amdgpu_ring_write (ring, addr1);amdgpu_ring_write (ring, ref);
@@ -4424,7 +4424,7 @@ static void gfx_v12_0_ring_emit_ib_gfx(s control |= ib->length_dw | (vmid <<24 );amdgpu_ring_write (ring, header); -BUG_ON (ib->gpu_addr &0x3 );/* Dword align */ +WARN_ON (ib->gpu_addr &0x3 );/* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) |
@@ -4443,7 +4443,7 @@ static void gfx_v12_0_ring_emit_ib_compuu32 control =INDIRECT_BUFFER_VALID | ib->length_dw | (vmid <<24 );amdgpu_ring_write (ring,PACKET3 (PACKET3_INDIRECT_BUFFER ,2 )); -BUG_ON (ib->gpu_addr &0x3 );/* Dword align */ +WARN_ON (ib->gpu_addr &0x3 );/* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) |
@@ -4474,9 +4474,9 @@ static void gfx_v12_0_ring_emit_fence(st* aligned if only send 32bit data low (discard data high) */ if (write64bit) -BUG_ON (addr &0x7 ); +WARN_ON (addr &0x7 );else -BUG_ON (addr &0x3 ); +WARN_ON (addr &0x3 );amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));amdgpu_ring_write (ring,lower_32_bits (seq));
@@ -4524,9 +4524,6 @@ static void gfx_v12_0_ring_emit_fence_ki {struct amdgpu_device *adev = ring->adev; -/* we only allocate 32bit for each seq wb address */ -BUG_ON (flags &AMDGPU_FENCE_FLAG_64BIT ); -/* write fence seq to the "addr" */ amdgpu_ring_write (ring,PACKET3 (PACKET3_WRITE_DATA ,3 )); amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
Greg Kroah-Hartman
maintainerPATCH 575/675 drm/amdgpu/gfx8: drop unecessary BUG_ON()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit 84a1a8a952ab4b8c23c5dd1f2eea4049cb4914f5 upstream.
There's no need to crash the kernel for this case.
--- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 3 --- 1 file changed, 3 deletions(-)
drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +0 -3
@@ -6226,9 +6226,6 @@ static void gfx_v8_0_ring_emit_fence_comstatic void gfx_v8_0_ring_emit_fence_kiq (struct amdgpu_ring *ring,u64 addr,u64 seq,unsigned int flags) { -/* we only allocate 32bit for each seq wb address */ -BUG_ON (flags &AMDGPU_FENCE_FLAG_64BIT ); -/* write fence seq to the "addr" */ amdgpu_ring_write (ring,PACKET3 (PACKET3_WRITE_DATA ,3 )); amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
Greg Kroah-Hartman
maintainerPATCH 576/675 drm/amdgpu/gfx9.4.3: replace BUG_ON() with WARN_ON()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit 00f4050f7c367d7bdce347ca279ce467c434cf15 upstream.
There's no need to crash the kernel for these cases.
--- drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)
drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c +4 -7
@@ -405,7 +405,7 @@ static void gfx_v9_4_3_wait_reg_mem(stru WAIT_REG_MEM_ENGINE(eng_sel)));if (mem_space) -BUG_ON (addr0 &0x3 );/* Dword align */ +WARN_ON (addr0 &0x3 );/* Dword align */ amdgpu_ring_write (ring, addr0);amdgpu_ring_write (ring, addr1);amdgpu_ring_write (ring, ref);
@@ -2871,7 +2871,7 @@ static void gfx_v9_4_3_ring_emit_ib_comp }amdgpu_ring_write (ring,PACKET3 (PACKET3_INDIRECT_BUFFER ,2 )); -BUG_ON (ib->gpu_addr &0x3 );/* Dword align */ +WARN_ON (ib->gpu_addr &0x3 );/* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) |
@@ -2905,9 +2905,9 @@ static void gfx_v9_4_3_ring_emit_fence(s* aligned if only send 32bit data low (discard data high) */ if (write64bit) -BUG_ON (addr &0x7 ); +WARN_ON (addr &0x7 );else -BUG_ON (addr &0x3 ); +WARN_ON (addr &0x3 );amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));amdgpu_ring_write (ring,lower_32_bits (seq));
@@ -2967,9 +2967,6 @@ static void gfx_v9_4_3_ring_emit_fence_k {struct amdgpu_device *adev = ring->adev; -/* we only allocate 32bit for each seq wb address */ -BUG_ON (flags &AMDGPU_FENCE_FLAG_64BIT ); -/* write fence seq to the "addr" */ amdgpu_ring_write (ring,PACKET3 (PACKET3_WRITE_DATA ,3 )); amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
Greg Kroah-Hartman
maintainerPATCH 577/675 drm/amdgpu/gfx9: replace BUG_ON() with WARN_ON()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit 6302be10b521f5106ce01eb5a724b9e7945a5061 upstream.
There's no need to crash the kernel for these cases.
--- drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +5 -5
@@ -1183,7 +1183,7 @@ static void gfx_v9_0_wait_reg_mem(struct WAIT_REG_MEM_ENGINE(eng_sel)));if (mem_space) -BUG_ON (addr0 &0x3 );/* Dword align */ +WARN_ON (addr0 &0x3 );/* Dword align */ amdgpu_ring_write (ring, addr0);amdgpu_ring_write (ring, addr1);amdgpu_ring_write (ring, ref);
@@ -5473,7 +5473,7 @@ static void gfx_v9_0_ring_emit_ib_gfx(st }amdgpu_ring_write (ring, header); -BUG_ON (ib->gpu_addr &0x3 );/* Dword align */ +WARN_ON (ib->gpu_addr &0x3 );/* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) |
@@ -5569,7 +5569,7 @@ static void gfx_v9_0_ring_emit_ib_comput }amdgpu_ring_write (ring,PACKET3 (PACKET3_INDIRECT_BUFFER ,2 )); -BUG_ON (ib->gpu_addr &0x3 );/* Dword align */ +WARN_ON (ib->gpu_addr &0x3 );/* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) |
@@ -5610,9 +5610,9 @@ static void gfx_v9_0_ring_emit_fence(str* aligned if only send 32bit data low (discard data high) */ if (write64bit) -BUG_ON (addr &0x7 ); +WARN_ON (addr &0x7 );else -BUG_ON (addr &0x3 ); +WARN_ON (addr &0x3 );amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));amdgpu_ring_write (ring,lower_32_bits (seq));
Greg Kroah-Hartman
maintainerPATCH 578/675 drm/amdgpu/jpeg: fix jpeg_v4_0_3_is_idle detection
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Boyuan Zhang <[email protected]>
commit c44af3810fc8b3adf6910a332038aa566560c8fa upstream.
jpeg_v4_0_3_is_idle() initializes ret to false and then accumulates ring idle status using &=. Since false & condition always remains false, the function can never report the JPEG block as idle.
Initialize ret to true so the function returns true only when all JPEG rings report RB_JOB_DONE.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c +1 -1
@@ -1010,7 +1010,7 @@ void jpeg_v4_0_3_dec_ring_nop(struct amdstatic bool jpeg_v4_0_3_is_idle (struct amdgpu_ip_block *ip_block) {struct amdgpu_device *adev = ip_block->adev; -bool ret = false; +bool ret = true;int i, j;for (i =0 ; i < adev->jpeg.num_jpeg_inst; ++i) {
Greg Kroah-Hartman
maintainerPATCH 579/675 drm/amdgpu/jpeg: fix jpeg_v5_0_1_is_idle detection
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Boyuan Zhang <[email protected]>
commit efcedeececcf995fcf717b21e39aa7c446fa3bf7 upstream.
jpeg_v5_0_1_is_idle() initializes ret to false and then accumulates ring idle status using &=. Since false & condition always remains false, the function can never report the JPEG block as idle.
Initialize ret to true so the function returns true only when all JPEG rings report RB_JOB_DONE.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c +1 -1
@@ -657,7 +657,7 @@ static void jpeg_v5_0_1_dec_ring_set_wptstatic bool jpeg_v5_0_1_is_idle (struct amdgpu_ip_block *ip_block) {struct amdgpu_device *adev = ip_block->adev; -bool ret = false; +bool ret = true;int i, j;for (i =0 ; i < adev->jpeg.num_jpeg_inst; ++i) {
Greg Kroah-Hartman
maintainerPATCH 580/675 drm/amdgpu/sdma4.4.2: replace BUG_ON() with WARN_ON()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit 40cdbe9fa424cc6264a7aed93a04bd7d69109d9e upstream.
There's no need to crash the kernel for these cases.
--- drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c +2 -2
@@ -458,7 +458,7 @@ static void sdma_v4_4_2_ring_emit_fence(/* write the fence */ amdgpu_ring_write (ring,SDMA_PKT_HEADER_OP (SDMA_OP_FENCE ));/* zero in first two bits */ -BUG_ON (addr &0x3 ); +WARN_ON (addr &0x3 );amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));amdgpu_ring_write (ring,lower_32_bits (seq));
@@ -468,7 +468,7 @@ static void sdma_v4_4_2_ring_emit_fence( addr +=4 ;amdgpu_ring_write (ring,SDMA_PKT_HEADER_OP (SDMA_OP_FENCE ));/* zero in first two bits */ -BUG_ON (addr &0x3 ); +WARN_ON (addr &0x3 );amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (seq));
Greg Kroah-Hartman
maintainerPATCH 581/675 drm/amdgpu/soc24: reset dGPU if suspend got aborted
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jakob Linke <[email protected]>
commit aff079bdce65f6d085e4b0091fdf87fffa95b0d9 upstream.
For SOC24 ASICs (RDNA4 / Navi 4x dGPUs) re-enabling PM features fails if an S3 suspend got aborted, the same issue already handled for SOC21 and SOC15:
commit df3c7dc5c58b ("drm/amdgpu: Reset dGPU if suspend got aborted") commit 38e8ca3e4b6d ("amdgpu/soc15: enable asic reset for dGPU in case of suspend abort")
The aborted resume fails with:
amdgpu: SMU: No response msg_reg: 6 resp_reg: 0
amdgpu: Failed to enable requested dpm features!
amdgpu: resume of IP block <smu> failed -62
Apply the same workaround for soc24: detect the aborted-suspend state at resume via the sign-of-life register and reset the device before re-init.
This is a workaround till a proper solution is finalized.
--- drivers/gpu/drm/amd/amdgpu/soc24.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+)
drivers/gpu/drm/amd/amdgpu/soc24.c +28 -0
@@ -526,8 +526,36 @@ static int soc24_common_suspend(struct areturn soc24_common_hw_fini (ip_block); } +static bool soc24_need_reset_on_resume (struct amdgpu_device *adev) +{ +u32 sol_reg1, sol_reg2; + +/* Will reset for the following suspend abort cases. +* 1) Only reset dGPU side. +* 2) S3 suspend got aborted and TOS is active. +* As for dGPU suspend abort cases the SOL value +* will be kept as zero at this resume point. +*/ +if (!(adev->flags &AMD_IS_APU ) && adev->in_s3) { + sol_reg1 =RREG32_SOC15 (MP0 ,0 , regMPASP_SMN_C2PMSG_81); +msleep (100 ); + sol_reg2 =RREG32_SOC15 (MP0 ,0 , regMPASP_SMN_C2PMSG_81); + +return (sol_reg1 != sol_reg2); + } + +return false; +} +static int soc24_common_resume (struct amdgpu_ip_block *ip_block) { +struct amdgpu_device *adev = ip_block->adev; + +if (soc24_need_reset_on_resume (adev)) { +dev_info (adev->dev,"S3 suspend aborted, resetting..." ); +soc24_asic_reset (adev); + } +return soc24_common_hw_init (ip_block); }
Greg Kroah-Hartman
maintainerPATCH 582/675 drm/amdgpu/vce: fix integer overflow in image size
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Boyuan Zhang <[email protected]>
commit 186bfdc4e26d019b2e7570cb121964a1d89b2e5b upstream.
Fix a security vulnerability where malicious VCE command streams with oversized dimensions (e.g. 65536×65536) cause 32-bit integer overflow, wrapping the calculated buffer size to 0. This bypasses validation and allows GPU firmware to perform out-of-bound memory access.
The fix uses 64-bit arithmetic to detect overflow and rejects invalid dimensions before they reach the hardware.
V2: remove redundant check
V3: modify max height value
V4: remove size64
--- drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +14 -3
@@ -853,9 +853,20 @@ int amdgpu_vce_ring_parse_cs(struct amdg goto out; } - *size =amdgpu_ib_get_value (ib, idx +8 ) * -amdgpu_ib_get_value (ib, idx +10 ) * -8 *3 /2 ; +uint32_t width, height; + width =amdgpu_ib_get_value (ib, idx +8 ); + height =amdgpu_ib_get_value (ib, idx +10 ); + +if (width ==0 || height ==0 || + width >4096 || height >2304 ) { +DRM_ERROR ("invalid VCE image size: %ux%u\n" , + width, height); + r = -EINVAL ; + goto out; + } + + *size = width * height *8 *3 /2 ; +break ;case 0x04000001 :/* config extension */
Greg Kroah-Hartman
maintainerPATCH 583/675 drm/amdgpu/vcn4: avoid rereading IB param length
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Boyuan Zhang <[email protected]>
commit 3b4082fabc67c9780b06eb959e59dd92fa79c0f0 upstream.
Reuse the parameter length returned by vcn_v4_0_enc_find_ib_param() instead of rereading it from the IB.
This avoids a potential TOCTOU issue if the IB contents change between reads.
--- drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +9 -6
@@ -1926,14 +1926,17 @@ out:#define RENCODE_IB_PARAM_SESSION_INIT 0x00000003/* return the offset in ib if id is found, -1 otherwise */ -static int vcn_v4_0_enc_find_ib_param (struct amdgpu_ib *ib,uint32_t id,int start) +static int vcn_v4_0_enc_find_ib_param (struct amdgpu_ib *ib,uint32_t id,int start,uint32_t *length) {int i;uint32_t len;for (i = start; (len =amdgpu_ib_get_value (ib, i)) >=8 ; i += len /4 ) { -if (amdgpu_ib_get_value (ib, i +1 ) == id) +if (amdgpu_ib_get_value (ib, i +1 ) == id) { +if (length) + *length = len;return i; + } }return -1 ; }
@@ -1943,14 +1946,14 @@ static int vcn_v4_0_ring_patch_cs_in_pla struct amdgpu_ib *ib) {struct amdgpu_ring *ring =amdgpu_job_ring (job); -uint32_t val; +uint32_t val, len;int idx =0 , sidx;/* The first instance can decode anything */ if (!ring->me)return 0 ; -while ((idx =vcn_v4_0_enc_find_ib_param (ib,RADEON_VCN_ENGINE_INFO , idx)) >=0 ) { +while ((idx =vcn_v4_0_enc_find_ib_param (ib,RADEON_VCN_ENGINE_INFO , idx, &len)) >=0 ) { val =amdgpu_ib_get_value (ib, idx +2 );/* RADEON_VCN_ENGINE_TYPE */ if (val ==RADEON_VCN_ENGINE_TYPE_DECODE ) {uint32_t valid_buf_flag =amdgpu_ib_get_value (ib, idx +6 );
@@ -1963,12 +1966,12 @@ static int vcn_v4_0_ring_patch_cs_in_plaamdgpu_ib_get_value (ib, idx +8 );return vcn_v4_0_dec_msg (p, job, msg_buffer_addr); }else if (val ==RADEON_VCN_ENGINE_TYPE_ENCODE ) { - sidx =vcn_v4_0_enc_find_ib_param (ib,RENCODE_IB_PARAM_SESSION_INIT , idx); + sidx =vcn_v4_0_enc_find_ib_param (ib,RENCODE_IB_PARAM_SESSION_INIT , idx,NULL );if (sidx >=0 &&amdgpu_ib_get_value (ib, sidx +2 ) ==RENCODE_ENCODE_STANDARD_AV1 )return vcn_v4_0_limit_sched (p, job); } - idx +=amdgpu_ib_get_value (ib, idx) /4 ; + idx += len /4 ; }return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 584/675 drm/dp_mst: Handle torn-down topology gracefully in drm_dp_mst_topology_queue_probe()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luca Coelho <[email protected]>
commit 613059875958e7b217b250ed14c3b189f9488421 upstream.
A hotplug or link-loss event can tear down the MST topology (setting mgr->mst_state = false and mgr->mst_primary = NULL) concurrently with a caller invoking drm_dp_mst_topology_queue_probe(). Since the check is already performed under mgr->lock, the condition is not a programming error but a valid race -- the topology was valid when the caller decided to call this function, but was torn down before the lock was acquired.
Replace the drm_WARN_ON() with a graceful early return. This eliminates spurious kernel warnings and the resulting compositor crashes observed when connecting/disconnecting DP MST monitors, while keeping the correct behavior of doing nothing when MST is not active. A drm_dbg_mst() trace is added so the skipped probe remains observable under MST debug logging.
The existing WARN_ON(mgr->mst_primary) in drm_dp_mst_topology_mgr_set_mst() already catches the case where the topology is initialized twice, so no diagnostic coverage is lost.
--- drivers/gpu/drm/display/drm_dp_mst_topology.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/gpu/drm/display/drm_dp_mst_topology.c +3 -1
@@ -3740,8 +3740,10 @@ void drm_dp_mst_topology_queue_probe(str {mutex_lock (&mgr->lock); -if (drm_WARN_ON (mgr->dev, !mgr->mst_state || !mgr->mst_primary)) +if (!mgr->mst_state || !mgr->mst_primary) { +drm_dbg_kms (mgr->dev,"queue_probe skipped: topology torn down\n" ); goto out_unlock; + }drm_dp_mst_topology_mgr_invalidate_mstb (mgr->mst_primary);drm_dp_mst_queue_probe_work (mgr);
Greg Kroah-Hartman
maintainerPATCH 585/675 drm/amdgpu: fix division by zero with invalid uvd dimensions
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Boyuan Zhang <[email protected]>
commit 0c01c811be47e6b146552dd59bfedbea8f09b8f4 upstream.
When width or height is less than 16, width_in_mb or height_in_mb becomes 0, leading to fs_in_mb being 0. This causes a division by zero when calculating num_dpb_buffer in H264 and H264 Perf decode paths.
Add validation to reject frames with width < 16 or height < 16 before performing any calculations that depend on these values.
V2: Format change - move up all vaiable definitions.
V3: Use warn_once to avoid spam.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +8 -0
@@ -654,6 +654,14 @@ static int amdgpu_uvd_cs_msg_decode(struunsigned int image_size, tmp, min_dpb_size, num_dpb_buffer;unsigned int min_ctx_size = ~0 ; +/* Reject invalid dimensions to prevent division by zero */ +if (width <16 || height <16 ) { +dev_WARN_ONCE (adev->dev,1 , +"Invalid UVD decoding dimensions (%dx%d)!\n" , + width, height); +return -EINVAL ; + } + image_size = width * height; image_size += image_size /2 ; image_size =ALIGN (image_size,1024 );
Greg Kroah-Hartman
maintainerPATCH 586/675 drm/amdgpu: fix resource leak on ACP reset timeout
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ce Sun <[email protected]>
commit 020da7c5aac5b86bad8a1571f6eda6b8cff9331d upstream.
When ACP soft reset poll times out, original code returns early without cleanup, leaking MFD child devices, genpd links and all ACP heap allocations.
Replace direct early return with goto out to force run all cleanup logic regardless of reset success, preserve timeout error code for caller.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c +7 -4
@@ -505,6 +505,7 @@ static int acp_hw_fini(struct amdgpu_ip_u32 val =0 ;u32 count =0 ;struct amdgpu_device *adev = ip_block->adev; +int ret =0 ;/* return early if no ACP */ if (!adev->acp.acp_genpd) {
@@ -526,7 +527,8 @@ static int acp_hw_fini(struct amdgpu_ip_break ;if (--count ==0 ) {dev_err (&adev->pdev->dev,"Failed to reset ACP\n" ); -return -ETIMEDOUT ; + ret = -ETIMEDOUT ; + goto out; }udelay (100 ); }
@@ -543,11 +545,12 @@ static int acp_hw_fini(struct amdgpu_ip_break ;if (--count ==0 ) {dev_err (&adev->pdev->dev,"Failed to reset ACP\n" ); -return -ETIMEDOUT ; + ret = -ETIMEDOUT ; + goto out; }udelay (100 ); } - +out:device_for_each_child (adev->acp.parent,NULL , acp_genpd_remove_device);
@@ -556,7 +559,7 @@ static int acp_hw_fini(struct amdgpu_ip_kfree (adev->acp.acp_genpd);kfree (adev->acp.acp_cell); -return 0 ; +return ret; }static int acp_suspend (struct amdgpu_ip_block *ip_block)
Greg Kroah-Hartman
maintainerPATCH 587/675 drm/amdgpu: invoke pm_genpd_remove() before freeing genpd
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ce Sun <[email protected]>
commit 28c9b3c5dc35cc790d11e26ca3fc6e068be63998 upstream.
Call pm_genpd_remove() to unregister from global list prior to releasing acp_genpd memory, and clear the pointer after free.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c +2 -0
@@ -556,7 +556,9 @@ out:mfd_remove_devices (adev->acp.parent);kfree (adev->acp.acp_res); +pm_genpd_remove (&adev->acp.acp_genpd->gpd);kfree (adev->acp.acp_genpd); + adev->acp.acp_genpd =NULL ;kfree (adev->acp.acp_cell);return ret;
Greg Kroah-Hartman
maintainerPATCH 588/675 drm/amdgpu: fix aperture mapping leak
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Asad Kamal <[email protected]>
commit ea772a440d56b285f4d491affac50ecd41f6b402 upstream.
amdgpu_pci_remove() calls drm_dev_unplug() before invoking the driver fini routines. This causes drm_dev_enter() in amdgpu_ttm_fini() to always return false, so iounmap(aper_base_kaddr) never runs on normal driver unload, leaving an orphaned entry in the x86 PAT interval tree.
On connected_to_cpu hardware, the aperture is mapped write-back (WB) via ioremap_cache(). On reload, IP discovery calls memremap(..., MEMREMAP_WC) over the same range. The WC vs WB conflict causes:
ioremap error for 0x..., requested 0x1, got 0x0
amdgpu: discovery failed: -2
Fix by switching to devres-managed mappings so cleanup is guaranteed regardless of drm_dev_enter() state:
- connected_to_cpu path: devm_memremap(MEMREMAP_WB). For IORESOURCE_SYSTEM_RAM ranges this takes the try_ram_remap() shortcut, returning __va(offset) from the existing kernel direct map. No new ioremap VA or PAT entry is created, so there is nothing to orphan.
- dGPU path: devm_ioremap_wc() registers iounmap() as a devres action, guaranteeing cleanup at device_del() time.
Also remove iounmap(aper_base_kaddr) from amdgpu_device_unmap_mmio() since the mapping is now devres-owned.
v2: Remove redundant x86_64 guard (Lijo)
--- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 - drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 36 ++++++++++++----------------- 2 files changed, 16 insertions(+), 22 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +0 -2
@@ -4946,8 +4946,6 @@ static void amdgpu_device_unmap_mmio(striounmap (adev->rmmio); adev->rmmio =NULL ; -if (adev->mman.aper_base_kaddr) -iounmap (adev->mman.aper_base_kaddr); adev->mman.aper_base_kaddr =NULL ;/* Memory manager related */
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +16 -20
@@ -1980,18 +1980,23 @@ int amdgpu_ttm_init(struct amdgpu_device/* Change the size here instead of the init above so only lpfn is affected */ amdgpu_ttm_set_buffer_funcs_status (adev, false);#ifdef CONFIG_64BIT -#ifdef CONFIG_X86 -if (adev->gmc.xgmi.connected_to_cpu) - adev->mman.aper_base_kaddr =ioremap_cache (adev->gmc.aper_base, - adev->gmc.visible_vram_size); - -else if (adev->gmc.is_app_apu) +if (adev->gmc.xgmi.connected_to_cpu) { +void *kaddr =devm_memremap (adev->dev, adev->gmc.aper_base, + adev->gmc.visible_vram_size, +MEMREMAP_WB ); +if (IS_ERR (kaddr)) +return PTR_ERR (kaddr); + adev->mman.aper_base_kaddr = (__force void __iomem *)kaddr; + }else if (adev->gmc.is_app_apu) {DRM_DEBUG_DRIVER ("No need to ioremap when real vram size is 0\n" ); - else -#endif - adev->mman.aper_base_kaddr =ioremap_wc (adev->gmc.aper_base, - adev->gmc.visible_vram_size); + }else { + adev->mman.aper_base_kaddr =devm_ioremap_wc (adev->dev, + adev->gmc.aper_base, + adev->gmc.visible_vram_size); +if (!adev->mman.aper_base_kaddr) +return -ENOMEM ; + }#endif /*
@@ -2152,8 +2157,6 @@ int amdgpu_ttm_init(struct amdgpu_device*/ void amdgpu_ttm_fini (struct amdgpu_device *adev) { -int idx; -if (!adev->mman.initialized)return ;
@@ -2180,14 +2183,7 @@ void amdgpu_ttm_fini(struct amdgpu_devicamdgpu_ttm_fw_reserve_vram_fini (adev);amdgpu_ttm_drv_reserve_vram_fini (adev); -if (drm_dev_enter (adev_to_drm (adev), &idx)) { - -if (adev->mman.aper_base_kaddr) -iounmap (adev->mman.aper_base_kaddr); - adev->mman.aper_base_kaddr =NULL ; - -drm_dev_exit (idx); - } + adev->mman.aper_base_kaddr =NULL ;if (!adev->gmc.is_app_apu)amdgpu_vram_mgr_fini (adev);
Greg Kroah-Hartman
maintainerPATCH 589/675 drm/amd/pm: fix smu13 power limit range calculation
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Wang <[email protected]>
commit 220f22e1d66c1cfb63387eb1c4210f92a357c2d9 upstream.
SMU13 reports SocketPowerLimitAc/Dc as the default power limit, but MsgLimits.Power may carry a different firmware bound for the same PPT throttler. Using only the socket limit for both min and max can therefore expose an incorrect power range.
Keep the socket limit as the default, but derive the range from both values:
use the lower value for the min base and the higher value for the max base before applying OD percentages. Keep the current limit query independent from the cap calculation.
--- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 11 +++++++---- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 15 ++++++++------- 2 files changed, 15 insertions(+), 11 deletions(-)
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c +7 -4
@@ -2481,11 +2481,14 @@ static int smu_v13_0_0_get_power_limit(suint32_t pp_limit = smu->adev->pm.ac_power ? skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0 ] : skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0 ]; -uint32_t power_limit =0 , od_percent_upper =0 , od_percent_lower =0 ; +uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0 ][POWER_SOURCE_AC ]; +uint32_t min_limit =min_t (uint32_t, pp_limit, msg_limit); +uint32_t max_limit =max_t (uint32_t, pp_limit, msg_limit); +uint32_t od_percent_upper =0 , od_percent_lower =0 ;int ret;if (current_power_limit) { - ret =smu_v13_0_get_current_power_limit (smu, &power_limit); + ret =smu_v13_0_get_current_power_limit (smu, current_power_limit);if (ret) *current_power_limit = pp_limit; }
@@ -2508,12 +2511,12 @@ static int smu_v13_0_0_get_power_limit(s od_percent_upper, od_percent_lower, pp_limit);if (max_power_limit) { - *max_power_limit = pp_limit * (100 + od_percent_upper); + *max_power_limit = max_limit * (100 + od_percent_upper); *max_power_limit /=100 ; }if (min_power_limit) { - *min_power_limit = pp_limit * (100 - od_percent_lower); + *min_power_limit = min_limit * (100 - od_percent_lower); *min_power_limit /=100 ; }
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c +8 -7
@@ -2442,15 +2442,16 @@ static int smu_v13_0_7_get_power_limit(suint32_t pp_limit = smu->adev->pm.ac_power ? skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0 ] : skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0 ]; -uint32_t power_limit =0 , od_percent_upper =0 , od_percent_lower =0 ; +uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0 ][POWER_SOURCE_AC ]; +uint32_t min_limit =min_t (uint32_t, pp_limit, msg_limit); +uint32_t max_limit =max_t (uint32_t, pp_limit, msg_limit); +uint32_t od_percent_upper =0 , od_percent_lower =0 ;int ret;if (current_power_limit) { - ret =smu_v13_0_get_current_power_limit (smu, &power_limit); + ret =smu_v13_0_get_current_power_limit (smu, current_power_limit);if (ret) - power_limit = pp_limit; - - *current_power_limit = power_limit; + *current_power_limit = pp_limit; }if (default_power_limit)
@@ -2471,12 +2472,12 @@ static int smu_v13_0_7_get_power_limit(s od_percent_upper, od_percent_lower, pp_limit);if (max_power_limit) { - *max_power_limit = pp_limit * (100 + od_percent_upper); + *max_power_limit = max_limit * (100 + od_percent_upper); *max_power_limit /=100 ; }if (min_power_limit) { - *min_power_limit = pp_limit * (100 - od_percent_lower); + *min_power_limit = min_limit * (100 - od_percent_lower); *min_power_limit /=100 ; }
Greg Kroah-Hartman
maintainerPATCH 590/675 drm/amdgpu: fix check in amdgpu_hmm_invalidate_gfx
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian König <[email protected]>
commit 52f650963d8825e97a0ccdd2b616f8a01d9d3d38 upstream.
For a short moment during alloc/free the userptr BO is not part of his VM, so bo->vm_bo can be NULL.
Keep a reference to the VM root PD as parent of the userptr BO so that we can always use that to wait for all submissions of the VM instead of only the one involving the userptr BO.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +1 -0
@@ -523,6 +523,7 @@ int amdgpu_gem_userptr_ioctl(struct drm_ bo =gem_to_amdgpu_bo (gobj); bo->preferred_domains =AMDGPU_GEM_DOMAIN_GTT ; bo->allowed_domains =AMDGPU_GEM_DOMAIN_GTT ; + bo->parent =amdgpu_bo_ref (fpriv->vm.root.bo); r =amdgpu_ttm_tt_set_userptr (&bo->tbo, args->addr, args->flags);if (r) goto release_object;
drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c +1 -2
@@ -69,7 +69,6 @@ static bool amdgpu_hmm_invalidate_gfx(st { struct amdgpu_bo *bo = container_of(mni, struct amdgpu_bo, notifier);struct amdgpu_device *adev =amdgpu_ttm_adev (bo->tbo.bdev); -struct amdgpu_bo *vm_root = bo->vm_bo->vm->root.bo;long r;if (!mmu_notifier_range_blockable (range))
@@ -80,7 +79,7 @@ static bool amdgpu_hmm_invalidate_gfx(stmmu_interval_set_seq (mni, cur_seq);amdgpu_vm_bo_invalidate (bo, false); - r =dma_resv_wait_timeout (vm_root->tbo.base.resv, + r =dma_resv_wait_timeout (bo->parent->tbo.base.resv,DMA_RESV_USAGE_BOOKKEEP , false,MAX_SCHEDULE_TIMEOUT );mutex_unlock (&adev->notifier_lock);
Greg Kroah-Hartman
maintainerPATCH 591/675 bpf: Fix same-register dst/src OOB read and pointer leak in sock_ops
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiayuan Chen <[email protected]>
[ Upstream commit 10f86a2a5c91fc4c4d001960f1c21abe52545ef6 ]
When a BPF sock_ops program accesses ctx fields with dst_reg == src_reg, the SOCK_OPS_GET_SK() and SOCK_OPS_GET_FIELD() macros fail to zero the destination register in the !fullsock / !locked_tcp_sock path.
Both macros borrow a temporary register to check is_fullsock / is_locked_tcp_sock when dst_reg == src_reg, because dst_reg holds the ctx pointer. When the check is false (e.g., TCP_NEW_SYN_RECV state with a request_sock), dst_reg should be zeroed but is not, leaving the stale ctx pointer:
- SOCK_OPS_GET_SK: dst_reg retains the ctx pointer, passes NULL checks as PTR_TO_SOCKET_OR_NULL, and can be used as a bogus socket pointer, leading to stack-out-of-bounds access in helpers like bpf_skc_to_tcp6_sock().
- SOCK_OPS_GET_FIELD: dst_reg retains the ctx pointer which the verifier believes is a SCALAR_VALUE, leaking a kernel pointer.
Fix both macros by:
- Changing JMP_A(1) to JMP_A(2) in the fullsock path to skip the added instruction.
- Adding BPF_MOV64_IMM(si->dst_reg, 0) after the temp register restore in the !fullsock path, placed after the restore because dst_reg == src_reg means we need src_reg intact to read ctx->temp.
--- net/core/filter.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
net/core/filter.c +4 -2
@@ -10539,10 +10539,11 @@ static u32 sock_ops_convert_ctx_access(enum bpf_access_type type, si->dst_reg, si->dst_reg, \ offsetof(OBJ, OBJ_FIELD)); \if (si->dst_reg == si->src_reg) { \ - *insn++ =BPF_JMP_A (1 ); \ + *insn++ =BPF_JMP_A (2 ); \ *insn++ =BPF_LDX_MEM (BPF_DW , reg, si->src_reg, \ offsetof(struct bpf_sock_ops_kern , \ temp)); \ + *insn++ =BPF_MOV64_IMM (si->dst_reg,0 ); \ } \ }while (0 )
@@ -10576,10 +10577,11 @@ static u32 sock_ops_convert_ctx_access(enum bpf_access_type type, si->dst_reg, si->src_reg, \ offsetof(struct bpf_sock_ops_kern, sk));\if (si->dst_reg == si->src_reg) { \ - *insn++ =BPF_JMP_A (1 ); \ + *insn++ =BPF_JMP_A (2 ); \ *insn++ =BPF_LDX_MEM (BPF_DW , reg, si->src_reg, \ offsetof(struct bpf_sock_ops_kern , \ temp)); \ + *insn++ =BPF_MOV64_IMM (si->dst_reg,0 ); \ } \ }while (0 )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 592/675 dm-verity-fec: fix the size of dm_verity_fec_io::erasures
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit a7fca324d7d90f7b139d4d32747c83a629fdb446 upstream.
At most 25 entries in dm_verity_fec_io::erasures are used: the maximum number of FEC roots plus one. Therefore, set the array size accordingly. This reduces the size of dm_verity_fec_io by 912 bytes.
Note: a later commit introduces a constant DM_VERITY_FEC_MAX_ROOTS, which allows the size to be more clearly expressed as DM_VERITY_FEC_MAX_ROOTS + 1. This commit just fixes the size first.
--- drivers/md/dm-verity-fec.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/md/dm-verity-fec.h +2 -1
@@ -50,7 +50,8 @@ struct dm_verity_fec {/* per-bio data */ struct dm_verity_fec_io {struct rs_control *rs;/* Reed-Solomon state */ -int erasures[DM_VERITY_FEC_MAX_RSN ];/* erasures for decode_rs8 */ +/* erasures for decode_rs8 */ +int erasures[DM_VERITY_FEC_RSM -DM_VERITY_FEC_MIN_RSN +1 ];u8 *bufs[DM_VERITY_FEC_BUF_MAX ];/* bufs for deinterleaving */ unsigned int nbufs;/* number of buffers allocated */ u8 *output;/* buffer for corrected output */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 593/675 dm-verity-fec: fix reading parity bytes split across blocks (take 3)
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit 430a05cb926f6bdf53e81460a2c3a553257f3f61 upstream.
fec_decode_bufs() assumes that the parity bytes of the first RS codeword it decodes are never split across parity blocks.
This assumption is false. Consider v->fec->block_size == 4096 && v->fec->roots == 17 && fio->nbufs == 1, for example. In that case, each call to fec_decode_bufs() consumes v->fec->roots * (fio->nbufs << DM_VERITY_FEC_BUF_RS_BITS) = 272 parity bytes.
Considering that the parity data for each message block starts on a block boundary, the byte alignment in the parity data will iterate through 272*i mod 4096 until the 3 parity blocks have been consumed. On the 16th call (i=15), the alignment will be 4080 bytes into the first block. Only 16 bytes remain in that block, but 17 parity bytes will be needed. The code reads out-of-bounds from the parity block buffer.
Fortunately this doesn't normally happen, since it can occur only for certain non-default values of fec_roots *and* when the maximum number of buffers couldn't be allocated due to low memory. For example with block_size=4096 only the following cases are affected:
fec_roots=17: nbufs in [1, 3, 5, 15]
fec_roots=19: nbufs in [1, 229]
fec_roots=21: nbufs in [1, 3, 5, 13, 15, 39, 65, 195]
fec_roots=23: nbufs in [1, 89]Regardless, fix it by refactoring how the parity blocks are read.
--- drivers/md/dm-verity-fec.c | 100 ++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 56 deletions(-)
drivers/md/dm-verity-fec.c +44 -56
@@ -39,36 +39,6 @@ static inline u64 fec_interleave(struct dm_verity *v, u64 offset)return offset + mod * (v->fec->rounds << v->data_dev_block_bits); } -/* -* Read error-correcting codes for the requested RS block. Returns a pointer -* to the data block. Caller is responsible for releasing buf. -*/ -static u8 *fec_read_parity (struct dm_verity *v,u64 rsb,int index, -unsigned int *offset,unsigned int par_buf_offset, -struct dm_buffer **buf,unsigned short ioprio) -{ -u64 position, block, rem; -u8 *res; - -/* We have already part of parity bytes read, skip to the next block */ -if (par_buf_offset) - index++; - - position = (index + rsb) * v->fec->roots; - block =div64_u64_rem (position, v->fec->io_size, &rem); - *offset = par_buf_offset ?0 : (unsigned int )rem; - - res =dm_bufio_read_with_ioprio (v->fec->bufio, block, buf, ioprio); -if (IS_ERR (res)) { -DMERR ("%s: FEC %llu: parity read failed (block %llu): %ld" , - v->data_dev->name, (unsigned long long )rsb, - (unsigned long long )block,PTR_ERR (res)); - *buf =NULL ; - } - -return res; -} -/* Loop over each preallocated buffer slot. */ #define fec_for_each_prealloc_buffer (__i) \ for (__i = 0; __i < DM_VERITY_FEC_BUF_PREALLOC; __i++)
@@ -116,15 +86,29 @@ static int fec_decode_bufs(struct dm_verity *v, struct dm_verity_io *io, {int r, corrected =0 , res;struct dm_buffer *buf; -unsigned int n, i, j, offset, par_buf_offset =0 ; +unsigned int n, i, j, parity_pos, to_copy;uint16_t par_buf[DM_VERITY_FEC_RSM -DM_VERITY_FEC_MIN_RSN ];u8 *par, *block; +u64 parity_block;struct bio *bio =dm_bio_from_per_bio_data (io, v->ti->per_io_data_size); - par =fec_read_parity (v, rsb, block_offset, &offset, - par_buf_offset, &buf, bio->bi_ioprio); -if (IS_ERR (par)) +/* +* Compute the index of the first parity block that will be needed and +* the starting position in that block. Then read that block. +* +* io_size is always a power of 2, but roots might not be. Note that +* when it's not, a codeword's parity bytes can span a block boundary. +*/ + parity_block = (rsb + block_offset) * v->fec->roots; + parity_pos = parity_block & (v->fec->io_size -1 ); + parity_block >>= v->data_dev_block_bits; + par =dm_bufio_read_with_ioprio (v->fec->bufio, parity_block, &buf, + bio->bi_ioprio); +if (IS_ERR (par)) { +DMERR ("%s: FEC %llu: parity read failed (block %llu): %ld" , + v->data_dev->name, rsb, parity_block,PTR_ERR (par));return PTR_ERR (par); + }/* * Decode the RS blocks we have in bufs. Each RS block results in
@@ -132,8 +116,32 @@ static int fec_decode_bufs(struct dm_verity *v, struct dm_verity_io *io,*/ fec_for_each_buffer_rs_block (fio, n, i) { block =fec_buffer_rs_block (v, fio, n, i); -for (j =0 ; j < v->fec->roots - par_buf_offset; j++) - par_buf[par_buf_offset + j] = par[offset + j]; + +/* +* Copy the next 'roots' parity bytes to 'par_buf', reading +* another parity block if needed. +*/ + to_copy =min (v->fec->io_size - parity_pos, v->fec->roots); +for (j =0 ; j < to_copy; j++) + par_buf[j] = par[parity_pos++]; +if (to_copy < v->fec->roots) { + parity_block++; + parity_pos =0 ; + +dm_bufio_release (buf); + par =dm_bufio_read_with_ioprio (v->fec->bufio, + parity_block, &buf, + bio->bi_ioprio); +if (IS_ERR (par)) { +DMERR ("%s: FEC %llu: parity read failed (block %llu): %ld" , + v->data_dev->name, rsb, parity_block, +PTR_ERR (par)); +return PTR_ERR (par); + } +for (; j < v->fec->roots; j++) + par_buf[j] = par[parity_pos++]; + } +/* Decode an RS block using Reed-Solomon */ res =decode_rs8 (fio->rs, block, par_buf, v->fec->rsn,NULL , neras, fio->erasures,0 ,NULL );
@@ -148,26 +156,6 @@ static int fec_decode_bufs(struct dm_verity *v, struct dm_verity_io *io, block_offset++;if (block_offset >=1 << v->data_dev_block_bits) goto done; - -/* Read the next block when we run out of parity bytes */ - offset += (v->fec->roots - par_buf_offset); -/* Check if parity bytes are split between blocks */ -if (offset < v->fec->io_size && (offset + v->fec->roots) > v->fec->io_size) { - par_buf_offset = v->fec->io_size - offset; -for (j =0 ; j < par_buf_offset; j++) - par_buf[j] = par[offset + j]; - offset += par_buf_offset; - }else - par_buf_offset =0 ; - -if (offset >= v->fec->io_size) { -dm_bufio_release (buf); - - par =fec_read_parity (v, rsb, block_offset, &offset, - par_buf_offset, &buf, bio->bi_ioprio); -if (IS_ERR (par)) -return PTR_ERR (par); - } } done: r = corrected;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 594/675 dm-verity-fec: replace {MAX,MIN}_RSN with {MIN,MAX}_ROOTS
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit 82fbd6a3e29a329d439690cd7ccc4162c9cd8db6 upstream.
Every time DM_VERITY_FEC_{MAX,MIN}_RSN are used, they are subtracted from DM_VERITY_FEC_RSM to get the bounds on the number of roots. Therefore, replace these with {MIN,MAX}_ROOTS constants which are more directly useful. (Note the inversion, where MAX_RSN maps to MIN_ROOTS and MIN_RSN maps to MAX_ROOTS.) No functional change.
--- drivers/md/dm-verity-fec.c | 6 +++--- drivers/md/dm-verity-fec.h | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-)
drivers/md/dm-verity-fec.c +3 -3
@@ -87,7 +87,7 @@ static int fec_decode_bufs(struct dm_verity *v, struct dm_verity_io *io,int r, corrected =0 , res;struct dm_buffer *buf;unsigned int n, i, j, parity_pos, to_copy; -uint16_t par_buf[DM_VERITY_FEC_RSM -DM_VERITY_FEC_MIN_RSN ]; +uint16_t par_buf[DM_VERITY_FEC_MAX_ROOTS ];u8 *par, *block;u64 parity_block;struct bio *bio =dm_bio_from_per_bio_data (io, v->ti->per_io_data_size);
@@ -605,8 +605,8 @@ int verity_fec_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v, }else if (!strcasecmp (arg_name,DM_VERITY_OPT_FEC_ROOTS )) {if (sscanf (arg_value,"%hhu%c" , &num_c, &dummy) !=1 || !num_c || - num_c < (DM_VERITY_FEC_RSM -DM_VERITY_FEC_MAX_RSN ) || - num_c > (DM_VERITY_FEC_RSM -DM_VERITY_FEC_MIN_RSN )) { + num_c <DM_VERITY_FEC_MIN_ROOTS || + num_c >DM_VERITY_FEC_MAX_ROOTS ) { ti->error ="Invalid " DM_VERITY_OPT_FEC_ROOTS ;return -EINVAL ; }
drivers/md/dm-verity-fec.h +3 -4
@@ -13,8 +13,8 @@/* Reed-Solomon(M, N) parameters */ #define DM_VERITY_FEC_RSM 255 -#define DM_VERITY_FEC_MAX_RSN 253 -#define DM_VERITY_FEC_MIN_RSN 231/* ~10% space overhead */ +#define DM_VERITY_FEC_MIN_ROOTS 2/* RS(255, 253): ~0.8% space overhead */ +#define DM_VERITY_FEC_MAX_ROOTS 24/* RS(255, 231): ~10% space overhead */ /* buffers for deinterleaving and decoding */ #define DM_VERITY_FEC_BUF_PREALLOC 1/* buffers to preallocate */
@@ -50,8 +50,7 @@ struct dm_verity_fec {/* per-bio data */ struct dm_verity_fec_io {struct rs_control *rs;/* Reed-Solomon state */ -/* erasures for decode_rs8 */ -int erasures[DM_VERITY_FEC_RSM -DM_VERITY_FEC_MIN_RSN +1 ]; +int erasures[DM_VERITY_FEC_MAX_ROOTS +1 ];/* erasures for decode_rs8 */ u8 *bufs[DM_VERITY_FEC_BUF_MAX ];/* bufs for deinterleaving */ unsigned int nbufs;/* number of buffers allocated */ u8 *output;/* buffer for corrected output */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 595/675 dm-verity: fix buffer overflow in FEC calculation
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikulas Patocka <[email protected]>
commit 31d6e6c0ba8d5a7bd59660035a089307100c5e8e upstream.
There's a buffer overflow in dm-verity-fec:
if (neras && *neras <= v->fec->roots)
fio->erasures[(*neras)++] = i;
This allows *neras to reach roots + 1 (the post-increment pushes it past roots). This value is then passed as no_eras to decode_rs8(). Inside the RS decoder (lib/reed_solomon/decode_rs.c:113-121), the erasure locator polynomial loop writes lambda[j] where j can reach nroots + 1 — one element past the end of lambda[] (which is sized nroots + 1, valid indices 0..nroots). The out-of-bounds write lands on syn[0], corrupting the syndrome buffer.
--- drivers/md/dm-verity-fec.c | 4 ++-- drivers/md/dm-verity-fec.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-)
drivers/md/dm-verity-fec.c +2 -2
@@ -250,7 +250,7 @@ static int fec_read_bufs(struct dm_verity *v, struct dm_verity_io *io, (unsigned long long)block, PTR_ERR(bbuf));/* assume the block is corrupted */ -if (neras && *neras <= v->fec->roots) +if (neras && *neras < v->fec->roots) fio->erasures[(*neras)++] = i;continue ;
@@ -268,7 +268,7 @@ static int fec_read_bufs(struct dm_verity *v, struct dm_verity_io *io,* skip if we have already found the theoretical * maximum number (i.e. fec->roots) of erasures */ -if (neras && *neras <= v->fec->roots && +if (neras && *neras < v->fec->roots &&fec_is_erasure (v, io, want_digest, bbuf)) fio->erasures[(*neras)++] = i; }
drivers/md/dm-verity-fec.h +1 -1
@@ -50,7 +50,7 @@ struct dm_verity_fec {/* per-bio data */ struct dm_verity_fec_io {struct rs_control *rs;/* Reed-Solomon state */ -int erasures[DM_VERITY_FEC_MAX_ROOTS +1 ];/* erasures for decode_rs8 */ +int erasures[DM_VERITY_FEC_MAX_ROOTS ];/* erasures for decode_rs8 */ u8 *bufs[DM_VERITY_FEC_BUF_MAX ];/* bufs for deinterleaving */ unsigned int nbufs;/* number of buffers allocated */ u8 *output;/* buffer for corrected output */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 596/675 drm/xe/uapi: Reject coh_none PAT index for CPU_ADDR_MIRROR
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jia Yao <[email protected]>
commit 4d58d7535e826a3175527b6174502f0db319d7f6 upstream.
Add validation in xe_vm_bind_ioctl() to reject PAT indices with XE_COH_NONE coherency mode when used with DRM_XE_VM_BIND_FLAG_CPU_ADDR_MIRROR.
CPU address mirror mappings use system memory that is CPU cached, which makes them incompatible with COH_NONE PAT indices. Allowing COH_NONE with CPU cached buffers is a security risk, as the GPU may bypass CPU caches and read stale sensitive data from DRAM.
Although CPU_ADDR_MIRROR does not create an immediate mapping, the backing system memory is still CPU cached. Apply the same PAT coherency restrictions as DRM_XE_VM_BIND_OP_MAP_USERPTR.
v2:
- Correct fix tag
v6:
- No change
v7:
- Correct fix tag
v8:
- Rebase
v9:
- Limit the restrictions to iGPU
v10:
- Just add the iGPU logic but keep dGPU logic
--- drivers/gpu/drm/xe/xe_vm.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/xe/xe_vm.c +2 -0
@@ -3393,6 +3393,8 @@ static int vm_bind_ioctl_check_args(struct xe_device *xe, struct xe_vm *vm, op == DRM_XE_VM_BIND_OP_MAP_USERPTR) ||XE_IOCTL_DBG (xe, coh_mode ==XE_COH_NONE && op ==DRM_XE_VM_BIND_OP_MAP_USERPTR ) || +XE_IOCTL_DBG (xe, !IS_DGFX (xe) && coh_mode ==XE_COH_NONE && + is_cpu_addr_mirror) ||XE_IOCTL_DBG (xe, op ==DRM_XE_VM_BIND_OP_MAP_USERPTR && !IS_ENABLED (CONFIG_DRM_GPUSVM )) || XE_IOCTL_DBG(xe, obj &&
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 597/675 ublk: wait on ublk_dev_ready() instead of ub->completion
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ming Lei <[email protected]>
commit 432a9b2780c0a01caf547bd1fc2fcf28aeb8d173 upstream.
ub->completion is only re-armed by a successful START_USER_RECOVERY. If the ublk server sends END_USER_RECOVERY without one - e.g. its START failed with -EBUSY and the error was ignored - the wait is satisfied by the stale completion of the previous recovery cycle, and the device is marked LIVE and the requeue list kicked while the FETCH stream is still running and ubq->canceling is still set. The kick redispatches a previously requeued request, __ublk_queue_rq_common() sees ->canceling and parks it again via __ublk_abort_rq(), and after the last FETCH clears ->canceling nothing ever kicks the requeue list again: the request is stranded there while holding its tag. If it is the flush machinery's flush_rq, every subsequent fsync piles up in uninterruptible sleep and teardown hangs on tag draining. This matches a report of a lost PREFLUSH with ext4 on top of ublk after daemon crash recovery.
ub->completion is an edge-triggered latch used as a proxy for the level condition "every queue has fetched all I/O commands", which can regress (F_BATCH's UNPREP, daemon death) and whose re-arm can be skipped. Drop it and wait on the real condition instead: the new helper ublk_wait_dev_ready_and_lock() waits on ublk_dev_ready() via wait_var_event_interruptible(), woken from ublk_mark_io_ready(), then re-checks it under ub->mutex, waiting again on regression, and returns with the mutex held and readiness guaranteed.
Readiness becomes true in the same ub->mutex critical section that clears the last queue's ->canceling, so END_USER_RECOVERY marks the device LIVE and kicks the requeue list strictly after ->canceling clears. The wait stays interruptible, so a server whose daemon died can still be signalled out. For ublk_ctrl_start_dev() this replaces the fail-fast -EINVAL on an F_BATCH ready->UNPREP regression with waiting until the device is ready again.
[ 6.18.y tracks readiness per fetched I/O command in ->nr_io_ready rather
than per queue in ->nr_queue_ready, so wait and wake on that counter; ->canceling is cleared by ublk_reset_io_flags(), which stays in ublk_mark_io_ready(). UBLK_F_BATCH_IO does not exist here, so ublk_ctrl_start_dev() has no F_BATCH readiness re-check to replace, and readiness can only regress via ublk_reset_ch_dev() on daemon death. ]
--- drivers/block/ublk_drv.c | 52 ++++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 15 deletions(-)
drivers/block/ublk_drv.c +37 -15
@@ -19,6 +19,7 @@#include <linux/errno.h> #include <linux/major.h> #include <linux/wait.h> +#include <linux/wait_bit.h> #include <linux/blkdev.h> #include <linux/init.h> #include <linux/swap.h>
@@ -26,7 +27,6 @@#include <linux/compat.h> #include <linux/mutex.h> #include <linux/writeback.h> -#include <linux/completion.h> #include <linux/highmem.h> #include <linux/sysfs.h> #include <linux/miscdevice.h>
@@ -230,7 +230,6 @@ struct ublk_device {struct ublk_params params; -struct completion completion;u32 nr_io_ready;bool unprivileged_daemons;struct mutex cancel_mutex;
@@ -2150,9 +2149,13 @@ static void ublk_mark_io_ready(struct ublk_device *ub) ub->nr_io_ready++;if (ublk_dev_ready (ub)) { -/* now we are ready for handling ublk io request */ +/* +* now we are ready for handling ublk io request, clear +* device-level canceling flag and wake ublk_dev_ready() +* waiters +*/ ublk_reset_io_flags (ub); -complete_all (&ub->completion); +wake_up_var (&ub->nr_io_ready); } }
@@ -2829,7 +2832,6 @@ static int ublk_init_queues(struct ublk_device *ub) goto fail; } -init_completion (&ub->completion);return 0 ; fail:
@@ -2966,6 +2968,26 @@ static bool ublk_validate_user_pid(struct ublk_device *ub, pid_t ublksrv_pid)return ub->ublksrv_tgid == ublksrv_pid; } +/* +* Wait until all queues have fetched their I/O commands, and return with +* ub->mutex held and readiness guaranteed: then every queue's ->canceling +* is cleared. Ready may regress between wakeup and mutex_lock() (daemon +* death), so re-check it under the mutex and wait again. +*/ +static int ublk_wait_dev_ready_and_lock (struct ublk_device *ub) +{ +while (true) { +if (wait_var_event_interruptible (&ub->nr_io_ready, +ublk_dev_ready (ub))) +return -EINTR ; + +mutex_lock (&ub->mutex); +if (ublk_dev_ready (ub)) +return 0 ; +mutex_unlock (&ub->mutex); + } +} +static int ublk_ctrl_start_dev (struct ublk_device *ub,const struct ublksrv_ctrl_cmd *header) {
@@ -3031,13 +3053,13 @@ static int ublk_ctrl_start_dev(struct ublk_device *ub, lim.max_segments = ub->params.seg.max_segments; } -if (wait_for_completion_interruptible (&ub->completion) !=0 ) +if (ublk_wait_dev_ready_and_lock (ub))return -EINTR ; -if (!ublk_validate_user_pid (ub, ublksrv_pid)) -return -EINVAL ; - -mutex_lock (&ub->mutex); +if (!ublk_validate_user_pid (ub, ublksrv_pid)) { + ret = -EINVAL ; + goto out_unlock; + }if (ub->dev_info.state ==UBLK_S_DEV_LIVE ||test_bit (UB_STATE_USED , &ub->state)) { ret = -EEXIST ;
@@ -3549,7 +3571,6 @@ static int ublk_ctrl_start_recovery(struct ublk_device *ub, goto out_unlock; }pr_devel ("%s: start recovery for dev id %d.\n" , __func__, header->dev_id); -init_completion (&ub->completion); ret =0 ; out_unlock:mutex_unlock (&ub->mutex);
@@ -3565,16 +3586,17 @@ static int ublk_ctrl_end_recovery(struct ublk_device *ub,pr_devel ("%s: Waiting for all FETCH_REQs, dev id %d...\n" , __func__, header->dev_id); -if (wait_for_completion_interruptible (&ub->completion)) +if (ublk_wait_dev_ready_and_lock (ub))return -EINTR ;pr_devel ("%s: All FETCH_REQs received, dev id %d\n" , __func__, header->dev_id); -if (!ublk_validate_user_pid (ub, ublksrv_pid)) -return -EINVAL ; +if (!ublk_validate_user_pid (ub, ublksrv_pid)) { + ret = -EINVAL ; + goto out_unlock; + } -mutex_lock (&ub->mutex);if (ublk_nosrv_should_stop_dev (ub)) goto out_unlock;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 598/675 net: qrtr: ns: Raise node count limit to 512
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Youssef Samir <[email protected]>
commit ff194cffd586cbd4cc49eccb002c65f2a902a277 upstream.
The current node limit of 64 breaks the functionality for a number of AI200 deployments that have up to 384 nodes. Raise the limit to 512.
--- net/qrtr/ns.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/qrtr/ns.c +2 -2
@@ -85,9 +85,9 @@ struct qrtr_node {/* Max nodes limit is chosen based on the current platform requirements. * If the requirement changes in the future, this value can be increased. */ -#define QRTR_NS_MAX_NODES 64 +#define QRTR_NS_MAX_NODES 512 -static u8 node_count; +static u16 node_count;static struct qrtr_node *node_get (unsigned int node_id) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 599/675 ksmbd: validate num_subauth when copying ACE in set_ntacl_dacl
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haofeng Li <[email protected]>
commit 47f0b34f6bc98ed85bfdc293e8f3e432ec24958d upstream.
set_ntacl_dacl() copies each ACE from the attacker-controlled stored security descriptor verbatim into the response DACL without checking sid.num_subauth. The ACE bytes (including an unchecked num_subauth) originate from an authenticated SMB2_SET_INFO(SecInfo=DACL) that is stored raw via ksmbd_vfs_set_sd_xattr(); parse_dacl() rejects a bad ACE with break rather than an error, so parse_sec_desc() still returns success and the malformed SD reaches the xattr intact.
On a subsequent SMB2_QUERY_INFO(SecInfo=DACL) for an inode carrying a POSIX access ACL, build_sec_desc() -> set_ntacl_dacl() -> set_posix_acl_entries_dacl() walks the copied ACEs and reads
ntace->sid.sub_auth[ntace->sid.num_subauth - 1]
with num_subauth taken straight from the stored SD. Since sub_auth[] is fixed at SID_MAX_SUB_AUTHORITIES (15), a crafted num_subauth (e.g.
255) drives an out-of-bounds heap read of ~1 KB with an offset fully controlled by an authenticated client.
The sibling functions already gate this field:
parse_dacl() -- num_subauth == 0 || > SID_MAX_SUB_AUTHORITIES parse_sid() -- num_subauth > SID_MAX_SUB_AUTHORITIES smb_copy_sid() -- min_t(u8, num_subauth, SID_MAX_SUB_AUTHORITIES)
set_ntacl_dacl() is the lone inconsistent path that omits the check.
Add the same num_subauth validation in set_ntacl_dacl() before copying the ACE, matching the gate already enforced by parse_dacl().
--- fs/smb/server/smbacl.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
fs/smb/server/smbacl.c +7 -1
@@ -745,12 +745,18 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,if (nt_ace_size > aces_size)break ; +if (ntace->sid.num_subauth ==0 || + ntace->sid.num_subauth >SID_MAX_SUB_AUTHORITIES ) + goto next_ace; +memcpy ((char *)pndace + size, ntace, nt_ace_size);if (check_add_overflow (size, nt_ace_size, &size))break ; + num_aces++; + +next_ace: aces_size -= nt_ace_size; ntace = (struct smb_ace *)((char *)ntace + nt_ace_size); - num_aces++; } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 600/675 ksmbd: restore DACL size on check_add_overflow() to avoid malformed ACL
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Guan <[email protected]>
commit bbf0a8e931204ecdab494a88d43b0a24a04285c5 upstream.
check_add_overflow() unconditionally writes the truncated sum into *d even on overflow, per its contract in include/linux/overflow.h. The four check_add_overflow() guards in set_posix_acl_entries_dacl() and set_ntacl_dacl() break out of the ACE-building loops on overflow, but the truncated *size is then consumed downstream at the end of set_ntacl_dacl():
pndacl->size = cpu_to_le16(le16_to_cpu(pndacl->size) + size);
This produces an on-wire NT ACL whose pndacl->size under-reports the bytes actually written by the preceding fill_ace_for_sid()/memcpy() calls, yielding a malformed ACL that can trigger out-of-bounds reads when re-parsed by clients or ksmbd itself.
Restore *size to its pre-addition value on each overflow branch (via *size -= ace_sz / size -= nt_ace_size) so that after the break, *size once again holds the cumulative size of the successfully-written ACEs. The committed ACL is then truncated-but-self-consistent rather than malformed.
The ksmbd DACL builders are the only check_add_overflow() sites found where an overflow path breaks out of a loop and the destination value is consumed afterward. The other nearby break-style cases either return -EINVAL on overflow (transport_ipc.c) or break without consuming the overflowed destination value afterward (buildid.c).
--- fs/smb/server/smbacl.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
fs/smb/server/smbacl.c +6 -1
@@ -649,6 +649,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap, ace_sz =fill_ace_for_sid (ntace, sid,ACCESS_ALLOWED , flags, pace->e_perm,0777 );if (check_add_overflow (*size, ace_sz, size)) { + *size -= ace_sz;kfree (sid);break ; }
@@ -663,6 +664,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap, ace_sz =fill_ace_for_sid (ntace, sid,ACCESS_ALLOWED ,0x03 , pace->e_perm,0777 );if (check_add_overflow (*size, ace_sz, size)) { + *size -= ace_sz;kfree (sid);break ; }
@@ -708,6 +710,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap, ace_sz =fill_ace_for_sid (ntace, sid,ACCESS_ALLOWED ,0x0b , pace->e_perm,0777 );if (check_add_overflow (*size, ace_sz, size)) { + *size -= ace_sz;kfree (sid);break ; }
@@ -750,8 +753,10 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap, goto next_ace;memcpy ((char *)pndace + size, ntace, nt_ace_size); -if (check_add_overflow (size, nt_ace_size, &size)) +if (check_add_overflow (size, nt_ace_size, &size)) { + size -= nt_ace_size;break ; + } num_aces++; next_ace:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 601/675 ksmbd: bound DACL dedup walk to copied ACEs
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
commit 58d97fcd0bf1aee694e244cc28635b9df95b543b upstream.
set_ntacl_dacl() can stop copying ACEs before consuming the full input DACL when size accounting overflows.
When that happens, num_aces reflects only the ACEs that were actually copied into the output DACL, but set_posix_acl_entries_dacl() still receives nt_num_aces and uses it to walk the existing ACE array during dedup.
That makes the dedup walk scan past the copied ACE array and inspect buffer tail that does not contain valid ACEs.
Split the two meanings currently carried by the NT ACE count. Pass the number of copied NT ACEs to bound the dedup walk, and preserve the original "input DACL had NT ACEs" state separately for the Everyone/default ACL fallback.
This keeps the dedup walk aligned with the ACEs that are actually present in the rebuilt DACL.
--- fs/smb/server/smbacl.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-)
fs/smb/server/smbacl.c +10 -6
@@ -595,7 +595,8 @@ static void parse_dacl(struct mnt_idmap *idmap,static void set_posix_acl_entries_dacl (struct mnt_idmap *idmap,struct smb_ace *pndace,struct smb_fattr *fattr,u16 *num_aces, -u16 *size,u32 nt_aces_num) +u16 *size,u16 existing_nt_aces, +bool had_nt_aces) {struct posix_acl_entry *pace;struct smb_sid *sid;
@@ -627,14 +628,14 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap, gid =posix_acl_gid_translate (idmap, pace);id_to_sid (gid,SIDUNIX_GROUP , sid); - }else if (pace->e_tag ==ACL_OTHER && !nt_aces_num) { + }else if (pace->e_tag ==ACL_OTHER && !had_nt_aces) {smb_copy_sid (sid, &sid_everyone); }else {kfree (sid);continue ; } ntace = pndace; -for (j =0 ; j < nt_aces_num; j++) { +for (j =0 ; j < existing_nt_aces; j++) {if (ntace->sid.sub_auth[ntace->sid.num_subauth -1 ] == sid->sub_auth[sid->num_subauth -1 ]) goto pass_same_sid;
@@ -678,7 +679,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,kfree (sid); } -if (nt_aces_num) +if (had_nt_aces)return ; posix_default_acl:
@@ -732,6 +733,7 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap, {struct smb_ace *ntace, *pndace;u16 nt_num_aces =le16_to_cpu (nt_dacl->num_aces), num_aces =0 ; +u16 copied_nt_aces;unsigned short size =0 ;int i;
@@ -765,8 +767,10 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap, } } + copied_nt_aces = num_aces;set_posix_acl_entries_dacl (idmap, pndace, fattr, - &num_aces, &size, nt_num_aces); + &num_aces, &size, copied_nt_aces, + nt_num_aces !=0 ); pndacl->num_aces =cpu_to_le16 (num_aces); pndacl->size =cpu_to_le16 (le16_to_cpu (pndacl->size) + size); }
@@ -784,7 +788,7 @@ static void set_mode_dacl(struct mnt_idmap *idmap,if (fattr->cf_acls) {set_posix_acl_entries_dacl (idmap, pndace, fattr, - &num_aces, &size, num_aces); + &num_aces, &size, num_aces, false); goto out; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 602/675 ksmbd: validate ACE size against SID sub-authorities
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
commit 5152c6d49e3fd4e9f2e857c57527aead752f1f87 upstream.
set_ntacl_dacl() validates sid.num_subauth before copying an ACE, but does not verify that the declared ACE size contains all sub-authorities described by that field. An undersized ACE can therefore be copied and later make the POSIX ACL deduplication walk inspect data beyond the copied ACE boundary.
The existing initial bound check is also too small. It only ensures that the ACE size field is accessible before set_ntacl_dacl() reads sid.num_subauth farther into the input buffer.
Require enough input for the fixed SID header before accessing num_subauth, reject ACEs smaller than that header, and skip ACEs whose declared size cannot contain the complete SID. This makes the validation consistent with the other ACE walk paths.
--- fs/smb/server/smbacl.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
fs/smb/server/smbacl.c +10 -3
@@ -743,15 +743,22 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,for (i =0 ; i < nt_num_aces; i++) {unsigned short nt_ace_size; -if (offsetof(struct smb_ace , access_req) > aces_size) +if (aces_size < offsetof(struct smb_ace , sid) + +CIFS_SID_BASE_SIZE )break ; nt_ace_size =le16_to_cpu (ntace->size); -if (nt_ace_size > aces_size) +if (nt_ace_size > aces_size || + nt_ace_size < offsetof(struct smb_ace , sid) + +CIFS_SID_BASE_SIZE )break ;if (ntace->sid.num_subauth ==0 || - ntace->sid.num_subauth >SID_MAX_SUB_AUTHORITIES ) + ntace->sid.num_subauth >SID_MAX_SUB_AUTHORITIES || + nt_ace_size < offsetof(struct smb_ace , sid) + +CIFS_SID_BASE_SIZE + +sizeof (__le32) * + ntace->sid.num_subauth) goto next_ace;memcpy ((char *)pndace + size, ntace, nt_ace_size);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 603/675 fscrypt: Avoid dynamic allocation in fscrypt_get_devices()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit 6fe4e4b8259e1330945b5f3c9476e08473b8e0e8 upstream.
When a blk_crypto_key starts being used or is evicted, fs/crypto/ calls fscrypt_get_devices() to get the filesystem's list of block devices, then iterates over them and calls blk_crypto_config_supported(), blk_crypto_start_using_key(), or blk_crypto_evict_key() on each one.
Currently, the block device pointers are placed in a dynamically allocated array. This dynamic allocation is problematic because:
- It can fail, especially at the fscrypt_destroy_inline_crypt_key() call site when it's invoked for inode eviction under direct reclaim.
- fscrypt_destroy_inline_crypt_key() doesn't handle the failure. It just zeroizes and frees the blk_crypto_key without calling blk_crypto_evict_key(). That causes a use-after-free.
For now, let's fix this in the straightforward and easily-backportable way by switching to an on-stack array. Currently the fscrypt multi-device functionality is used only by f2fs, which has a hardcoded limit of 8 block devices. An on-stack array works fine for that.
(Of course, this solution won't scale up to large number of block devices. For that we'd need a different solution, like moving the block device iteration into the filesystem. Or in the case of btrfs, which will only support blk-crypto-fallback, we should make it just call blk-crypto-fallback directly, so the block devices won't be needed.)
--- fs/crypto/inline_crypt.c | 57 ++++++++++++++-------------------------- fs/f2fs/super.c | 25 ++++++++++-------- include/linux/fscrypt.h | 18 +++++++------ 3 files changed, 44 insertions(+), 56 deletions(-)
fs/crypto/inline_crypt.c +20 -37
@@ -22,22 +22,14 @@#include "fscrypt_private.h" -static struct block_device **fscrypt_get_devices (struct super_block *sb, -unsigned int *num_devs) +static unsigned int +fscrypt_get_devices (struct super_block *sb, +struct block_device *devs[FSCRYPT_MAX_DEVICES ]) { -struct block_device **devs; - -if (sb->s_cop->get_devices) { - devs = sb->s_cop->get_devices (sb, num_devs); -if (devs) -return devs; - } - devs =kmalloc (sizeof (*devs),GFP_KERNEL ); -if (!devs) -return ERR_PTR (-ENOMEM ); +if (sb->s_cop->get_devices) +return sb->s_cop->get_devices (sb, devs); devs[0 ] = sb->s_bdev; - *num_devs =1 ; -return devs; +return 1 ; }static unsigned int fscrypt_get_dun_bytes (const struct fscrypt_inode_info *ci)
@@ -96,7 +88,7 @@ int fscrypt_select_encryption_impl(struct fscrypt_inode_info *ci,const struct inode *inode = ci->ci_inode;struct super_block *sb = inode->i_sb;struct blk_crypto_config crypto_cfg; -struct block_device **devs; +struct block_device *devs[FSCRYPT_MAX_DEVICES ];unsigned int num_devs;unsigned int i;
@@ -135,20 +127,15 @@ int fscrypt_select_encryption_impl(struct fscrypt_inode_info *ci, crypto_cfg.key_type = is_hw_wrapped_key ?BLK_CRYPTO_KEY_TYPE_HW_WRAPPED :BLK_CRYPTO_KEY_TYPE_RAW ; - devs =fscrypt_get_devices (sb, &num_devs); -if (IS_ERR (devs)) -return PTR_ERR (devs); - + num_devs =fscrypt_get_devices (sb, devs);for (i =0 ; i < num_devs; i++) {if (!blk_crypto_config_supported (devs[i], &crypto_cfg)) - goto out_free_devs; +return 0 ; }fscrypt_log_blk_crypto_impl (ci->ci_mode, devs, num_devs, &crypto_cfg); ci->ci_inlinecrypt = true; -out_free_devs: -kfree (devs);return 0 ; }
@@ -164,7 +151,7 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,enum blk_crypto_key_type key_type = is_hw_wrapped ?BLK_CRYPTO_KEY_TYPE_HW_WRAPPED :BLK_CRYPTO_KEY_TYPE_RAW ;struct blk_crypto_key *blk_key; -struct block_device **devs; +struct block_device *devs[FSCRYPT_MAX_DEVICES ];unsigned int num_devs;unsigned int i;int err;
@@ -182,17 +169,12 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key, }/* Start using blk-crypto on all the filesystem's block devices. */ - devs =fscrypt_get_devices (sb, &num_devs); -if (IS_ERR (devs)) { - err =PTR_ERR (devs); - goto fail; - } + num_devs =fscrypt_get_devices (sb, devs);for (i =0 ; i < num_devs; i++) { err =blk_crypto_start_using_key (devs[i], blk_key);if (err)break ; } -kfree (devs);if (err) {fscrypt_err (inode,"error %d starting to use blk-crypto" , err); goto fail;
@@ -210,20 +192,21 @@ void fscrypt_destroy_inline_crypt_key(struct super_block *sb, struct fscrypt_prepared_key *prep_key) {struct blk_crypto_key *blk_key = prep_key->blk_key; -struct block_device **devs; +struct block_device *devs[FSCRYPT_MAX_DEVICES ];unsigned int num_devs;unsigned int i;if (!blk_key)return ; -/* Evict the key from all the filesystem's block devices. */ - devs =fscrypt_get_devices (sb, &num_devs); -if (!IS_ERR (devs)) { -for (i =0 ; i < num_devs; i++) -blk_crypto_evict_key (devs[i], blk_key); -kfree (devs); - } +/* +* Evict the key from all the filesystem's block devices. +* This *must* be done before the key is freed. +*/ + num_devs =fscrypt_get_devices (sb, devs); +for (i =0 ; i < num_devs; i++) +blk_crypto_evict_key (devs[i], blk_key); +kfree_sensitive (blk_key); }
fs/f2fs/super.c +14 -11
@@ -3659,24 +3659,27 @@ static bool f2fs_has_stable_inodes(struct super_block *sb)return true; } -static struct block_device **f2fs_get_devices (struct super_block *sb, -unsigned int *num_devs) +static unsigned int +f2fs_get_devices (struct super_block *sb, +struct block_device *devs[FSCRYPT_MAX_DEVICES ]) {struct f2fs_sb_info *sbi =F2FS_SB (sb); -struct block_device **devs; +int ndevs;int i; -if (!f2fs_is_multi_device (sbi)) -return NULL ; +static_assert (MAX_DEVICES <=FSCRYPT_MAX_DEVICES ); - devs =kmalloc_array (sbi->s_ndevs,sizeof (*devs),GFP_KERNEL ); -if (!devs) -return ERR_PTR (-ENOMEM ); +if (!f2fs_is_multi_device (sbi)) { + devs[0 ] = sb->s_bdev; +return 1 ; + } + ndevs = sbi->s_ndevs; +if (WARN_ON_ONCE (ndevs >FSCRYPT_MAX_DEVICES )) + ndevs =FSCRYPT_MAX_DEVICES ; -for (i =0 ; i < sbi->s_ndevs; i++) +for (i =0 ; i < ndevs; i++) devs[i] =FDEV (i).bdev; - *num_devs = sbi->s_ndevs; -return devs; +return ndevs; }static const struct fscrypt_operations f2fs_cryptops = {
include/linux/fscrypt.h +10 -8
@@ -57,6 +57,9 @@ struct fscrypt_name {/* Maximum value for the third parameter of fscrypt_operations.set_context(). */ #define FSCRYPT_SET_CONTEXT_MAX_SIZE 40 +/* Maximum supported number of block devices per filesystem */ +#define FSCRYPT_MAX_DEVICES 8 +#ifdef CONFIG_FS_ENCRYPTION /* Crypto operations for filesystems */
@@ -181,21 +184,20 @@ struct fscrypt_operations {bool (*has_stable_inodes)(struct super_block *sb);/* -* Return an array of pointers to the block devices to which the -* filesystem may write encrypted file contents, NULL if the filesystem -* only has a single such block device, or an ERR_PTR() on error. +* Retrieve the list of block devices to which the filesystem may write +* encrypted file contents. * -* On successful non-NULL return, *num_devs is set to the number of -* devices in the returned array. The caller must free the returned -* array using kfree(). +* This writes the block_device pointers to @devs and returns the count +* (between 1 and FSCRYPT_MAX_DEVICES inclusively). * * If the filesystem can use multiple block devices (other than block * devices that aren't used for encrypted file contents, such as * external journal devices), and wants to support inline encryption, * then it must implement this function. Otherwise it's not needed. */ -struct block_device **(*get_devices)(struct super_block *sb, -unsigned int *num_devs); +unsigned int (*get_devices)( +struct super_block *sb, +struct block_device *devs[FSCRYPT_MAX_DEVICES ]); }; int fscrypt_d_revalidate(struct inode *dir, const struct qstr *name,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 604/675 drm/amd/display: Fix DTB DTO updates breaking live pixel rate sources
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harry Wentland <[email protected]>
commit 76a2db58e95e328007043f54ac3c7336ccbee440 upstream.
dcn32_update_clocks_update_dtb_dto() and its dcn35 counterpart reprogram the DTB DTO of every timing generator in the context whenever the DTBCLK reference changes, passing a zeroed pixel rate and never setting is_hdmi. Both dccg set_dtbclk_dto() implementations treat a zero pixel rate as a disable request. On dcn32 that branch drives PIPE_DTO_SRC_SEL to the DP DTO source, so a timing generator actively scanning out an HDMI stream has its pixel rate source re-muxed out from under the live raster and the OTG stops on the spot. On dcn35 it clears DTBCLK_DTO_ENABLE and restores DTBCLK_Pn clock gating, which does the same to a live 128b/132b stream.
Two displays where only one runs a 128b/132b link hit this reliably. is_dtbclk_required() holds the DTBCLK reference high while both are active, and the moment the 128b/132b stream is torn down (compositor switch, display disable, hot-unplug) the next safe_to_lower pass drops the reference to the lowest DPM level and the DTO walk freezes the surviving screen. On Navi31 the DAL mailbox then goes deaf on the DISPCLK hard-min that follows the walk in dcn32_update_clocks(), stranding both SMU mailboxes until reboot.
Set is_hdmi for HDMI and DVI signals so the disable path leaves the pixel rate source selection on the HDMI path, and pass the real pixel rate for 128b/132b streams so a reference change rescales their DTO instead of disabling it.
[ mschwartz: dcn32 and dcn35 clk_mgr hunks only. The rest is HDMI FRL
enablement, absent before 7.2, so the FRL conditions and the req_audio_dtbclk_khz assignment they guard are dropped and the FRL-centric changelog is rewritten. Added the pipe_ctx->stream check the new dereferences need. ]
--- .../gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c | 9 ++++++++- .../gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c +8 -1
@@ -276,13 +276,20 @@ static void dcn32_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr,struct dtbclk_dto_params dto_params = {0 };/* use mask to program DTO once per tg */ -if (pipe_ctx->stream_res.tg && +if (pipe_ctx->stream && pipe_ctx->stream_res.tg && !(tg_mask & (1 << pipe_ctx->stream_res.tg->inst))) { tg_mask |= (1 << pipe_ctx->stream_res.tg->inst); dto_params.otg_inst = pipe_ctx->stream_res.tg->inst; dto_params.ref_dtbclk_khz = ref_dtbclk_khz; +if (dccg->ctx->dc->link_srv->dp_is_128b_132b_signal (pipe_ctx)) + dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz /10 ; + +if (dc_is_hdmi_signal (pipe_ctx->stream->signal) || +dc_is_dvi_signal (pipe_ctx->stream->signal)) + dto_params.is_hdmi = true; + dccg->funcs->set_dtbclk_dto (clk_mgr->dccg, &dto_params);//dccg->funcs->set_audio_dtbclk_dto(clk_mgr->dccg, &dto_params); }
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c +8 -1
@@ -264,13 +264,20 @@ static void dcn35_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr,struct dtbclk_dto_params dto_params = {0 };/* use mask to program DTO once per tg */ -if (pipe_ctx->stream_res.tg && +if (pipe_ctx->stream && pipe_ctx->stream_res.tg && !(tg_mask & (1 << pipe_ctx->stream_res.tg->inst))) { tg_mask |= (1 << pipe_ctx->stream_res.tg->inst); dto_params.otg_inst = pipe_ctx->stream_res.tg->inst; dto_params.ref_dtbclk_khz = ref_dtbclk_khz; +if (dccg->ctx->dc->link_srv->dp_is_128b_132b_signal (pipe_ctx)) + dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz /10 ; + +if (dc_is_hdmi_signal (pipe_ctx->stream->signal) || +dc_is_dvi_signal (pipe_ctx->stream->signal)) + dto_params.is_hdmi = true; + dccg->funcs->set_dtbclk_dto (clk_mgr->dccg, &dto_params);//dccg->funcs->set_audio_dtbclk_dto(clk_mgr->dccg, &dto_params); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 605/675 landlock: Fix formatting
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mickaël Salaün <[email protected]>
[ Upstream commit 405ca72dc589dd746e5ee5378bb9d9ee7f844010 ]
Auto-format with clang-format -i security/landlock/*.[ch]
Stable-dep-of: b232bd12789f ("landlock: Account all audit data allocations to user space")
--- security/landlock/domain.c | 3 +-- security/landlock/ruleset.c | 7 +++---- 2 files changed, 4 insertions(+), 6 deletions(-)
security/landlock/domain.c +1 -2
@@ -94,8 +94,7 @@ static struct landlock_details *get_curr* allocate with GFP_KERNEL_ACCOUNT because it is independent from the * caller. */ - details = -kzalloc (struct_size (details, exe_path, path_size),GFP_KERNEL ); + details =kzalloc_flex (*details, exe_path, path_size);if (!details)return ERR_PTR (-ENOMEM );
security/landlock/ruleset.c +3 -4
@@ -33,9 +33,8 @@ static struct landlock_ruleset *create_r {struct landlock_ruleset *new_ruleset; - new_ruleset = -kzalloc (struct_size (new_ruleset, access_masks, num_layers), -GFP_KERNEL_ACCOUNT ); + new_ruleset =kzalloc_flex (*new_ruleset, access_masks, num_layers, +GFP_KERNEL_ACCOUNT );if (!new_ruleset)return ERR_PTR (-ENOMEM );refcount_set (&new_ruleset->usage,1 );
@@ -553,7 +552,7 @@ landlock_merge_ruleset(struct landlock_rreturn new_dom; new_dom->hierarchy = -kzalloc (sizeof (*new_dom->hierarchy),GFP_KERNEL_ACCOUNT ); +kzalloc_obj (*new_dom->hierarchy,GFP_KERNEL_ACCOUNT );if (!new_dom->hierarchy)return ERR_PTR (-ENOMEM );
Greg Kroah-Hartman
maintainerPATCH 606/675 landlock: Account all audit data allocations to user space
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mickaël Salaün <[email protected]>
[ Upstream commit b232bd12789fa57405b5092f28788be97aae9999 ]
Mark the kzalloc_flex() of struct landlock_details with GFP_KERNEL_ACCOUNT so the allocation is charged to the calling task, like the other Landlock per-domain allocations which have used GFP_KERNEL_ACCOUNT forever.
Every property of landlock_details is caller-attributable: allocated by landlock_restrict_self(2), owned by the caller's landlock_hierarchy, contents are the caller's pid, uid, comm, and exe_path, lifetime bounded by the caller's domain. While the caller may not know nor control the size of this allocation (i.e. exe_path), this data should still be accounted for it.
The deciding factor is whether userspace can trigger the allocation, not whether the size of the data is known nor controlled by the caller. This aligns with the kmemcg accounting policy established by commit 5d097056c9a0 ("kmemcg: account certain kmem allocations to memcg").
No new failure modes: the hierarchy and ruleset are allocated before details and are already accounted, so landlock_restrict_self(2) already returns -ENOMEM under memcg pressure. This change widens that existing failure window slightly; it does not introduce a new error code.
--- security/landlock/domain.c | 9 +++++---- security/landlock/domain.h | 5 +---- 2 files changed, 6 insertions(+), 8 deletions(-)
security/landlock/domain.c +5 -4
@@ -90,11 +90,12 @@ static struct landlock_details *get_currreturn ERR_CAST (buffer);/* -* Create the new details according to the path's length. Do not -* allocate with GFP_KERNEL_ACCOUNT because it is independent from the -* caller. +* Create the new details according to the path's length. Account to +* the calling task's memcg, like the other Landlock per-domain +* allocations, even if it may not control the related size. */ - details =kzalloc_flex (*details, exe_path, path_size); + details = +kzalloc_flex (*details, exe_path, path_size,GFP_KERNEL_ACCOUNT );if (!details)return ERR_PTR (-ENOMEM );
security/landlock/domain.h +1 -4
@@ -33,10 +33,7 @@ enum landlock_log_status {* Rarely accessed, mainly when logging the first domain's denial. * * The contained pointers are initialized at the domain creation time and never -* changed again. Contrary to most other Landlock object types, this one is -* not allocated with GFP_KERNEL_ACCOUNT because its size may not be under the -* caller's control (e.g. unknown exe_path) and the data is not explicitly -* requested nor used by tasks. +* changed again. */ struct landlock_details {/**
Greg Kroah-Hartman
maintainerPATCH 607/675 audit: widen ino fields to u64
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Layton <[email protected]>
[ Upstream commit 125dfa218134df7cc112667e92984de9d8cd0bf6 ]
inode->i_ino is being widened from unsigned long to u64. The audit subsystem uses unsigned long ino in struct fields, function parameters, and local variables that store inode numbers from arbitrary filesystems. On 32-bit platforms this truncates inode numbers that exceed 32 bits, which will cause incorrect audit log entries and broken watch/mark comparisons.
Widen all audit ino fields, parameters, and locals to u64, and update the inode format string from %lu to %llu to match.
Stable-dep-of: 81905b5acbe7 ("audit: fix recursive locking deadlock in audit_dupe_exe()")
--- include/linux/audit.h | 2 +- kernel/audit.h | 13 ++++++------- kernel/audit_fsnotify.c | 4 ++-- kernel/audit_watch.c | 12 ++++++------ kernel/auditsc.c | 4 ++-- 5 files changed, 17 insertions(+), 18 deletions(-)
include/linux/audit.h +1 -1
@@ -16,7 +16,7 @@#include <uapi/linux/netfilter/nf_tables.h> #include <uapi/linux/fanotify.h> -#define AUDIT_INO_UNSET ((unsigned long)-1) +#define AUDIT_INO_UNSET ((u64)-1)#define AUDIT_DEV_UNSET ((dev_t)-1)struct audit_sig_info {
kernel/audit.h +6 -7
@@ -76,7 +76,7 @@ struct audit_names {int name_len;/* number of chars to log */ bool hidden;/* don't log this record */ -unsigned long ino; +u64 ino;dev_t dev;umode_t mode;kuid_t uid;
@@ -225,9 +225,9 @@ extern int auditd_test_task(struct task_#define AUDIT_INODE_BUCKETS 32extern struct list_head audit_inode_hash[AUDIT_INODE_BUCKETS ]; -static inline int audit_hash_ino (u32 ino) +static inline int audit_hash_ino (u64 ino) { -return (ino & (AUDIT_INODE_BUCKETS -1 )); +return ((u32 )ino & (AUDIT_INODE_BUCKETS -1 )); }/* Indicates that audit should log the full pathname. */
@@ -277,16 +277,15 @@ extern int audit_to_watch(struct audit_kextern int audit_add_watch (struct audit_krule *krule,struct list_head **list);extern void audit_remove_watch_rule (struct audit_krule *krule);extern char *audit_watch_path (struct audit_watch *watch); -extern int audit_watch_compare (struct audit_watch *watch,unsigned long ino, -dev_t dev); +extern int audit_watch_compare (struct audit_watch *watch,u64 ino,dev_t dev);extern struct audit_fsnotify_mark *audit_alloc_mark (struct audit_krule *krule,char *pathname,int len);extern char *audit_mark_path (struct audit_fsnotify_mark *mark);extern void audit_remove_mark (struct audit_fsnotify_mark *audit_mark);extern void audit_remove_mark_rule (struct audit_krule *krule); -extern int audit_mark_compare (struct audit_fsnotify_mark *mark, -unsigned long ino,dev_t dev); +extern int audit_mark_compare (struct audit_fsnotify_mark *mark,u64 ino, +dev_t dev);extern int audit_dupe_exe (struct audit_krule *new,struct audit_krule *old);extern int audit_exe_compare (struct task_struct *tsk,struct audit_fsnotify_mark *mark);
kernel/audit_fsnotify.c +2 -2
@@ -25,7 +25,7 @@*/ struct audit_fsnotify_mark {dev_t dev;/* associated superblock device */ -unsigned long ino;/* associated inode number */ +u64 ino;/* associated inode number */ char *path;/* insertion path */ struct fsnotify_mark mark;/* fsnotify mark on the inode */ struct audit_krule *rule;
@@ -57,7 +57,7 @@ char *audit_mark_path(struct audit_fsnotreturn mark->path; } -int audit_mark_compare (struct audit_fsnotify_mark *mark,unsigned long ino,dev_t dev) +int audit_mark_compare (struct audit_fsnotify_mark *mark,u64 ino,dev_t dev) {if (mark->ino ==AUDIT_INO_UNSET )return 0 ;
kernel/audit_watch.c +6 -6
@@ -37,7 +37,7 @@ struct audit_watch {refcount_t count;/* reference count */ dev_t dev;/* associated superblock device */ char *path;/* insertion path */ -unsigned long ino;/* associated inode number */ +u64 ino;/* associated inode number */ struct audit_parent *parent;/* associated parent */ struct list_head wlist;/* entry in parent->watches list */ struct list_head rules;/* anchor for krule->rlist */
@@ -125,7 +125,7 @@ char *audit_watch_path(struct audit_watcreturn watch->path; } -int audit_watch_compare (struct audit_watch *watch,unsigned long ino,dev_t dev) +int audit_watch_compare (struct audit_watch *watch,u64 ino,dev_t dev) {return (watch->ino !=AUDIT_INO_UNSET ) && (watch->ino == ino) &&
@@ -244,7 +244,7 @@ static void audit_watch_log_rule_change(/* Update inode info in audit rules based on filesystem event. */ static void audit_update_watch (struct audit_parent *parent,const struct qstr *dname,dev_t dev, -unsigned long ino,unsigned invalidating) +u64 ino,unsigned invalidating) {struct audit_watch *owatch, *nwatch, *nextw;struct audit_krule *r, *nextr;
@@ -285,7 +285,7 @@ static void audit_update_watch(struct aulist_del (&oentry->rule.list);audit_panic ("error updating watch, removing" ); }else { -int h =audit_hash_ino ((u32 )ino); +int h =audit_hash_ino (ino);/* * nentry->rule.watch == oentry->rule.watch so
@@ -439,7 +439,7 @@ int audit_add_watch(struct audit_krule *audit_add_to_parent (krule, parent); - h =audit_hash_ino ((u32 )watch->ino); + h =audit_hash_ino (watch->ino); *list = &audit_inode_hash[h]; error:path_put (&parent_path);
@@ -527,7 +527,7 @@ int audit_dupe_exe(struct audit_krule *nint audit_exe_compare (struct task_struct *tsk,struct audit_fsnotify_mark *mark) {struct file *exe_file; -unsigned long ino; +u64 ino;dev_t dev;/* only do exe filtering if we are recording @current events/records */
kernel/auditsc.c +2 -2
@@ -886,7 +886,7 @@ static int audit_filter_inode_name(strucstruct audit_names *n, struct audit_context *ctx) { - int h = audit_hash_ino((u32)n->ino); + int h = audit_hash_ino(n->ino);struct list_head *list = &audit_inode_hash[h];return __audit_filter_op (tsk, ctx, list, n, ctx->major);
@@ -1534,7 +1534,7 @@ static void audit_log_name(struct audit_audit_log_format (ab," name=(null)" );if (n->ino !=AUDIT_INO_UNSET ) - audit_log_format(ab, " inode=%lu dev=%02x:%02x mode=%#ho ouid=%u ogid=%u rdev=%02x:%02x", + audit_log_format(ab, " inode=%llu dev=%02x:%02x mode=%#ho ouid=%u ogid=%u rdev=%02x:%02x", n->ino, MAJOR(n->dev), MINOR(n->dev),
Greg Kroah-Hartman
maintainerPATCH 608/675 audit: use unsigned int instead of unsigned
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ricardo Robaina <[email protected]>
[ Upstream commit 8b226771014beab1292081151a99530886ce54b4 ]
Address checkpatch.pl warning below, across the audit subsystem:
WARNING: Prefer 'unsigned int' to bare use of 'unsigned'
Minor cleanup, no functional changes.
Stable-dep-of: 81905b5acbe7 ("audit: fix recursive locking deadlock in audit_dupe_exe()")
--- include/linux/audit.h | 4 ++-- include/linux/audit_arch.h | 12 ++++++------ kernel/audit.c | 2 +- kernel/audit.h | 2 +- kernel/audit_tree.c | 2 +- kernel/audit_watch.c | 2 +- kernel/auditfilter.c | 8 ++++---- kernel/auditsc.c | 2 +- lib/compat_audit.c | 12 ++++++------ 9 files changed, 23 insertions(+), 23 deletions(-)
include/linux/audit.h +2 -2
@@ -125,8 +125,8 @@ enum audit_nfcfgop { AUDIT_NFT_OP_INVALID, }; -extern int __init audit_register_class (int class,unsigned *list); -extern int audit_classify_syscall (int abi,unsigned syscall); +extern int __init audit_register_class (int class,unsigned int *list); +extern int audit_classify_syscall (int abi,unsigned int syscall);extern int audit_classify_arch (int arch);/* audit_names->type values */
include/linux/audit_arch.h +6 -6
@@ -21,13 +21,13 @@ enum auditsc_class_t {AUDITSC_NVALS /* count */ }; -extern int audit_classify_compat_syscall (int abi,unsigned syscall); +extern int audit_classify_compat_syscall (int abi,unsigned int syscall);/* only for compat system calls */ -extern unsigned compat_write_class[]; -extern unsigned compat_read_class[]; -extern unsigned compat_dir_class[]; -extern unsigned compat_chattr_class[]; -extern unsigned compat_signal_class[]; +extern unsigned int compat_write_class[]; +extern unsigned int compat_read_class[]; +extern unsigned int compat_dir_class[]; +extern unsigned int compat_chattr_class[]; +extern unsigned int compat_signal_class[];#endif
kernel/audit.c +1 -1
@@ -2030,7 +2030,7 @@ void audit_log_vformat(struct audit_buff* here and AUDIT_BUFSIZ is at least 1024, then we can * log everything that printk could have logged. */ avail =audit_expand (ab, -max_t (unsigned,AUDIT_BUFSIZ ,1 +len-avail)); + max_t(unsigned int, AUDIT_BUFSIZ, 1+len-avail));if (!avail) goto out_va_end; len =vsnprintf (skb_tail_pointer (skb), avail, fmt, args2);
kernel/audit.h +1 -1
@@ -233,7 +233,7 @@ static inline int audit_hash_ino(u64 ino/* Indicates that audit should log the full pathname. */ #define AUDIT_NAME_FULL -1 -extern int audit_match_class (int class,unsigned syscall); +extern int audit_match_class (int class,unsigned int syscall);extern int audit_comparator (const u32 left,const u32 op,const u32 right);extern int audit_uid_comparator (kuid_t left,u32 op,kuid_t right);extern int audit_gid_comparator (kgid_t left,u32 op,kgid_t right);
kernel/audit_tree.c +1 -1
@@ -33,7 +33,7 @@ struct audit_chunk {struct audit_node {struct list_head list;struct audit_tree *owner; -unsigned index;/* index; upper bit indicates 'will prune' */ +unsigned int index;/* index; upper bit indicates 'will prune' */ } owners[] __counted_by(count); };
kernel/audit_watch.c +1 -1
@@ -244,7 +244,7 @@ static void audit_watch_log_rule_change(/* Update inode info in audit rules based on filesystem event. */ static void audit_update_watch (struct audit_parent *parent,const struct qstr *dname,dev_t dev, -u64 ino,unsigned invalidating) +u64 ino,unsigned int invalidating) {struct audit_watch *owatch, *nwatch, *nextw;struct audit_krule *r, *nextr;
kernel/auditfilter.c +4 -4
@@ -165,13 +165,13 @@ static inline int audit_to_inode(structstatic __u32 *classes[AUDIT_SYSCALL_CLASSES ]; -int __init audit_register_class (int class,unsigned *list) +int __init audit_register_class (int class,unsigned int *list) {__u32 *p =kcalloc (AUDIT_BITMASK_SIZE ,sizeof (__u32),GFP_KERNEL );if (!p)return -ENOMEM ;while (*list != ~0U ) { -unsigned n = *list++; +unsigned int n = *list++;if (n >=AUDIT_BITMASK_SIZE *32 -AUDIT_SYSCALL_CLASSES ) {kfree (p);return -EINVAL ;
@@ -186,7 +186,7 @@ int __init audit_register_class(int clasreturn 0 ; } -int audit_match_class (int class,unsigned syscall) +int audit_match_class (int class,unsigned int syscall) {if (unlikely (syscall >=AUDIT_BITMASK_SIZE *32 ))return 0 ;
@@ -237,7 +237,7 @@ static int audit_match_signal(struct aud/* Common user-space to kernel rule translation. */ static inline struct audit_entry *audit_to_entry_common (struct audit_rule_data *rule) { -unsigned listnr; +unsigned int listnr;struct audit_entry *entry;int i, err;
kernel/auditsc.c +1 -1
@@ -150,7 +150,7 @@ static const struct audit_nfcfgop_tab austatic int audit_match_perm (struct audit_context *ctx,int mask) { -unsigned n; +unsigned int n;if (unlikely (!ctx))return 0 ;
lib/compat_audit.c +6 -6
@@ -4,32 +4,32 @@#include <linux/audit_arch.h> #include <asm/unistd32.h> -unsigned compat_dir_class[] = { +unsigned int compat_dir_class[] = { #include <asm-generic/audit_dir_write.h> ~0U }; -unsigned compat_read_class[] = { +unsigned int compat_read_class[] = { #include <asm-generic/audit_read.h> ~0U }; -unsigned compat_write_class[] = { +unsigned int compat_write_class[] = { #include <asm-generic/audit_write.h> ~0U }; -unsigned compat_chattr_class[] = { +unsigned int compat_chattr_class[] = { #include <asm-generic/audit_change_attr.h> ~0U }; -unsigned compat_signal_class[] = { +unsigned int compat_signal_class[] = { #include <asm-generic/audit_signal.h> ~0U }; -int audit_classify_compat_syscall (int abi,unsigned syscall) +int audit_classify_compat_syscall (int abi,unsigned int syscall) {switch (syscall) {#ifdef __NR_open
Greg Kroah-Hartman
maintainerPATCH 609/675 audit: fix recursive locking deadlock in audit_dupe_exe()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ricardo Robaina <[email protected]>
[ Upstream commit 81905b5acbe77284734438df3fbec1158e6429a3 ]
A deadlock occurs in the audit subsystem when duplicating executable-related rules.
When a file is moved (e.g., via do_renameat2()), the VFS layer locks the parent directory (I_MUTEX_PARENT), which synchronously triggers an fsnotify_move event. If an existing executable audit rule matches the file being moved, the audit subsystem catches this event and calls audit_dupe_exe() to duplicate the watch and update the rule. Then, audit_alloc_mark() would call kern_path_parent() to resolve the path, leading to a blind attempt to acquire the exact same I_MUTEX_PARENT lock already held by the task, resulting in the following recursive locking deadlock:
============================================
WARNING: possible recursive locking detected 6.12.0-55.27.1.el10_0.x86_64+debug #1 Not tainted
--------------------------------------------
mv/5099 is trying to acquire lock:
ffff888132845358 (&inode->i_sb->s_type->i_mutex_dir_key/1){+.+.}-{3:3},
at: __kern_path_locked+0x10a/0x2f0
but task is already holding lock:
ffff888132846b58 (&inode->i_sb->s_type->i_mutex_dir_key/1){+.+.}-{3:3},
at: lock_two_directories+0x13f/0x2b0
other info that might help us debug this:
Possible unsafe locking scenario:
CPU0
---- lock(&inode->i_sb->s_type->i_mutex_dir_key/1);
lock(&inode->i_sb->s_type->i_mutex_dir_key/1);
*** DEADLOCK ***
May be due to missing lock nesting notation
6 locks held by mv/5099:
#0: ffff888112a9c440 (sb_writers#13)
at: do_renameat2+0x34c/0xbc0
#1: ffff888112a9c790 (&type->s_vfs_rename_key#3)
at: do_renameat2+0x415/0xbc0
#2: ffff888132846b58 (&inode->i_sb->s_type->i_mutex_dir_key/1)
at: lock_two_directories+0x13f/0x2b0
#3: ffff888132845358 (&inode->i_sb->s_type->i_mutex_dir_key/5)
at: lock_two_directories+0x175/0x2b0
#4: ffffffffb3a1fb10 (&fsnotify_mark_srcu)
at: fsnotify+0x454/0x28a0
#5: ffffffffaf886230 (audit_filter_mutex)
at: audit_update_watch+0x36/0x11e0
stack backtrace: Call Trace: <TASK> dump_stack_lvl+0x6f/0xb0 print_deadlock_bug.cold+0xbd/0xca validate_chain+0x83a/0xf00 __lock_acquire+0xcac/0x1d20 lock_acquire.part.0+0x11b/0x360 down_write_nested+0x9f/0x230 __kern_path_locked+0x10a/0x2f0 kern_path_locked+0x26/0x40 audit_alloc_mark+0xfb/0x4f0 audit_dupe_exe+0x6c/0xe0 audit_dupe_rule+0x6c2/0xc00 audit_update_watch+0x4cc/0x11e0 audit_watch_handle_event+0x12c/0x1b0 send_to_group+0x5d0/0x8b0 fsnotify+0x615/0x28a0 fsnotify_move+0x1d8/0x630 vfs_rename+0xdcd/0x1df0 do_renameat2+0x9d4/0xbc0 __x64_sys_renameat+0x192/0x260 do_syscall_64+0x92/0x180 entry_SYSCALL_64_after_hwframe+0x76/0x7e RIP: 0033:0x7f0491fe8c4e Code: 0f 1f 40 00 48 8b 15 c1 e1 16 00 f7 d8 64 89 02 b8 ff ff ff ff c3 66 0f 1f 44 00 00 f3 0f 1e fa 49 89 ca b8 08 01 00 00 0f 05 <48> 3d 00 f0 ff ff 77 0a c3 66 0f 1f 84 00 00 00 00 00 48 8b 15 89 RSP: 002b:00007ffc7210bf38 EFLAGS: 00000246 ORIG_RAX: 0000000000000108 RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f0491fe8c4e RDX: 0000000000000003 RSI: 00007ffc7210e6c8 RDI: 00000000ffffff9c RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000001 R10: 00005575eb2dae2a R11: 0000000000000246 R12: 00005575eb2dae2a R13: 00007ffc7210e6c8 R14: 0000000000000003 R15: 00000000ffffff9c </TASK>
The aforementioned deadlock can be consistently reproduced by running the script below:
audit-dupe-exe-deadlock.sh
--------------------------
#!/bin/bash
auditctl -D
mkdir -p /tmp/foo
touch /tmp/file
auditctl -a always,exit -F exe=/tmp/file -F path=/tmp/file -S all -k dr mv /tmp/file /tmp/foo/file
rm -Rf /tmp/foo
This patch fixes the issue by introducing struct audit_watch_ctx to pass the fsnotify event context down to audit_alloc_mark(). By utilizing the already-resolved directory inode provided by the event, we bypass the kern_path_parent() path resolution entirely, safely avoiding the recursive lock. Furthermore, it explicitly allows duplicate fsnotify marks (allow_dups = 1) during the rename update, allowing the new rule's mark to safely coexist with the old rule's mark until the old rule is freed.
P.S.: This issue was identified and reproduced during a comprehensive code coverage analysis of the audit subsystem. The full report is available at the link below:
https://people.redhat.com/rrobaina/audit-code-coverage-analysis.pdf
P.P.S: With the permission of both Ricardo and Nathan, I've squashed a fixup patch from Nathan that addresses a compile time error when CONFIG_AUDITSYSCALL=n.
--- kernel/audit.h | 17 ++++++++++++----- kernel/audit_fsnotify.c | 32 +++++++++++++++++++++++--------- kernel/audit_watch.c | 25 +++++++++++++++++-------- kernel/auditfilter.c | 9 +++++---- 4 files changed, 57 insertions(+), 26 deletions(-)
kernel/audit.h +12 -5
@@ -256,8 +256,13 @@ extern int audit_del_rule(struct audit_eextern void audit_free_rule_rcu (struct rcu_head *head);extern struct list_head audit_filter_list[]; -extern struct audit_entry *audit_dupe_rule (struct audit_krule *old); +struct audit_watch_ctx { +struct inode *dir; +struct inode *child; +}; +extern struct audit_entry *audit_dupe_rule (struct audit_krule *old, +struct audit_watch_ctx *ctx);extern void audit_log_d_path_exe (struct audit_buffer *ab,struct mm_struct *mm);
@@ -280,13 +285,15 @@ extern char *audit_watch_path(struct audextern int audit_watch_compare (struct audit_watch *watch,u64 ino,dev_t dev);extern struct audit_fsnotify_mark *audit_alloc_mark (struct audit_krule *krule, -char *pathname,int len); +char *pathname,int len, +struct audit_watch_ctx *ctx);extern char *audit_mark_path (struct audit_fsnotify_mark *mark);extern void audit_remove_mark (struct audit_fsnotify_mark *audit_mark);extern void audit_remove_mark_rule (struct audit_krule *krule);extern int audit_mark_compare (struct audit_fsnotify_mark *mark,u64 ino,dev_t dev); -extern int audit_dupe_exe (struct audit_krule *new,struct audit_krule *old); +extern int audit_dupe_exe (struct audit_krule *new,struct audit_krule *old, +struct audit_watch_ctx *ctx);extern int audit_exe_compare (struct task_struct *tsk,struct audit_fsnotify_mark *mark);
@@ -317,13 +324,13 @@ extern struct list_head *audit_killed_tr#define audit_watch_path (w) ""#define audit_watch_compare (w, i, d) 0 -#define audit_alloc_mark (k, p, l) (ERR_PTR(-EINVAL)) +#define audit_alloc_mark (k, p, l, c) (ERR_PTR(-EINVAL))#define audit_mark_path (m) ""#define audit_remove_mark (m) do { } while (0)#define audit_remove_mark_rule (k) do { } while (0)#define audit_mark_compare (m, i, d) 0#define audit_exe_compare (t, m) (-EINVAL) -#define audit_dupe_exe (n, o) (-EINVAL) +#define audit_dupe_exe (n, o, c) (-EINVAL)#define audit_remove_tree_rule (rule) BUG()#define audit_add_tree_rule (rule) -EINVAL
kernel/audit_fsnotify.c +23 -9
@@ -71,19 +71,30 @@ static void audit_update_mark(struct aud audit_mark->ino = inode ? inode->i_ino :AUDIT_INO_UNSET ; } -struct audit_fsnotify_mark *audit_alloc_mark (struct audit_krule *krule,char *pathname,int len) +struct audit_fsnotify_mark *audit_alloc_mark (struct audit_krule *krule,char *pathname, +int len,struct audit_watch_ctx *ctx) {struct audit_fsnotify_mark *audit_mark;struct path path;struct dentry *dentry; -int ret; +struct inode *dir, *child; +int ret, allow_dups;if (pathname[0 ] !='/' || pathname[len-1 ] =='/' )return ERR_PTR (-EINVAL ); - dentry =kern_path_parent (pathname, &path); -if (IS_ERR (dentry)) -return ERR_CAST (dentry);/* returning an error */ +if (!ctx) { + dentry =kern_path_parent (pathname, &path); +if (IS_ERR (dentry)) +return ERR_CAST (dentry);/* returning an error */ + dir =d_inode (path.dentry); + child =d_inode (dentry); + allow_dups =0 ; + }else { + dir = ctx->dir; + child = ctx->child; + allow_dups =1 ; + } audit_mark =kzalloc (sizeof (*audit_mark),GFP_KERNEL );if (unlikely (!audit_mark)) {
@@ -94,18 +105,21 @@ struct audit_fsnotify_mark *audit_alloc_fsnotify_init_mark (&audit_mark->mark, audit_fsnotify_group); audit_mark->mark.mask =AUDIT_FS_EVENTS ; audit_mark->path = pathname; -audit_update_mark (audit_mark, dentry->d_inode); audit_mark->rule = krule; - ret =fsnotify_add_inode_mark (&audit_mark->mark, path.dentry->d_inode,0 ); +audit_update_mark (audit_mark, child); + ret =fsnotify_add_inode_mark (&audit_mark->mark, dir, allow_dups); +if (ret <0 ) { audit_mark->path =NULL ;fsnotify_put_mark (&audit_mark->mark); audit_mark =ERR_PTR (ret); } out: -dput (dentry); -path_put (&path); +if (!ctx) { +dput (dentry); +path_put (&path); + }return audit_mark; }
kernel/audit_watch.c +17 -8
@@ -244,7 +244,8 @@ static void audit_watch_log_rule_change(/* Update inode info in audit rules based on filesystem event. */ static void audit_update_watch (struct audit_parent *parent,const struct qstr *dname,dev_t dev, -u64 ino,unsigned int invalidating) +u64 ino,unsigned int invalidating, +struct audit_watch_ctx *ctx) {struct audit_watch *owatch, *nwatch, *nextw;struct audit_krule *r, *nextr;
@@ -280,7 +281,7 @@ static void audit_update_watch(struct aulist_del (&oentry->rule.rlist);list_del_rcu (&oentry->list); - nentry =audit_dupe_rule (&oentry->rule); + nentry =audit_dupe_rule (&oentry->rule, ctx);if (IS_ERR (nentry)) {list_del (&oentry->rule.list);audit_panic ("error updating watch, removing" );
@@ -479,10 +480,17 @@ static int audit_watch_handle_event(struif (WARN_ON_ONCE (inode_mark->group != audit_watch_group))return 0 ; -if (mask & (FS_CREATE |FS_MOVED_TO ) && inode) -audit_update_watch (parent, dname, inode->i_sb->s_dev, inode->i_ino,0 ); -else if (mask & (FS_DELETE |FS_MOVED_FROM )) -audit_update_watch (parent, dname,AUDIT_DEV_UNSET ,AUDIT_INO_UNSET ,1 ); +if (mask & (FS_CREATE |FS_MOVED_TO ) && inode) { +struct audit_watch_ctx ctx = { .dir = dir, .child = inode }; + +audit_update_watch (parent, dname, inode->i_sb->s_dev, inode->i_ino,0 , + &ctx); + }else if (mask & (FS_DELETE |FS_MOVED_FROM )) { +struct audit_watch_ctx ctx = { .dir = dir, .child =NULL }; + +audit_update_watch (parent, dname,AUDIT_DEV_UNSET ,AUDIT_INO_UNSET ,1 , + &ctx); + }else if (mask & (FS_DELETE_SELF |FS_UNMOUNT |FS_MOVE_SELF ))audit_remove_parent_watches (parent);
@@ -505,7 +513,8 @@ static int __init audit_watch_init(void) }device_initcall (audit_watch_init); -int audit_dupe_exe (struct audit_krule *new,struct audit_krule *old) +int audit_dupe_exe (struct audit_krule *new,struct audit_krule *old, +struct audit_watch_ctx *ctx) {struct audit_fsnotify_mark *audit_mark;char *pathname;
@@ -514,7 +523,7 @@ int audit_dupe_exe(struct audit_krule *nif (!pathname)return -ENOMEM ; - audit_mark =audit_alloc_mark (new, pathname,strlen (pathname)); + audit_mark =audit_alloc_mark (new, pathname,strlen (pathname), ctx);if (IS_ERR (audit_mark)) {kfree (pathname);return PTR_ERR (audit_mark);
kernel/auditfilter.c +5 -4
@@ -590,7 +590,7 @@ static struct audit_entry *audit_data_to err =PTR_ERR (str); goto exit_free; } - audit_mark =audit_alloc_mark (&entry->rule, str, f_val); + audit_mark =audit_alloc_mark (&entry->rule, str, f_val,NULL );if (IS_ERR (audit_mark)) {kfree (str); err =PTR_ERR (audit_mark);
@@ -818,7 +818,8 @@ static inline int audit_dupe_lsm_field(s* rule with the new rule in the filterlist, then free the old rule. * The rlist element is undefined; list manipulations are handled apart from * the initial copy. */ -struct audit_entry *audit_dupe_rule (struct audit_krule *old) +struct audit_entry *audit_dupe_rule (struct audit_krule *old, +struct audit_watch_ctx *ctx) {u32 fcount = old->field_count;struct audit_entry *entry;
@@ -877,7 +878,7 @@ struct audit_entry *audit_dupe_rule(stru new->filterkey = fk;break ;case AUDIT_EXE : - err =audit_dupe_exe (new, old); + err =audit_dupe_exe (new, old, ctx);break ; }if (err) {
@@ -1416,7 +1417,7 @@ static int update_lsm_rule(struct audit_if (!security_audit_rule_known (r))return 0 ; - nentry =audit_dupe_rule (r); + nentry =audit_dupe_rule (r,NULL );if (entry->rule.exe)audit_remove_mark (entry->rule.exe);if (IS_ERR (nentry)) {
Greg Kroah-Hartman
maintainerPATCH 610/675 fuse-uring: fix race between registration and connection abortion
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joanne Koong <[email protected]>
[ Upstream commit 952b5d36f6a298f57c52a59e72076c69386a8aaf ]
This fixes this race:
- thread a: io_uring_enter -> register sqe -> fuse_uring_create_ring_ent -> allocate ent but doesn't grab queue_ref yet
- thread b: fuse_conn_destroy() -> fuse_chan_abort() -> fuse_uring_abort() is a no-op due to queue ref being 0
- thread a: grabs the queue_ref, queue_ref is now 1, rest of fuse_uring_do_register() logic executes
- thread b: fuse_chan_abort() returns, fuse_chan_wait_aborted() now runs and calls
"wait_event(ring->stop_waitq, atomic_read(&ring->queue_refs) == 0);"
The abort/unmount thread will hang indefinitely in unkillable state as nothing will decrement queue_refs or wake stop_waitq, and the ring, queue, and ent are leaked.
Fix this by checking fch->connected under fch->lock after the created ent has grabbed a ref count on the queue. This ensures that in the scenario above, it is guaranteed that we either release the queue ref and wake up stop_waitq (in case fuse_chan_wait_aborted() is already waiting) in fuse_uring_do_register() when we detect !fch->connected, or if the connection is aborted after the check, it is guaranteed that the async teardown worker will be running in the background cleaning up ents and decrementing the ent's ref on the queue, which will unblock the eventual queue and ring teardown.
--- fs/fuse/dev_uring.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-)
fs/fuse/dev_uring.c +16 -6
@@ -998,15 +998,26 @@ static bool is_ring_ready(struct fuse_ri/* * fuse_uring_req_fetch command handling */ -static void fuse_uring_do_register (struct fuse_ring_ent *ent, -struct io_uring_cmd *cmd, -unsigned int issue_flags) +static int fuse_uring_do_register (struct fuse_ring_ent *ent, +struct io_uring_cmd *cmd, +unsigned int issue_flags) {struct fuse_ring_queue *queue = ent->queue;struct fuse_ring *ring = queue->ring;struct fuse_conn *fc = ring->fc;struct fuse_iqueue *fiq = &fc->iq; +spin_lock (&fc->lock); +/* abort teardown path is running or has run */ +if (!fc->connected) { +spin_unlock (&fc->lock); +if (atomic_dec_and_test (&ring->queue_refs)) +wake_up_all (&ring->stop_waitq); +kfree (ent); +return -ECONNABORTED ; + } +spin_unlock (&fc->lock); +fuse_uring_prepare_cancel (cmd, issue_flags, ent);spin_lock (&queue->lock);
@@ -1023,6 +1034,7 @@ static void fuse_uring_do_register(strucwake_up_all (&fc->blocked_waitq); } } +return 0 ; }/*
@@ -1138,9 +1150,7 @@ static int fuse_uring_register(struct ioif (IS_ERR (ent))return PTR_ERR (ent); -fuse_uring_do_register (ent, cmd, issue_flags); - -return 0 ; +return fuse_uring_do_register (ent, cmd, issue_flags); }/*
Greg Kroah-Hartman
maintainerPATCH 611/675 xfs: dont replace the wrong part of the cow fork
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Darrick J. Wong" <[email protected]>
[ Upstream commit a1caeeadbf57ff86dfc3454398c46de86056a74e ]
LOLLM points out that xfs_iext_lookup_extent can return a @got where got->br_startoff < startoff. In this case, xrep_cow_replace_range replaces the entire mapping instead of just the part that had been marked bad in the bitmap, but advances the bitmap cursor in xrep_cow_replace by the amount replaced. As a result, we fail to replace the end of the bad range, and replace part of the good range.
Fix this by rewriting the replace method to handle replacing the middle of a cow fork mapping. This we do by returning both the current mapping as @got, and the subset of the mapping that we want to replace as @rep, using @rep to store the results of the new allocation, and comparing @rep to @got to figure out the exact transformations needed.
--- fs/xfs/scrub/cow_repair.c | 203 +++++++++++++++++++++++++++++----------------- fs/xfs/scrub/trace.h | 28 +++--- 2 files changed, 148 insertions(+), 83 deletions(-)
fs/xfs/scrub/cow_repair.c +131 -72
@@ -80,12 +80,6 @@ struct xrep_cow {unsigned int next_bno; }; -/* CoW staging extent. */ -struct xrep_cow_extent { -xfs_fsblock_t fsbno; -xfs_extlen_t len; -}; -/* * Mark the part of the file range that corresponds to the given physical * space. Caller must ensure that the physical range is within xc->irec.
@@ -401,22 +395,21 @@ out_rtg: STATIC intxrep_cow_alloc (struct xfs_scrub *sc, -xfs_extlen_t maxlen, -struct xrep_cow_extent *repl) +struct xfs_bmbt_irec *del) {struct xfs_alloc_arg args = { .tp = sc->tp, .mp = sc->mp, .oinfo =XFS_RMAP_OINFO_SKIP_UPDATE , .minlen =1 , - .maxlen = maxlen, + .maxlen = del->br_blockcount, .prod =1 , .resv =XFS_AG_RESV_NONE , .datatype =XFS_ALLOC_USERDATA , };int error; - error =xfs_trans_reserve_more (sc->tp, maxlen,0 ); + error =xfs_trans_reserve_more (sc->tp, del->br_blockcount,0 );if (error)return error;
@@ -429,8 +422,8 @@ xrep_cow_alloc(xfs_refcount_alloc_cow_extent (sc->tp, false, args.fsbno, args.len); - repl->fsbno = args.fsbno; - repl->len = args.len; + del->br_startblock = args.fsbno; + del->br_blockcount = args.len;return 0 ; }
@@ -441,10 +434,12 @@ xrep_cow_alloc( STATIC intxrep_cow_alloc_rt (struct xfs_scrub *sc, -xfs_extlen_t maxlen, -struct xrep_cow_extent *repl) +struct xfs_bmbt_irec *del) { -xfs_rtxlen_t maxrtx =xfs_rtb_to_rtx (sc->mp, maxlen); +xfs_fsblock_t fsbno; +xfs_rtxlen_t maxrtx = +min (U32_MAX ,xfs_blen_to_rtbxlen (sc->mp, del->br_blockcount)); +xfs_extlen_t len;int error; error =xfs_trans_reserve_more (sc->tp,0 , maxrtx);
@@ -452,11 +447,14 @@ xrep_cow_alloc_rt(return error; error =xfs_rtallocate_rtgs (sc->tp,NULLRTBLOCK ,1 , maxrtx,1 , false, - false, &repl->fsbno, &repl->len); + false, &fsbno, &len);if (error)return error; -xfs_refcount_alloc_cow_extent (sc->tp, true, repl->fsbno, repl->len); +xfs_refcount_alloc_cow_extent (sc->tp, true, fsbno, len); + + del->br_startblock = fsbno; + del->br_blockcount = len;return 0 ; }
@@ -470,19 +468,19 @@ static inline intxrep_cow_find_mapping ( struct xrep_cow *xc, struct xfs_iext_cursor *icur, - xfs_fileoff_t startoff, - struct xfs_bmbt_irec *got) + xfs_fileoff_t badoff, + xfs_extlen_t badlen, + struct xfs_bmbt_irec *got, + struct xfs_bmbt_irec *rep) { struct xfs_inode *ip = xc->sc->ip;struct xfs_ifork *ifp =xfs_ifork_ptr (ip,XFS_COW_FORK ); -if (!xfs_iext_lookup_extent (ip, ifp, startoff, icur, got)) +if (!xfs_iext_lookup_extent (ip, ifp, badoff, icur, got)) goto bad; +memcpy (rep, got,sizeof (*rep)); -if (got->br_startoff > startoff) - goto bad; - -if (got->br_blockcount ==0 ) +if (got->br_startoff > badoff) goto bad;if (isnullstartblock (got->br_startblock))
@@ -491,6 +489,24 @@ xrep_cow_find_mapping(if (xfs_bmap_is_written_extent (got)) goto bad; +if (got->br_startoff < badoff) { +const int64_t delta = badoff - got->br_startoff; + + rep->br_blockcount -= delta; + rep->br_startoff += delta; + rep->br_startblock += delta; + } + +if (got->br_startoff + got->br_blockcount > badoff + badlen) { +const int64_t delta = (got->br_startoff + got->br_blockcount) - + (badoff + badlen); + + rep->br_blockcount -= delta; + } + +if (got->br_blockcount ==0 ) + goto bad; +return 0 ; bad:ASSERT (0 );
@@ -501,46 +517,92 @@ bad:#define REPLACE_RIGHT_SIDE (1U << 1)/* -* Given a CoW fork mapping @got and a replacement mapping @repl, remap the -* beginning of @got with the space described by @rep. +* Given a CoW fork mapping @got and a replacement mapping @rep, map the space +* described by @rep into the cow fork, pushing aside @got as necessary. @icur +* must point to iext tree leaf containing @got. */ static inline void xrep_cow_replace_mapping ( -struct xfs_inode *ip, -struct xfs_iext_cursor *icur, -const struct xfs_bmbt_irec *got, -const struct xrep_cow_extent *repl) +struct xfs_inode *ip, +struct xfs_iext_cursor *icur, +struct xfs_bmbt_irec *got, +struct xfs_bmbt_irec *rep) { -struct xfs_bmbt_irec new = *got;/* struct copy */ +struct xfs_ifork *ifp =xfs_ifork_ptr (ip,XFS_COW_FORK ); +xfs_fileoff_t rep_endoff = + rep->br_startoff + rep->br_blockcount; +xfs_fileoff_t got_endoff = + got->br_startoff + got->br_blockcount; +uint32_t state =BMAP_COWFORK ; -ASSERT (repl->len >0 ); +ASSERT (rep->br_blockcount >0 );ASSERT (!isnullstartblock (got->br_startblock)); +ASSERT (got->br_startoff <= rep->br_startoff); +ASSERT (got_endoff >= rep_endoff); -trace_xrep_cow_replace_mapping (ip, got, repl->fsbno, repl->len); +trace_xrep_cow_replace_mapping (ip, got, rep); -if (got->br_blockcount == repl->len) { +if (got->br_startoff == rep->br_startoff) + state |=BMAP_LEFT_FILLING ; +if (got_endoff == rep_endoff) + state |=BMAP_RIGHT_FILLING ; + +switch (state & (BMAP_LEFT_FILLING |BMAP_RIGHT_FILLING )) { +case BMAP_LEFT_FILLING |BMAP_RIGHT_FILLING :/* -* The new extent is a complete replacement for the existing -* extent. Update the COW fork record. +* Replacement matches the whole mapping, update the record. */ - new.br_startblock = repl->fsbno; -xfs_iext_update_extent (ip,BMAP_COWFORK , icur, &new); -return ; - } +xfs_iext_update_extent (ip, state, icur, rep); +break ; +case BMAP_LEFT_FILLING : +/* +* Replace the first part of the mapping: Update the cursor +* position with the new mapping, then add a record with the +* tail of the old mapping. +*/ + got->br_startoff = rep_endoff; + got->br_blockcount -= rep->br_blockcount; + got->br_startblock += rep->br_blockcount; + +xfs_iext_update_extent (ip, state, icur, rep); +xfs_iext_next (ifp, icur); +xfs_iext_insert (ip, icur, got, state); +break ; +case BMAP_RIGHT_FILLING : +/* +* Replacing the last part of the mapping. Shorten the current +* mapping then add a record with the new mapping. +*/ + got->br_blockcount -= rep->br_blockcount; -/* -* The new extent can replace the beginning of the COW fork record. -* Move the left side of @got upwards, then insert the new record. -*/ - new.br_startoff += repl->len; - new.br_startblock += repl->len; - new.br_blockcount -= repl->len; -xfs_iext_update_extent (ip,BMAP_COWFORK , icur, &new); - - new.br_startoff = got->br_startoff; - new.br_startblock = repl->fsbno; - new.br_blockcount = repl->len; -xfs_iext_insert (ip, icur, &new,BMAP_COWFORK ); +xfs_iext_update_extent (ip, state, icur, got); +xfs_iext_next (ifp, icur); +xfs_iext_insert (ip, icur, rep, state); +break ; +case 0 : +/* +* Replacing the middle of the extent. Shorten the current +* mapping, add a new record with the new mapping, and add a +* second new record with the tail of the old mapping. +*/ + got->br_blockcount = rep->br_startoff - got->br_startoff; + +struct xfs_bmbt_irec new = { + .br_startoff = rep_endoff, + .br_blockcount = got_endoff - rep_endoff, + .br_state = got->br_state, + .br_startblock = got->br_startblock + + rep->br_blockcount + + got->br_blockcount, + }; + +xfs_iext_update_extent (ip, state, icur, got); +xfs_iext_next (ifp, icur); +xfs_iext_insert (ip, icur, rep, state); +xfs_iext_next (ifp, icur); +xfs_iext_insert (ip, icur, &new, state); +break ; + } }/*
@@ -554,33 +616,30 @@ xrep_cow_replace_range( xfs_extlen_t *blockcount) {struct xfs_iext_cursor icur; -struct xrep_cow_extent repl; -struct xfs_bmbt_irec got; +struct xfs_bmbt_irec got, rep;struct xfs_scrub *sc = xc->sc; -xfs_fileoff_t nextoff; -xfs_extlen_t alloc_len; +xfs_fsblock_t old_fsbno;int error;/* -* Put the existing CoW fork mapping in @got. If @got ends before -* @rep, truncate @rep so we only replace one extent mapping at a time. +* Put the existing CoW fork mapping in @got, and put in @rep the +* contents of @got trimmed to @startoff/@blockcount. We only want +* to replace the bad region, and only one mapping at a time. */ - error =xrep_cow_find_mapping (xc, &icur, startoff, &got); + error =xrep_cow_find_mapping (xc, &icur, startoff, *blockcount, &got, + &rep);if (error)return error; - nextoff =min (startoff + *blockcount, - got.br_startoff + got.br_blockcount); + old_fsbno = rep.br_startblock;/* * Allocate a replacement extent. If we don't fill all the blocks, * shorten the quantity that will be deleted in this step. */ - alloc_len =min_t (xfs_fileoff_t,XFS_MAX_BMBT_EXTLEN , - nextoff - startoff);if (XFS_IS_REALTIME_INODE (sc->ip)) - error =xrep_cow_alloc_rt (sc, alloc_len, &repl); + error =xrep_cow_alloc_rt (sc, &rep);else - error =xrep_cow_alloc (sc, alloc_len, &repl); + error =xrep_cow_alloc (sc, &rep);if (error)return error;
@@ -588,7 +647,7 @@ xrep_cow_replace_range(* Replace the old mapping with the new one, and commit the metadata * changes made so far. */ -xrep_cow_replace_mapping (sc->ip, &icur, &got, &repl); +xrep_cow_replace_mapping (sc->ip, &icur, &got, &rep);xfs_inode_set_cowblocks_tag (sc->ip); error =xfs_defer_finish (&sc->tp);
@@ -597,15 +656,15 @@ xrep_cow_replace_range(/* Note the old CoW staging extents; we'll reap them all later. */ if (XFS_IS_REALTIME_INODE (sc->ip)) - error =xrtb_bitmap_set (&xc->old_cowfork_rtblocks, - got.br_startblock, repl.len); + error =xrtb_bitmap_set (&xc->old_cowfork_rtblocks, old_fsbno, + rep.br_blockcount);else - error =xfsb_bitmap_set (&xc->old_cowfork_fsblocks, - got.br_startblock, repl.len); + error =xfsb_bitmap_set (&xc->old_cowfork_fsblocks, old_fsbno, + rep.br_blockcount);if (error)return error; - *blockcount = repl.len; + *blockcount = rep.br_blockcount;return 0 ; }
fs/xfs/scrub/trace.h +17 -11
@@ -2672,9 +2672,9 @@ TRACE_EVENT(xrep_cow_mark_file_range, ); TRACE_EVENT(xrep_cow_replace_mapping, - TP_PROTO(struct xfs_inode *ip, const struct xfs_bmbt_irec *irec, - xfs_fsblock_t new_startblock, xfs_extlen_t new_blockcount), - TP_ARGS(ip, irec, new_startblock, new_blockcount), + TP_PROTO(struct xfs_inode *ip, const struct xfs_bmbt_irec *got, + const struct xfs_bmbt_irec *rep), + TP_ARGS(ip, got, rep), TP_STRUCT__entry( __field(dev_t, dev) __field(xfs_ino_t, ino)
@@ -2682,28 +2682,34 @@ TRACE_EVENT(xrep_cow_replace_mapping, __field(xfs_fileoff_t, startoff) __field(xfs_filblks_t, blockcount) __field(xfs_exntst_t, state) + __field(xfs_fileoff_t, new_startoff) __field(xfs_fsblock_t, new_startblock) __field(xfs_extlen_t, new_blockcount) +__field (xfs_exntst_t, new_state) ),TP_fast_assign ( __entry->dev = ip->i_mount->m_super->s_dev; __entry->ino = ip->i_ino; - __entry->startoff = irec->br_startoff; - __entry->startblock = irec->br_startblock; - __entry->blockcount = irec->br_blockcount; - __entry->state = irec->br_state; - __entry->new_startblock = new_startblock; - __entry->new_blockcount = new_blockcount; + __entry->startoff = got->br_startoff; + __entry->startblock = got->br_startblock; + __entry->blockcount = got->br_blockcount; + __entry->state = got->br_state; + __entry->new_startoff = rep->br_startoff; + __entry->new_startblock = rep->br_startblock; + __entry->new_blockcount = rep->br_blockcount; + __entry->new_state = rep->br_state; ), -TP_printk ("dev %d:%d ino 0x%llx startoff 0x%llx startblock 0x%llx fsbcount 0x%llx state 0x%x new_startblock 0x%llx new_fsbcount 0x%x" , +TP_printk ("dev %d:%d ino 0x%llx startoff 0x%llx startblock 0x%llx fsbcount 0x%llx state 0x%x new_startoff 0x%llx new_startblock 0x%llx new_fsbcount 0x%x new_state 0x%x" ,MAJOR (__entry->dev),MINOR (__entry->dev), __entry->ino, __entry->startoff, __entry->startblock, __entry->blockcount, __entry->state, + __entry->new_startoff, __entry->new_startblock, - __entry->new_blockcount) + __entry->new_blockcount, + __entry->new_state) ); TRACE_EVENT(xrep_cow_free_staging,
Greg Kroah-Hartman
maintainerPATCH 612/675 vduse: return internal vq group struct as map token
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eugenio Pérez <[email protected]>
[ Upstream commit 02e3f7ffe2906033da73b7c7ea8180b131d0cdbc ]
Return the internal struct that represents the vq group as virtqueue map token, instead of the device. This allows the map functions to access the information per group.
At this moment all the virtqueues share the same vq group, that only can point to ASID 0. This change prepares the infrastructure for actual per-group address space handling
Message-Id: <[email protected]>
Stable-dep-of: 9c1523803445 ("VDUSE: avoid leaking information to userspace")
--- drivers/vdpa/vdpa_user/iova_domain.c | 21 ++---- drivers/vdpa/vdpa_user/iova_domain.h | 5 - drivers/vdpa/vdpa_user/vduse_dev.c | 109 ++++++++++++++++++++++++++++++----- include/linux/virtio.h | 6 - 4 files changed, 108 insertions(+), 33 deletions(-)
drivers/vdpa/vdpa_user/iova_domain.c +7 -14
@@ -493,17 +493,15 @@ void vduse_domain_unmap_page(struct vdusvduse_domain_free_iova (iovad, dma_addr, size); } -void *vduse_domain_alloc_coherent (struct vduse_iova_domain *domain, -size_t size,dma_addr_t *dma_addr, -gfp_t flag) +dma_addr_t vduse_domain_alloc_coherent (struct vduse_iova_domain *domain, +size_t size,void *orig) {struct iova_domain *iovad = &domain->consistent_iovad;unsigned long limit = domain->iova_limit;dma_addr_t iova =vduse_domain_alloc_iova (iovad, size, limit); -void *orig =alloc_pages_exact (size, flag); -if (!iova || !orig) - goto err; +if (!iova) +return DMA_MAPPING_ERROR ;spin_lock (&domain->iotlb_lock); if (vduse_iotlb_add_range(domain, (u64)iova, (u64)iova + size - 1,
@@ -514,17 +512,12 @@ void *vduse_domain_alloc_coherent(struct }spin_unlock (&domain->iotlb_lock); - *dma_addr = iova; +return iova; -return orig; err: - *dma_addr =DMA_MAPPING_ERROR ; -if (orig) -free_pages_exact (orig, size); -if (iova) -vduse_domain_free_iova (iovad, iova, size); +vduse_domain_free_iova (iovad, iova, size); -return NULL ; +return DMA_MAPPING_ERROR ; } void vduse_domain_free_coherent(struct vduse_iova_domain *domain, size_t size,
drivers/vdpa/vdpa_user/iova_domain.h +2 -3
@@ -67,9 +67,8 @@ void vduse_domain_unmap_page(struct vdus dma_addr_t dma_addr, size_t size, enum dma_data_direction dir, unsigned long attrs); -void *vduse_domain_alloc_coherent (struct vduse_iova_domain *domain, -size_t size,dma_addr_t *dma_addr, -gfp_t flag); +dma_addr_t vduse_domain_alloc_coherent (struct vduse_iova_domain *domain, +size_t size,void *orig); void vduse_domain_free_coherent(struct vduse_iova_domain *domain, size_t size, void *vaddr, dma_addr_t dma_addr,
drivers/vdpa/vdpa_user/vduse_dev.c +96 -13
219 lines not on this page · raw message
include/linux/virtio.h +3 -3
@@ -41,13 +41,13 @@ struct virtqueue {void *priv; }; -struct vduse_iova_domain ; +struct vduse_vq_group ;union virtio_map {/* Device that performs DMA */ struct device *dma_dev; -/* VDUSE specific mapping data */ -struct vduse_iova_domain *iova_domain; +/* VDUSE specific virtqueue group for doing map */ +struct vduse_vq_group *group; }; int virtqueue_add_outbuf(struct virtqueue *vq,
Greg Kroah-Hartman
maintainerPATCH 613/675 vduse: remove unused vaddr parameter of vduse_domain_free_coherent
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eugenio Pérez <[email protected]>
[ Upstream commit 766e1749c0ef6a09651be9b8a8283d508c322b58 ]
We will modify the function in next patches so let's clean it first.
Message-Id: <[email protected]>
Stable-dep-of: 9c1523803445 ("VDUSE: avoid leaking information to userspace")
--- drivers/vdpa/vdpa_user/iova_domain.c | 3 +-- drivers/vdpa/vdpa_user/iova_domain.h | 3 +-- drivers/vdpa/vdpa_user/vduse_dev.c | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-)
drivers/vdpa/vdpa_user/iova_domain.c +1 -2
@@ -521,8 +521,7 @@ err: }void vduse_domain_free_coherent (struct vduse_iova_domain *domain,size_t size, -void *vaddr,dma_addr_t dma_addr, -unsigned long attrs) +dma_addr_t dma_addr,unsigned long attrs) {struct iova_domain *iovad = &domain->consistent_iovad;struct vhost_iotlb_map *map;
drivers/vdpa/vdpa_user/iova_domain.h +1 -2
@@ -71,8 +71,7 @@ dma_addr_t vduse_domain_alloc_coherent(s size_t size, void *orig);void vduse_domain_free_coherent (struct vduse_iova_domain *domain,size_t size, -void *vaddr,dma_addr_t dma_addr, -unsigned long attrs); +dma_addr_t dma_addr,unsigned long attrs);void vduse_domain_reset_bounce_map (struct vduse_iova_domain *domain);
drivers/vdpa/vdpa_user/vduse_dev.c +1 -1
@@ -960,7 +960,7 @@ static void vduse_dev_free_coherent(unio vdev = token.group->dev; domain = vdev->domain; -vduse_domain_free_coherent (domain, size, vaddr, dma_addr, attrs); +vduse_domain_free_coherent (domain, size, dma_addr, attrs); }static bool vduse_dev_need_sync (union virtio_map token,dma_addr_t dma_addr)
Greg Kroah-Hartman
maintainerPATCH 614/675 vduse: take out allocations from vduse_dev_alloc_coherent
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eugenio Pérez <[email protected]>
[ Upstream commit 489d76520612abf9a4ede4344349105406c91a73 ]
The function vduse_dev_alloc_coherent will be called under rwlock in next patches. Make it out of the lock to avoid increasing its fail rate.
Message-Id: <[email protected]>
Stable-dep-of: 9c1523803445 ("VDUSE: avoid leaking information to userspace")
--- drivers/vdpa/vdpa_user/iova_domain.c | 3 --- drivers/vdpa/vdpa_user/vduse_dev.c | 1 + 2 files changed, 1 insertion(+), 3 deletions(-)
drivers/vdpa/vdpa_user/iova_domain.c +0 -3
@@ -526,7 +526,6 @@ void vduse_domain_free_coherent(struct vstruct iova_domain *iovad = &domain->consistent_iovad;struct vhost_iotlb_map *map;struct vdpa_map_file *map_file; -phys_addr_t pa;spin_lock (&domain->iotlb_lock); map = vhost_iotlb_itree_first(domain->iotlb, (u64)dma_addr,
@@ -538,12 +537,10 @@ void vduse_domain_free_coherent(struct v map_file = (struct vdpa_map_file *)map->opaque;fput (map_file->file);kfree (map_file); - pa = map->addr;vhost_iotlb_map_free (domain->iotlb, map);spin_unlock (&domain->iotlb_lock);vduse_domain_free_iova (iovad, dma_addr, size); -free_pages_exact (phys_to_virt (pa), size); }static vm_fault_t vduse_domain_mmap_fault (struct vm_fault *vmf)
drivers/vdpa/vdpa_user/vduse_dev.c +1 -0
@@ -961,6 +961,7 @@ static void vduse_dev_free_coherent(unio domain = vdev->domain;vduse_domain_free_coherent (domain, size, dma_addr, attrs); +free_pages_exact (vaddr, size); }static bool vduse_dev_need_sync (union virtio_map token,dma_addr_t dma_addr)
Greg Kroah-Hartman
maintainerPATCH 615/675 VDUSE: avoid leaking information to userspace
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jason Wang <[email protected]>
[ Upstream commit 9c1523803445ee0348f62b77793266dd981596e0 ]
The bounceing is not necessarily page aligned, so current VDUSE can leak kernel information through mapping bounce pages to userspace. Allocate bounce pages with __GFP_ZERO to avoid leaking information to userspace.
Message-ID: <[email protected]>
--- drivers/vdpa/vdpa_user/iova_domain.c | 2 +- drivers/vdpa/vdpa_user/vduse_dev.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
drivers/vdpa/vdpa_user/iova_domain.c +1 -1
@@ -124,7 +124,7 @@ static int vduse_domain_map_bounce_page(if (!map->bounce_page) { head_map = &domain->bounce_maps[(iova &PAGE_MASK ) >>BOUNCE_MAP_SHIFT ];if (!head_map->bounce_page) { - tmp_page =alloc_page (GFP_ATOMIC ); + tmp_page =alloc_page (GFP_ATOMIC | __GFP_ZERO);if (!tmp_page)return -ENOMEM ;if (cmpxchg (&head_map->bounce_page,NULL , tmp_page))
drivers/vdpa/vdpa_user/vduse_dev.c +1 -1
@@ -930,7 +930,7 @@ static void *vduse_dev_alloc_coherent(unif (!token.group)return NULL ; - addr =alloc_pages_exact (size, flag); + addr =alloc_pages_exact (size, flag | __GFP_ZERO);if (!addr)return NULL ;
Greg Kroah-Hartman
maintainerPATCH 616/675 arm64: dts: qcom: correct RBR opp entry
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Baryshkov <[email protected]>
[ Upstream commit a5c21b9bd5f531e50141b0484faabb707b92f1e2 ]
DisplayPort Reduced Bit Rate uses link rate of 1.62 Gbps, the main link clock should be 162 MHz. Having the incorrect frequency (160 MHz) in the OPP table will result in selecting wrong link frequency. Correct the entry in the OPP table.
Stable-dep-of: c17e22094667 ("arm64: dts: qcom: hamoa: Fix OPP tables for all DisplayPort controllers")
--- arch/arm64/boot/dts/qcom/lemans.dtsi | 8 ++++---- arch/arm64/boot/dts/qcom/sc7180.dtsi | 4 ++-- arch/arm64/boot/dts/qcom/sc7280.dtsi | 8 ++++---- arch/arm64/boot/dts/qcom/sc8180x.dtsi | 12 ++++++------ arch/arm64/boot/dts/qcom/sc8280xp.dtsi | 32 ++++++++++++++++---------------- arch/arm64/boot/dts/qcom/sm6350.dtsi | 4 ++-- arch/arm64/boot/dts/qcom/sm8150.dtsi | 4 ++-- arch/arm64/boot/dts/qcom/sm8250.dtsi | 4 ++-- arch/arm64/boot/dts/qcom/sm8350.dtsi | 4 ++-- arch/arm64/boot/dts/qcom/sm8450.dtsi | 4 ++-- arch/arm64/boot/dts/qcom/x1e80100.dtsi | 16 ++++++++-------- 11 files changed, 50 insertions(+), 50 deletions(-)
arch/arm64/boot/dts/qcom/lemans.dtsi +4 -4
@@ -5146,8 +5146,8 @@ dp_opp_table: opp-table { compatible = "operating-points-v2"; - opp-160000000 { - opp-hz = /bits/ 64 <160000000>; + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; required-opps = <&rpmhpd_opp_low_svs>; };
@@ -5234,8 +5234,8 @@ dp1_opp_table: opp-table { compatible = "operating-points-v2"; - opp-160000000 { - opp-hz = /bits/ 64 <160000000>; + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; required-opps = <&rpmhpd_opp_low_svs>; };
arch/arm64/boot/dts/qcom/sc7180.dtsi +2 -2
@@ -3452,8 +3452,8 @@ dp_opp_table: opp-table { compatible = "operating-points-v2"; - opp-160000000 { - opp-hz = /bits/ 64 <160000000>; + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; required-opps = <&rpmhpd_opp_low_svs>; };
arch/arm64/boot/dts/qcom/sc7280.dtsi +4 -4
@@ -5196,8 +5196,8 @@ edp_opp_table: opp-table { compatible = "operating-points-v2"; - opp-160000000 { - opp-hz = /bits/ 64 <160000000>; + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; required-opps = <&rpmhpd_opp_low_svs>; };
@@ -5295,8 +5295,8 @@ dp_opp_table: opp-table { compatible = "operating-points-v2"; - opp-160000000 { - opp-hz = /bits/ 64 <160000000>; + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; required-opps = <&rpmhpd_opp_low_svs>; };
arch/arm64/boot/dts/qcom/sc8180x.dtsi +6 -6
@@ -3303,8 +3303,8 @@ dp0_opp_table: opp-table { compatible = "operating-points-v2"; - opp-160000000 { - opp-hz = /bits/ 64 <160000000>; + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; required-opps = <&rpmhpd_opp_low_svs>; };
@@ -3385,8 +3385,8 @@ dp1_opp_table: opp-table { compatible = "operating-points-v2"; - opp-160000000 { - opp-hz = /bits/ 64 <160000000>; + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; required-opps = <&rpmhpd_opp_low_svs>; };
@@ -3461,8 +3461,8 @@ edp_opp_table: opp-table { compatible = "operating-points-v2"; - opp-160000000 { - opp-hz = /bits/ 64 <160000000>; + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; required-opps = <&rpmhpd_opp_low_svs>; };
arch/arm64/boot/dts/qcom/sc8280xp.dtsi +16 -16
@@ -4754,8 +4754,8 @@ mdss0_dp0_opp_table: opp-table { compatible = "operating-points-v2"; - opp-160000000 { - opp-hz = /bits/ 64 <160000000>; + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; required-opps = <&rpmhpd_opp_low_svs>; };
@@ -4836,8 +4836,8 @@ mdss0_dp1_opp_table: opp-table { compatible = "operating-points-v2"; - opp-160000000 { - opp-hz = /bits/ 64 <160000000>; + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; required-opps = <&rpmhpd_opp_low_svs>; };
@@ -4916,8 +4916,8 @@ mdss0_dp2_opp_table: opp-table { compatible = "operating-points-v2"; - opp-160000000 { - opp-hz = /bits/ 64 <160000000>; + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; required-opps = <&rpmhpd_opp_low_svs>; };
@@ -4991,8 +4991,8 @@ mdss0_dp3_opp_table: opp-table { compatible = "operating-points-v2"; - opp-160000000 { - opp-hz = /bits/ 64 <160000000>; + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; required-opps = <&rpmhpd_opp_low_svs>; };
@@ -6110,8 +6110,8 @@ mdss1_dp0_opp_table: opp-table { compatible = "operating-points-v2"; - opp-160000000 { - opp-hz = /bits/ 64 <160000000>; + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; required-opps = <&rpmhpd_opp_low_svs>; };
@@ -6190,8 +6190,8 @@ mdss1_dp1_opp_table: opp-table { compatible = "operating-points-v2"; - opp-160000000 { - opp-hz = /bits/ 64 <160000000>; + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; required-opps = <&rpmhpd_opp_low_svs>; };
@@ -6270,8 +6270,8 @@ mdss1_dp2_opp_table: opp-table { compatible = "operating-points-v2"; - opp-160000000 { - opp-hz = /bits/ 64 <160000000>; + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; required-opps = <&rpmhpd_opp_low_svs>; };
@@ -6345,8 +6345,8 @@ mdss1_dp3_opp_table: opp-table { compatible = "operating-points-v2"; - opp-160000000 { - opp-hz = /bits/ 64 <160000000>; + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; required-opps = <&rpmhpd_opp_low_svs>; };
arch/arm64/boot/dts/qcom/sm6350.dtsi +2 -2
@@ -2306,8 +2306,8 @@ dp_opp_table: opp-table { compatible = "operating-points-v2"; - opp-160000000 { - opp-hz = /bits/ 64 <160000000>; + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; required-opps = <&rpmhpd_opp_low_svs>; };
arch/arm64/boot/dts/qcom/sm8150.dtsi +2 -2
@@ -3939,8 +3939,8 @@ dp_opp_table: opp-table { compatible = "operating-points-v2"; - opp-160000000 { - opp-hz = /bits/ 64 <160000000>; + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; required-opps = <&rpmhpd_opp_low_svs>; };
arch/arm64/boot/dts/qcom/sm8250.dtsi +2 -2
@@ -4824,8 +4824,8 @@ dp_opp_table: opp-table { compatible = "operating-points-v2"; - opp-160000000 { - opp-hz = /bits/ 64 <160000000>; + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; required-opps = <&rpmhpd_opp_low_svs>; };
arch/arm64/boot/dts/qcom/sm8350.dtsi +2 -2
@@ -2925,8 +2925,8 @@ dp_opp_table: opp-table { compatible = "operating-points-v2"; - opp-160000000 { - opp-hz = /bits/ 64 <160000000>; + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; required-opps = <&rpmhpd_opp_low_svs>; };
arch/arm64/boot/dts/qcom/sm8450.dtsi +2 -2
@@ -3483,8 +3483,8 @@ dp_opp_table: opp-table { compatible = "operating-points-v2"; - opp-160000000 { - opp-hz = /bits/ 64 <160000000>; + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; required-opps = <&rpmhpd_opp_low_svs>; };
arch/arm64/boot/dts/qcom/x1e80100.dtsi +8 -8
@@ -5522,8 +5522,8 @@ mdss_dp0_opp_table: opp-table { compatible = "operating-points-v2"; - opp-160000000 { - opp-hz = /bits/ 64 <160000000>; + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; required-opps = <&rpmhpd_opp_low_svs>; };
@@ -5610,8 +5610,8 @@ mdss_dp1_opp_table: opp-table { compatible = "operating-points-v2"; - opp-160000000 { - opp-hz = /bits/ 64 <160000000>; + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; required-opps = <&rpmhpd_opp_low_svs>; };
@@ -5697,8 +5697,8 @@ mdss_dp2_opp_table: opp-table { compatible = "operating-points-v2"; - opp-160000000 { - opp-hz = /bits/ 64 <160000000>; + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; required-opps = <&rpmhpd_opp_low_svs>; };
@@ -5779,8 +5779,8 @@ mdss_dp3_opp_table: opp-table { compatible = "operating-points-v2"; - opp-160000000 { - opp-hz = /bits/ 64 <160000000>; + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; required-opps = <&rpmhpd_opp_low_svs>; };
Greg Kroah-Hartman
maintainerPATCH 617/675 arm64: dts: qcom: hamoa: Fix OPP tables for all DisplayPort controllers
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abel Vesa <[email protected]>
[ Upstream commit c17e220946675232d383620ed9cff6685735ec48 ]
According to internal documentation, the corners specific for each rate from the DP link clock are:
- LOWSVS_D1 -> 19.2 MHz
- LOWSVS -> 270 MHz - SVS -> 540 MHz (594 MHz in case of DP3) - SVS_L1 -> 594 MHz - NOM -> 810 MHz - NOM_L1 -> 810 MHz - TURBO -> 810 MHz
So fix all tables for each of the four controllers according to the documentation, but since DP0 through DP2 have the same entries in their tables, lets drop the DP1 and DP2 and have all of them share the DP0 table instead. However keep a separate table for the DP3 as it is different for the SVS, compared to the rest of the controllers.
The 19.2 MHz @ LOWSVS_D1 isn't needed as it's not an actual working frequency and the controller will never select it. So remove it.
--- arch/arm64/boot/dts/qcom/x1e80100.dtsi | 77 +++++---------------------------- 1 file changed, 12 insertions(+), 65 deletions(-)
arch/arm64/boot/dts/qcom/x1e80100.dtsi +12 -65
@@ -5522,18 +5522,18 @@ mdss_dp0_opp_table: opp-table { compatible = "operating-points-v2"; - opp-162000000 { - opp-hz = /bits/ 64 <162000000>; - required-opps = <&rpmhpd_opp_low_svs>; - }; - opp-270000000 { opp-hz = /bits/ 64 <270000000>; - required-opps = <&rpmhpd_opp_svs>; + required-opps = <&rpmhpd_opp_low_svs>; }; opp-540000000 { opp-hz = /bits/ 64 <540000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-594000000 { + opp-hz = /bits/ 64 <594000000>; required-opps = <&rpmhpd_opp_svs_l1>; };
@@ -5574,7 +5574,7 @@ <&usb_1_ss1_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>, <&usb_1_ss1_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>; - operating-points-v2 = <&mdss_dp1_opp_table>; + operating-points-v2 = <&mdss_dp0_opp_table>; power-domains = <&rpmhpd RPMHPD_MMCX>;
@@ -5606,30 +5606,6 @@ }; }; }; - - mdss_dp1_opp_table: opp-table { - compatible = "operating-points-v2"; - - opp-162000000 { - opp-hz = /bits/ 64 <162000000>; - required-opps = <&rpmhpd_opp_low_svs>; - }; - - opp-270000000 { - opp-hz = /bits/ 64 <270000000>; - required-opps = <&rpmhpd_opp_svs>; - }; - - opp-540000000 { - opp-hz = /bits/ 64 <540000000>; - required-opps = <&rpmhpd_opp_svs_l1>; - }; - - opp-810000000 { - opp-hz = /bits/ 64 <810000000>; - required-opps = <&rpmhpd_opp_nom>; - }; - }; }; mdss_dp2: displayport-controller@ae9a000 {
@@ -5662,7 +5638,7 @@ <&usb_1_ss2_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>, <&usb_1_ss2_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>; - operating-points-v2 = <&mdss_dp2_opp_table>; + operating-points-v2 = <&mdss_dp0_opp_table>; power-domains = <&rpmhpd RPMHPD_MMCX>;
@@ -5693,30 +5669,6 @@ }; }; }; - - mdss_dp2_opp_table: opp-table { - compatible = "operating-points-v2"; - - opp-162000000 { - opp-hz = /bits/ 64 <162000000>; - required-opps = <&rpmhpd_opp_low_svs>; - }; - - opp-270000000 { - opp-hz = /bits/ 64 <270000000>; - required-opps = <&rpmhpd_opp_svs>; - }; - - opp-540000000 { - opp-hz = /bits/ 64 <540000000>; - required-opps = <&rpmhpd_opp_svs_l1>; - }; - - opp-810000000 { - opp-hz = /bits/ 64 <810000000>; - required-opps = <&rpmhpd_opp_nom>; - }; - }; }; mdss_dp3: displayport-controller@aea0000 {
@@ -5779,19 +5731,14 @@ mdss_dp3_opp_table: opp-table { compatible = "operating-points-v2"; - opp-162000000 { - opp-hz = /bits/ 64 <162000000>; - required-opps = <&rpmhpd_opp_low_svs>; - }; - opp-270000000 { opp-hz = /bits/ 64 <270000000>; - required-opps = <&rpmhpd_opp_svs>; + required-opps = <&rpmhpd_opp_low_svs>; }; - opp-540000000 { - opp-hz = /bits/ 64 <540000000>; - required-opps = <&rpmhpd_opp_svs_l1>; + opp-594000000 { + opp-hz = /bits/ 64 <594000000>; + required-opps = <&rpmhpd_opp_svs>; }; opp-810000000 {
Greg Kroah-Hartman
maintainerPATCH 618/675 netfilter: nf_tables: remove register tracking infrastructure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit 6b94d081f81dd524626f7aab2b98a9de335edb72 ]
This facility was disabled in commit9e539c5b6d9c ("netfilter: nf_tables: disable expression reduction infra"), because not all nft_exprs guarantee they will update the destination
register: some may set NFT_BREAK instead to cancel evaluation of the rule.
This has been dead code ever since.
There are no plans to salvage this at this time, so remove this.
Stable-dep-of: d07955dd34ec ("netfilter: nft_fib: reject fib expression on the netdev egress hook")
--- include/net/netfilter/nf_tables.h | 32 --------- include/net/netfilter/nft_fib.h | 2 include/net/netfilter/nft_meta.h | 3 net/bridge/netfilter/nft_meta_bridge.c | 20 ----- net/bridge/netfilter/nft_reject_bridge.c | 1 net/ipv4/netfilter/nft_dup_ipv4.c | 1 net/ipv4/netfilter/nft_fib_ipv4.c | 2 net/ipv4/netfilter/nft_reject_ipv4.c | 1 net/ipv6/netfilter/nft_dup_ipv6.c | 1 net/ipv6/netfilter/nft_fib_ipv6.c | 2 net/ipv6/netfilter/nft_reject_ipv6.c | 1 net/netfilter/nf_tables_api.c | 67 ------------------- net/netfilter/nft_bitwise.c | 104 ------------------------------- net/netfilter/nft_byteorder.c | 11 --- net/netfilter/nft_cmp.c | 3 net/netfilter/nft_compat.c | 10 -- net/netfilter/nft_connlimit.c | 1 net/netfilter/nft_counter.c | 1 net/netfilter/nft_ct.c | 46 ------------- net/netfilter/nft_dup_netdev.c | 1 net/netfilter/nft_dynset.c | 1 net/netfilter/nft_exthdr.c | 34 ---------- net/netfilter/nft_fib.c | 42 ------------ net/netfilter/nft_fib_inet.c | 1 net/netfilter/nft_fib_netdev.c | 1 net/netfilter/nft_flow_offload.c | 1 net/netfilter/nft_fwd_netdev.c | 2 net/netfilter/nft_hash.c | 36 ---------- net/netfilter/nft_immediate.c | 12 --- net/netfilter/nft_last.c | 1 net/netfilter/nft_limit.c | 2 net/netfilter/nft_log.c | 1 net/netfilter/nft_lookup.c | 12 --- net/netfilter/nft_masq.c | 3 net/netfilter/nft_meta.c | 45 ------------- net/netfilter/nft_nat.c | 2 net/netfilter/nft_numgen.c | 22 ------ net/netfilter/nft_objref.c | 2 net/netfilter/nft_osf.c | 25 ------- net/netfilter/nft_payload.c | 47 -------------- net/netfilter/nft_queue.c | 2 net/netfilter/nft_quota.c | 1 net/netfilter/nft_range.c | 1 net/netfilter/nft_redir.c | 3 net/netfilter/nft_reject_inet.c | 1 net/netfilter/nft_reject_netdev.c | 1 net/netfilter/nft_rt.c | 1 net/netfilter/nft_socket.c | 26 ------- net/netfilter/nft_synproxy.c | 1 net/netfilter/nft_tproxy.c | 1 net/netfilter/nft_tunnel.c | 26 ------- net/netfilter/nft_xfrm.c | 27 -------- 52 files changed, 693 deletions(-)
include/net/netfilter/nf_tables.h +0 -32
@@ -123,17 +123,6 @@ struct nft_regs { }; }; -struct nft_regs_track { -struct { -const struct nft_expr *selector; -const struct nft_expr *bitwise; -u8 num_reg; - } regs[NFT_REG32_NUM ]; - -const struct nft_expr *cur; -const struct nft_expr *last; -}; -/* Store/load an u8, u16 or u64 integer to/from the u32 data register. * * Note, when using concatenations, register allocation happens at 32-bit
@@ -433,8 +422,6 @@ int nft_expr_clone(struct nft_expr *dst,void nft_expr_destroy (const struct nft_ctx *ctx,struct nft_expr *expr);int nft_expr_dump (struct sk_buff *skb,unsigned int attr,const struct nft_expr *expr,bool reset); -bool nft_expr_reduce_bitwise (struct nft_regs_track *track, -const struct nft_expr *expr);struct nft_set_ext ;
@@ -949,7 +936,6 @@ struct nft_offload_ctx;* @destroy_clone: destruction clone function * @dump: function to dump parameters * @validate: validate expression, called during loop detection -* @reduce: reduce expression * @gc: garbage collection expression * @offload: hardware offload expression * @offload_action: function to report true/false to allocate one slot or not in the flow
@@ -983,8 +969,6 @@ struct nft_expr_ops { bool reset);int (*validate)(const struct nft_ctx *ctx,const struct nft_expr *expr); -bool (*reduce)(struct nft_regs_track *track, -const struct nft_expr *expr);bool (*gc)(struct net *net,const struct nft_expr *expr); int (*offload)(struct nft_offload_ctx *ctx,
@@ -1967,20 +1951,4 @@ static inline u64 nft_net_tstamp(const s return nft_pernet(net)->tstamp; } -#define __NFT_REDUCE_READONLY 1UL -#define NFT_REDUCE_READONLY (void *)__NFT_REDUCE_READONLY - -void nft_reg_track_update (struct nft_regs_track *track, -const struct nft_expr *expr,u8 dreg,u8 len); -void nft_reg_track_cancel (struct nft_regs_track *track,u8 dreg,u8 len); -void __nft_reg_track_cancel (struct nft_regs_track *track,u8 dreg); - -static inline bool nft_reg_track_cmp (struct nft_regs_track *track, -const struct nft_expr *expr,u8 dreg) -{ -return track->regs[dreg].selector && - track->regs[dreg].selector->ops == expr->ops && - track->regs[dreg].num_reg ==0 ; -} -#endif /* _NET_NF_TABLES_H */
include/net/netfilter/nft_fib.h +0 -2
@@ -66,6 +66,4 @@ void nft_fib6_eval(const struct nft_exprvoid nft_fib_store_result (void *reg,const struct nft_fib *priv,const struct net_device *dev); -bool nft_fib_reduce (struct nft_regs_track *track, -const struct nft_expr *expr);#endif
include/net/netfilter/nft_meta.h +0 -3
@@ -45,9 +45,6 @@ int nft_meta_get_validate(const struct nint nft_meta_set_validate (const struct nft_ctx *ctx,const struct nft_expr *expr); -bool nft_meta_get_reduce (struct nft_regs_track *track, -const struct nft_expr *expr); -struct nft_inner_tun_ctx ; void nft_meta_inner_eval(const struct nft_expr *expr, struct nft_regs *regs, const struct nft_pktinfo *pkt,
net/bridge/netfilter/nft_meta_bridge.c +0 -20
@@ -134,7 +134,6 @@ static const struct nft_expr_ops nft_met .init = nft_meta_bridge_get_init, .validate = nft_meta_bridge_get_validate, .dump = nft_meta_get_dump, - .reduce = nft_meta_get_reduce, }; static void nft_meta_bridge_set_eval(const struct nft_expr *expr,
@@ -181,24 +180,6 @@ static int nft_meta_bridge_set_init(consreturn 0 ; } -static bool nft_meta_bridge_set_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -int i; - -for (i =0 ; i <NFT_REG32_NUM ; i++) { -if (!track->regs[i].selector) -continue ; - -if (track->regs[i].selector->ops != &nft_meta_bridge_get_ops) -continue ; - -__nft_reg_track_cancel (track, i); - } - -return false; -} -static int nft_meta_bridge_set_validate (const struct nft_ctx *ctx,const struct nft_expr *expr) {
@@ -223,7 +204,6 @@ static const struct nft_expr_ops nft_met .init = nft_meta_bridge_set_init, .destroy = nft_meta_set_destroy, .dump = nft_meta_set_dump, - .reduce = nft_meta_bridge_set_reduce, .validate = nft_meta_bridge_set_validate, };
net/bridge/netfilter/nft_reject_bridge.c +0 -1
@@ -184,7 +184,6 @@ static const struct nft_expr_ops nft_rej .init = nft_reject_init, .dump = nft_reject_dump, .validate = nft_reject_bridge_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_reject_bridge_type__read_mostly = {
net/ipv4/netfilter/nft_dup_ipv4.c +0 -1
@@ -76,7 +76,6 @@ static const struct nft_expr_ops nft_dup .eval = nft_dup_ipv4_eval, .init = nft_dup_ipv4_init, .dump = nft_dup_ipv4_dump, - .reduce = NFT_REDUCE_READONLY, };static const struct nla_policy nft_dup_ipv4_policy[NFTA_DUP_MAX +1 ] = {
net/ipv4/netfilter/nft_fib_ipv4.c +0 -2
@@ -163,7 +163,6 @@ static const struct nft_expr_ops nft_fib .init = nft_fib_init, .dump = nft_fib_dump, .validate = nft_fib_validate, - .reduce = nft_fib_reduce, };static const struct nft_expr_ops nft_fib4_ops = {
@@ -173,7 +172,6 @@ static const struct nft_expr_ops nft_fib .init = nft_fib_init, .dump = nft_fib_dump, .validate = nft_fib_validate, - .reduce = nft_fib_reduce, }; static const struct nft_expr_ops *
net/ipv4/netfilter/nft_reject_ipv4.c +0 -1
@@ -45,7 +45,6 @@ static const struct nft_expr_ops nft_rej .init = nft_reject_init, .dump = nft_reject_dump, .validate = nft_reject_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_reject_ipv4_type__read_mostly = {
net/ipv6/netfilter/nft_dup_ipv6.c +0 -1
@@ -74,7 +74,6 @@ static const struct nft_expr_ops nft_dup .eval = nft_dup_ipv6_eval, .init = nft_dup_ipv6_init, .dump = nft_dup_ipv6_dump, - .reduce = NFT_REDUCE_READONLY, };static const struct nla_policy nft_dup_ipv6_policy[NFTA_DUP_MAX +1 ] = {
net/ipv6/netfilter/nft_fib_ipv6.c +0 -2
@@ -225,7 +225,6 @@ static const struct nft_expr_ops nft_fib .init = nft_fib_init, .dump = nft_fib_dump, .validate = nft_fib_validate, - .reduce = nft_fib_reduce, };static const struct nft_expr_ops nft_fib6_ops = {
@@ -235,7 +234,6 @@ static const struct nft_expr_ops nft_fib .init = nft_fib_init, .dump = nft_fib_dump, .validate = nft_fib_validate, - .reduce = nft_fib_reduce, }; static const struct nft_expr_ops *
net/ipv6/netfilter/nft_reject_ipv6.c +0 -1
@@ -46,7 +46,6 @@ static const struct nft_expr_ops nft_rej .init = nft_reject_init, .dump = nft_reject_dump, .validate = nft_reject_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_reject_ipv6_type__read_mostly = {
net/netfilter/nf_tables_api.c +0 -67
89 lines not on this page · raw message
net/netfilter/nft_bitwise.c +0 -104
131 lines not on this page · raw message
net/netfilter/nft_byteorder.c +0 -11
@@ -177,23 +177,12 @@ nla_put_failure:return -1 ; } -static bool nft_byteorder_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -struct nft_byteorder *priv =nft_expr_priv (expr); - -nft_reg_track_cancel (track, priv->dreg, priv->len); - -return false; -} -static const struct nft_expr_ops nft_byteorder_ops = { .type = &nft_byteorder_type, .size =NFT_EXPR_SIZE (sizeof (struct nft_byteorder )), .eval = nft_byteorder_eval, .init = nft_byteorder_init, .dump = nft_byteorder_dump, - .reduce = nft_byteorder_reduce, };struct nft_expr_type nft_byteorder_type__read_mostly = {
net/netfilter/nft_cmp.c +0 -3
@@ -190,7 +190,6 @@ static const struct nft_expr_ops nft_cmp .eval = nft_cmp_eval, .init = nft_cmp_init, .dump = nft_cmp_dump, - .reduce = NFT_REDUCE_READONLY, .offload = nft_cmp_offload, };
@@ -282,7 +281,6 @@ const struct nft_expr_ops nft_cmp_fast_o .eval = NULL, /* inlined */ .init = nft_cmp_fast_init, .dump = nft_cmp_fast_dump, - .reduce = NFT_REDUCE_READONLY, .offload = nft_cmp_fast_offload, };
@@ -376,7 +374,6 @@ const struct nft_expr_ops nft_cmp16_fast .eval = NULL, /* inlined */ .init = nft_cmp16_fast_init, .dump = nft_cmp16_fast_dump, - .reduce = NFT_REDUCE_READONLY, .offload = nft_cmp16_fast_offload, };
net/netfilter/nft_compat.c +0 -10
@@ -794,14 +794,6 @@ static const struct nfnetlink_subsystemstatic struct nft_expr_type nft_match_type; -static bool nft_match_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -const struct xt_match *match = expr->ops->data; - -return strcmp (match->name,"comment" ) ==0 ; -} -static const struct nft_expr_ops *nft_match_select_ops (const struct nft_ctx *ctx,const struct nlattr *const tb[])
@@ -844,7 +836,6 @@ nft_match_select_ops(const struct nft_ct ops->dump = nft_match_dump; ops->validate = nft_match_validate; ops->data = match; - ops->reduce = nft_match_reduce; matchsize =NFT_EXPR_SIZE (XT_ALIGN (match->matchsize));if (matchsize >NFT_MATCH_LARGE_THRESH ) {
@@ -933,7 +924,6 @@ nft_target_select_ops(const struct nft_c ops->destroy = nft_target_destroy; ops->dump = nft_target_dump; ops->data = target; - ops->reduce =NFT_REDUCE_READONLY ;if (family ==NFPROTO_BRIDGE ) { ops->eval = nft_target_eval_bridge;
net/netfilter/nft_connlimit.c +0 -1
@@ -247,7 +247,6 @@ static const struct nft_expr_ops nft_con .destroy_clone = nft_connlimit_destroy_clone, .dump = nft_connlimit_dump, .gc = nft_connlimit_gc, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_connlimit_type__read_mostly = {
net/netfilter/nft_counter.c +0 -1
@@ -313,7 +313,6 @@ static const struct nft_expr_ops nft_cou .destroy_clone = nft_counter_destroy, .dump = nft_counter_dump, .clone = nft_counter_clone, - .reduce = NFT_REDUCE_READONLY, .offload = nft_counter_offload, .offload_stats = nft_counter_offload_stats, };
net/netfilter/nft_ct.c +0 -46
84 lines not on this page · raw message
net/netfilter/nft_dup_netdev.c +0 -1
@@ -80,7 +80,6 @@ static const struct nft_expr_ops nft_dup .eval = nft_dup_netdev_eval, .init = nft_dup_netdev_init, .dump = nft_dup_netdev_dump, - .reduce = NFT_REDUCE_READONLY, .offload = nft_dup_netdev_offload, .offload_action = nft_dup_netdev_offload_action, };
net/netfilter/nft_dynset.c +0 -1
@@ -429,7 +429,6 @@ static const struct nft_expr_ops nft_dyn .activate = nft_dynset_activate, .deactivate = nft_dynset_deactivate, .dump = nft_dynset_dump, - .reduce = NFT_REDUCE_READONLY, };struct nft_expr_type nft_dynset_type__read_mostly = {
net/netfilter/nft_exthdr.c +0 -34
@@ -705,40 +705,12 @@ static int nft_exthdr_dump_strip(structreturn nft_exthdr_dump_common (skb, priv); } -static bool nft_exthdr_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -const struct nft_exthdr *priv =nft_expr_priv (expr); -const struct nft_exthdr *exthdr; - -if (!nft_reg_track_cmp (track, expr, priv->dreg)) { -nft_reg_track_update (track, expr, priv->dreg, priv->len); -return false; - } - - exthdr =nft_expr_priv (track->regs[priv->dreg].selector); -if (priv->type != exthdr->type || - priv->op != exthdr->op || - priv->flags != exthdr->flags || - priv->offset != exthdr->offset || - priv->len != exthdr->len) { -nft_reg_track_update (track, expr, priv->dreg, priv->len); -return false; - } - -if (!track->regs[priv->dreg].bitwise) -return true; - -return nft_expr_reduce_bitwise (track, expr); -} -static const struct nft_expr_ops nft_exthdr_ipv6_ops = { .type = &nft_exthdr_type, .size =NFT_EXPR_SIZE (sizeof (struct nft_exthdr )), .eval = nft_exthdr_ipv6_eval, .init = nft_exthdr_init, .dump = nft_exthdr_dump, - .reduce = nft_exthdr_reduce, };static const struct nft_expr_ops nft_exthdr_ipv4_ops = {
@@ -747,7 +719,6 @@ static const struct nft_expr_ops nft_ext .eval = nft_exthdr_ipv4_eval, .init = nft_exthdr_ipv4_init, .dump = nft_exthdr_dump, - .reduce = nft_exthdr_reduce, };static const struct nft_expr_ops nft_exthdr_tcp_ops = {
@@ -756,7 +727,6 @@ static const struct nft_expr_ops nft_ext .eval = nft_exthdr_tcp_eval, .init = nft_exthdr_init, .dump = nft_exthdr_dump, - .reduce = nft_exthdr_reduce, };static const struct nft_expr_ops nft_exthdr_tcp_set_ops = {
@@ -765,7 +735,6 @@ static const struct nft_expr_ops nft_ext .eval = nft_exthdr_tcp_set_eval, .init = nft_exthdr_tcp_set_init, .dump = nft_exthdr_dump_set, - .reduce = NFT_REDUCE_READONLY, };static const struct nft_expr_ops nft_exthdr_tcp_strip_ops = {
@@ -774,7 +743,6 @@ static const struct nft_expr_ops nft_ext .eval = nft_exthdr_tcp_strip_eval, .init = nft_exthdr_tcp_strip_init, .dump = nft_exthdr_dump_strip, - .reduce = NFT_REDUCE_READONLY, };static const struct nft_expr_ops nft_exthdr_sctp_ops = {
@@ -783,7 +751,6 @@ static const struct nft_expr_ops nft_ext .eval = nft_exthdr_sctp_eval, .init = nft_exthdr_init, .dump = nft_exthdr_dump, - .reduce = nft_exthdr_reduce, };#ifdef CONFIG_NFT_EXTHDR_DCCP
@@ -793,7 +760,6 @@ static const struct nft_expr_ops nft_ext .eval = nft_exthdr_dccp_eval, .init = nft_exthdr_dccp_init, .dump = nft_exthdr_dump, - .reduce = nft_exthdr_reduce, };#endif
net/netfilter/nft_fib.c +0 -42
48 lines not on this page · raw message
net/netfilter/nft_fib_inet.c +0 -1
@@ -49,7 +49,6 @@ static const struct nft_expr_ops nft_fib .init = nft_fib_init, .dump = nft_fib_dump, .validate = nft_fib_validate, - .reduce = nft_fib_reduce, };static struct nft_expr_type nft_fib_inet_type__read_mostly = {
net/netfilter/nft_fib_netdev.c +0 -1
@@ -58,7 +58,6 @@ static const struct nft_expr_ops nft_fib .init = nft_fib_init, .dump = nft_fib_dump, .validate = nft_fib_validate, - .reduce = nft_fib_reduce, };static struct nft_expr_type nft_fib_netdev_type__read_mostly = {
net/netfilter/nft_flow_offload.c +0 -1
@@ -224,7 +224,6 @@ static const struct nft_expr_ops nft_flo .destroy = nft_flow_offload_destroy, .validate = nft_flow_offload_validate, .dump = nft_flow_offload_dump, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_flow_offload_type__read_mostly = {
net/netfilter/nft_fwd_netdev.c +0 -2
@@ -228,7 +228,6 @@ static const struct nft_expr_ops nft_fwd .init = nft_fwd_neigh_init, .dump = nft_fwd_neigh_dump, .validate = nft_fwd_validate, - .reduce = NFT_REDUCE_READONLY, };static const struct nft_expr_ops nft_fwd_netdev_ops = {
@@ -238,7 +237,6 @@ static const struct nft_expr_ops nft_fwd .init = nft_fwd_netdev_init, .dump = nft_fwd_netdev_dump, .validate = nft_fwd_validate, - .reduce = NFT_REDUCE_READONLY, .offload = nft_fwd_netdev_offload, .offload_action = nft_fwd_netdev_offload_action, };
net/netfilter/nft_hash.c +0 -36
@@ -166,16 +166,6 @@ nla_put_failure:return -1 ; } -static bool nft_jhash_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -const struct nft_jhash *priv =nft_expr_priv (expr); - -nft_reg_track_cancel (track, priv->dreg,sizeof (u32)); - -return false; -} -static int nft_symhash_dump (struct sk_buff *skb,const struct nft_expr *expr,bool reset) {
@@ -196,30 +186,6 @@ nla_put_failure:return -1 ; } -static bool nft_symhash_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -struct nft_symhash *priv =nft_expr_priv (expr); -struct nft_symhash *symhash; - -if (!nft_reg_track_cmp (track, expr, priv->dreg)) { -nft_reg_track_update (track, expr, priv->dreg,sizeof (u32)); -return false; - } - - symhash =nft_expr_priv (track->regs[priv->dreg].selector); -if (priv->offset != symhash->offset || - priv->modulus != symhash->modulus) { -nft_reg_track_update (track, expr, priv->dreg,sizeof (u32)); -return false; - } - -if (!track->regs[priv->dreg].bitwise) -return true; - -return false; -} -static struct nft_expr_type nft_hash_type;static const struct nft_expr_ops nft_jhash_ops = { .type = &nft_hash_type,
@@ -227,7 +193,6 @@ static const struct nft_expr_ops nft_jha .eval = nft_jhash_eval, .init = nft_jhash_init, .dump = nft_jhash_dump, - .reduce = nft_jhash_reduce, };static const struct nft_expr_ops nft_symhash_ops = {
@@ -236,7 +201,6 @@ static const struct nft_expr_ops nft_sym .eval = nft_symhash_eval, .init = nft_symhash_init, .dump = nft_symhash_dump, - .reduce = nft_symhash_reduce, }; static const struct nft_expr_ops *
net/netfilter/nft_immediate.c +0 -12
@@ -320,17 +320,6 @@ static bool nft_immediate_offload_actionreturn false; } -static bool nft_immediate_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -const struct nft_immediate_expr *priv =nft_expr_priv (expr); - -if (priv->dreg !=NFT_REG_VERDICT ) -nft_reg_track_cancel (track, priv->dreg, priv->dlen); - -return false; -} -static const struct nft_expr_ops nft_imm_ops = { .type = &nft_imm_type, .size =NFT_EXPR_SIZE (sizeof (struct nft_immediate_expr )),
@@ -341,7 +330,6 @@ static const struct nft_expr_ops nft_imm .destroy = nft_immediate_destroy, .dump = nft_immediate_dump, .validate = nft_immediate_validate, - .reduce = nft_immediate_reduce, .offload = nft_immediate_offload, .offload_action = nft_immediate_offload_action, };
net/netfilter/nft_last.c +0 -1
@@ -125,7 +125,6 @@ static const struct nft_expr_ops nft_las .destroy = nft_last_destroy, .clone = nft_last_clone, .dump = nft_last_dump, - .reduce = NFT_REDUCE_READONLY, };struct nft_expr_type nft_last_type__read_mostly = {
net/netfilter/nft_limit.c +0 -2
@@ -243,7 +243,6 @@ static const struct nft_expr_ops nft_lim .destroy = nft_limit_pkts_destroy, .clone = nft_limit_pkts_clone, .dump = nft_limit_pkts_dump, - .reduce = NFT_REDUCE_READONLY, }; static void nft_limit_bytes_eval(const struct nft_expr *expr,
@@ -299,7 +298,6 @@ static const struct nft_expr_ops nft_lim .dump = nft_limit_bytes_dump, .clone = nft_limit_bytes_clone, .destroy = nft_limit_bytes_destroy, - .reduce = NFT_REDUCE_READONLY, }; static const struct nft_expr_ops *
net/netfilter/nft_log.c +0 -1
@@ -291,7 +291,6 @@ static const struct nft_expr_ops nft_log .init = nft_log_init, .destroy = nft_log_destroy, .dump = nft_log_dump, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_log_type__read_mostly = {
net/netfilter/nft_lookup.c +0 -12
@@ -269,17 +269,6 @@ static int nft_lookup_validate(const strreturn 0 ; } -static bool nft_lookup_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -const struct nft_lookup *priv =nft_expr_priv (expr); - -if (priv->set->flags &NFT_SET_MAP ) -nft_reg_track_cancel (track, priv->dreg, priv->set->dlen); - -return false; -} -static const struct nft_expr_ops nft_lookup_ops = { .type = &nft_lookup_type, .size =NFT_EXPR_SIZE (sizeof (struct nft_lookup )),
@@ -290,7 +279,6 @@ static const struct nft_expr_ops nft_loo .destroy = nft_lookup_destroy, .dump = nft_lookup_dump, .validate = nft_lookup_validate, - .reduce = nft_lookup_reduce, };struct nft_expr_type nft_lookup_type__read_mostly = {
net/netfilter/nft_masq.c +0 -3
@@ -143,7 +143,6 @@ static const struct nft_expr_ops nft_mas .destroy = nft_masq_ipv4_destroy, .dump = nft_masq_dump, .validate = nft_masq_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_masq_ipv4_type__read_mostly = {
@@ -171,7 +170,6 @@ static const struct nft_expr_ops nft_mas .destroy = nft_masq_ipv6_destroy, .dump = nft_masq_dump, .validate = nft_masq_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_masq_ipv6_type__read_mostly = {
@@ -213,7 +211,6 @@ static const struct nft_expr_ops nft_mas .destroy = nft_masq_inet_destroy, .dump = nft_masq_dump, .validate = nft_masq_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_masq_inet_type__read_mostly = {
net/netfilter/nft_meta.c +0 -45
67 lines not on this page · raw message
net/netfilter/nft_nat.c +0 -2
@@ -320,7 +320,6 @@ static const struct nft_expr_ops nft_nat .destroy = nft_nat_destroy, .dump = nft_nat_dump, .validate = nft_nat_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_nat_type__read_mostly = {
@@ -351,7 +350,6 @@ static const struct nft_expr_ops nft_nat .destroy = nft_nat_destroy, .dump = nft_nat_dump, .validate = nft_nat_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_inet_nat_type__read_mostly = {
net/netfilter/nft_numgen.c +0 -22
@@ -84,16 +84,6 @@ err:return err; } -static bool nft_ng_inc_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -const struct nft_ng_inc *priv =nft_expr_priv (expr); - -nft_reg_track_cancel (track, priv->dreg,NFT_REG32_SIZE ); - -return false; -} -static int nft_ng_dump (struct sk_buff *skb,enum nft_registers dreg,u32 modulus,enum nft_ng_types type,u32 offset) {
@@ -178,16 +168,6 @@ static int nft_ng_random_dump(struct sk_ priv->offset); } -static bool nft_ng_random_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -const struct nft_ng_random *priv =nft_expr_priv (expr); - -nft_reg_track_cancel (track, priv->dreg,NFT_REG32_SIZE ); - -return false; -} -static struct nft_expr_type nft_ng_type;static const struct nft_expr_ops nft_ng_inc_ops = { .type = &nft_ng_type,
@@ -196,7 +176,6 @@ static const struct nft_expr_ops nft_ng_ .init = nft_ng_inc_init, .destroy = nft_ng_inc_destroy, .dump = nft_ng_inc_dump, - .reduce = nft_ng_inc_reduce, };static const struct nft_expr_ops nft_ng_random_ops = {
@@ -205,7 +184,6 @@ static const struct nft_expr_ops nft_ng_ .eval = nft_ng_random_eval, .init = nft_ng_random_init, .dump = nft_ng_random_dump, - .reduce = nft_ng_random_reduce, }; static const struct nft_expr_ops *
net/netfilter/nft_objref.c +0 -2
@@ -123,7 +123,6 @@ static const struct nft_expr_ops nft_obj .deactivate = nft_objref_deactivate, .dump = nft_objref_dump, .validate = nft_objref_validate, - .reduce = NFT_REDUCE_READONLY, };struct nft_objref_map {
@@ -245,7 +244,6 @@ static const struct nft_expr_ops nft_obj .destroy = nft_objref_map_destroy, .dump = nft_objref_map_dump, .validate = nft_objref_map_validate, - .reduce = NFT_REDUCE_READONLY, }; static const struct nft_expr_ops *
net/netfilter/nft_osf.c +0 -25
@@ -131,30 +131,6 @@ static int nft_osf_validate(const structreturn nft_chain_validate_hooks (ctx->chain, hooks); } -static bool nft_osf_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -struct nft_osf *priv =nft_expr_priv (expr); -struct nft_osf *osf; - -if (!nft_reg_track_cmp (track, expr, priv->dreg)) { -nft_reg_track_update (track, expr, priv->dreg,NFT_OSF_MAXGENRELEN ); -return false; - } - - osf =nft_expr_priv (track->regs[priv->dreg].selector); -if (priv->flags != osf->flags || - priv->ttl != osf->ttl) { -nft_reg_track_update (track, expr, priv->dreg,NFT_OSF_MAXGENRELEN ); -return false; - } - -if (!track->regs[priv->dreg].bitwise) -return true; - -return false; -} -static struct nft_expr_type nft_osf_type;static const struct nft_expr_ops nft_osf_op = { .eval = nft_osf_eval,
@@ -163,7 +139,6 @@ static const struct nft_expr_ops nft_osf .dump = nft_osf_dump, .type = &nft_osf_type, .validate = nft_osf_validate, - .reduce = nft_osf_reduce, };static struct nft_expr_type nft_osf_type__read_mostly = {
net/netfilter/nft_payload.c +0 -47
77 lines not on this page · raw message
net/netfilter/nft_queue.c +0 -2
@@ -191,7 +191,6 @@ static const struct nft_expr_ops nft_que .init = nft_queue_init, .dump = nft_queue_dump, .validate = nft_queue_validate, - .reduce = NFT_REDUCE_READONLY, };static const struct nft_expr_ops nft_queue_sreg_ops = {
@@ -201,7 +200,6 @@ static const struct nft_expr_ops nft_que .init = nft_queue_sreg_init, .dump = nft_queue_sreg_dump, .validate = nft_queue_validate, - .reduce = NFT_REDUCE_READONLY, }; static const struct nft_expr_ops *
net/netfilter/nft_quota.c +0 -1
@@ -266,7 +266,6 @@ static const struct nft_expr_ops nft_quo .destroy = nft_quota_destroy, .clone = nft_quota_clone, .dump = nft_quota_dump, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_quota_type__read_mostly = {
net/netfilter/nft_range.c +0 -1
@@ -138,7 +138,6 @@ static const struct nft_expr_ops nft_ran .eval = nft_range_eval, .init = nft_range_init, .dump = nft_range_dump, - .reduce = NFT_REDUCE_READONLY, };struct nft_expr_type nft_range_type__read_mostly = {
net/netfilter/nft_redir.c +0 -3
@@ -146,7 +146,6 @@ static const struct nft_expr_ops nft_red .destroy = nft_redir_ipv4_destroy, .dump = nft_redir_dump, .validate = nft_redir_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_redir_ipv4_type__read_mostly = {
@@ -174,7 +173,6 @@ static const struct nft_expr_ops nft_red .destroy = nft_redir_ipv6_destroy, .dump = nft_redir_dump, .validate = nft_redir_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_redir_ipv6_type__read_mostly = {
@@ -203,7 +201,6 @@ static const struct nft_expr_ops nft_red .destroy = nft_redir_inet_destroy, .dump = nft_redir_dump, .validate = nft_redir_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_redir_inet_type__read_mostly = {
net/netfilter/nft_reject_inet.c +0 -1
@@ -79,7 +79,6 @@ static const struct nft_expr_ops nft_rej .init = nft_reject_init, .dump = nft_reject_dump, .validate = nft_reject_inet_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_reject_inet_type__read_mostly = {
net/netfilter/nft_reject_netdev.c +0 -1
@@ -158,7 +158,6 @@ static const struct nft_expr_ops nft_rej .init = nft_reject_init, .dump = nft_reject_dump, .validate = nft_reject_netdev_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_reject_netdev_type__read_mostly = {
net/netfilter/nft_rt.c +0 -1
@@ -195,7 +195,6 @@ static const struct nft_expr_ops nft_rt_ .init = nft_rt_get_init, .dump = nft_rt_get_dump, .validate = nft_rt_validate, - .reduce = NFT_REDUCE_READONLY, };struct nft_expr_type nft_rt_type__read_mostly = {
net/netfilter/nft_socket.c +0 -26
@@ -249,31 +249,6 @@ static int nft_socket_dump(struct sk_bufreturn 0 ; } -static bool nft_socket_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -const struct nft_socket *priv =nft_expr_priv (expr); -const struct nft_socket *socket; - -if (!nft_reg_track_cmp (track, expr, priv->dreg)) { -nft_reg_track_update (track, expr, priv->dreg, priv->len); -return false; - } - - socket =nft_expr_priv (track->regs[priv->dreg].selector); -if (priv->key != socket->key || - priv->dreg != socket->dreg || - priv->level != socket->level) { -nft_reg_track_update (track, expr, priv->dreg, priv->len); -return false; - } - -if (!track->regs[priv->dreg].bitwise) -return true; - -return nft_expr_reduce_bitwise (track, expr); -} -static int nft_socket_validate (const struct nft_ctx *ctx,const struct nft_expr *expr) {
@@ -296,7 +271,6 @@ static const struct nft_expr_ops nft_soc .init = nft_socket_init, .dump = nft_socket_dump, .validate = nft_socket_validate, - .reduce = nft_socket_reduce, };static struct nft_expr_type nft_socket_type__read_mostly = {
net/netfilter/nft_synproxy.c +0 -1
@@ -290,7 +290,6 @@ static const struct nft_expr_ops nft_syn .dump = nft_synproxy_dump, .type = &nft_synproxy_type, .validate = nft_synproxy_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_synproxy_type__read_mostly = {
net/netfilter/nft_tproxy.c +0 -1
@@ -331,7 +331,6 @@ static const struct nft_expr_ops nft_tpr .init = nft_tproxy_init, .destroy = nft_tproxy_destroy, .dump = nft_tproxy_dump, - .reduce = NFT_REDUCE_READONLY, .validate = nft_tproxy_validate, };
net/netfilter/nft_tunnel.c +0 -26
@@ -124,31 +124,6 @@ nla_put_failure:return -1 ; } -static bool nft_tunnel_get_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -const struct nft_tunnel *priv =nft_expr_priv (expr); -const struct nft_tunnel *tunnel; - -if (!nft_reg_track_cmp (track, expr, priv->dreg)) { -nft_reg_track_update (track, expr, priv->dreg, priv->len); -return false; - } - - tunnel =nft_expr_priv (track->regs[priv->dreg].selector); -if (priv->key != tunnel->key || - priv->dreg != tunnel->dreg || - priv->mode != tunnel->mode) { -nft_reg_track_update (track, expr, priv->dreg, priv->len); -return false; - } - -if (!track->regs[priv->dreg].bitwise) -return true; - -return false; -} -static struct nft_expr_type nft_tunnel_type;static const struct nft_expr_ops nft_tunnel_get_ops = { .type = &nft_tunnel_type,
@@ -156,7 +131,6 @@ static const struct nft_expr_ops nft_tun .eval = nft_tunnel_get_eval, .init = nft_tunnel_get_init, .dump = nft_tunnel_get_dump, - .reduce = nft_tunnel_get_reduce, };static struct nft_expr_type nft_tunnel_type__read_mostly = {
net/netfilter/nft_xfrm.c +0 -27
@@ -259,32 +259,6 @@ static int nft_xfrm_validate(const strucreturn nft_chain_validate_hooks (ctx->chain, hooks); } -static bool nft_xfrm_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -const struct nft_xfrm *priv =nft_expr_priv (expr); -const struct nft_xfrm *xfrm; - -if (!nft_reg_track_cmp (track, expr, priv->dreg)) { -nft_reg_track_update (track, expr, priv->dreg, priv->len); -return false; - } - - xfrm =nft_expr_priv (track->regs[priv->dreg].selector); -if (priv->key != xfrm->key || - priv->dreg != xfrm->dreg || - priv->dir != xfrm->dir || - priv->spnum != xfrm->spnum) { -nft_reg_track_update (track, expr, priv->dreg, priv->len); -return false; - } - -if (!track->regs[priv->dreg].bitwise) -return true; - -return nft_expr_reduce_bitwise (track, expr); -} -static struct nft_expr_type nft_xfrm_type;static const struct nft_expr_ops nft_xfrm_get_ops = { .type = &nft_xfrm_type,
@@ -293,7 +267,6 @@ static const struct nft_expr_ops nft_xfr .init = nft_xfrm_get_init, .dump = nft_xfrm_get_dump, .validate = nft_xfrm_validate, - .reduce = nft_xfrm_reduce, };static struct nft_expr_type nft_xfrm_type__read_mostly = {
Greg Kroah-Hartman
maintainerPATCH 619/675 netfilter: nft_fib: reject fib expression on the netdev egress hook
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Theodor Arsenij Larionov-Trichkine <[email protected]>
[ Upstream commit d07955dd34ecae17d35d8c7d0a273a3fba653a8c ]
A fib expression in a netdev egress base chain dereferences nft_in(pkt), NULL on the transmit path, causing a NULL pointer dereference at eval. nft_fib_validate() masks the hook with NF_INET_* values, but netdev hook numbers are a separate enum that aliases them (NF_NETDEV_EGRESS == NF_INET_LOCAL_IN), so an egress chain passes validation and then faults.
Add nft_fib_netdev_validate() that limits each result/flag to the netdev hook where the device it reads exists: the input-device cases (OIF, OIFNAME, ADDRTYPE with F_IIF) to ingress, the output-device case (ADDRTYPE with F_OIF) to egress, ADDRTYPE with no device flag to both. Also restrict nft_fib_validate() to NFPROTO_IPV4/IPV6/INET so its NF_INET_* masks are not applied to another family's hooks.
--- net/netfilter/nft_fib.c | 9 +++++++++ net/netfilter/nft_fib_netdev.c | 29 ++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-)
net/netfilter/nft_fib.c +9 -0
@@ -31,6 +31,15 @@ int nft_fib_validate(const struct nft_ctconst struct nft_fib *priv =nft_expr_priv (expr);unsigned int hooks; +switch (ctx->family) { +case NFPROTO_IPV4 : +case NFPROTO_IPV6 : +case NFPROTO_INET : +break ; +default : +return -EOPNOTSUPP ; + } +switch (priv->result) {case NFT_FIB_RESULT_OIF :case NFT_FIB_RESULT_OIFNAME :
net/netfilter/nft_fib_netdev.c +28 -1
@@ -50,6 +50,33 @@ static void nft_fib_netdev_eval(const st regs->verdict.code =NFT_BREAK ; } +static int nft_fib_netdev_validate (const struct nft_ctx *ctx, +const struct nft_expr *expr) +{ +const struct nft_fib *priv =nft_expr_priv (expr); +unsigned int hooks; + +switch (priv->result) { +case NFT_FIB_RESULT_OIF : +case NFT_FIB_RESULT_OIFNAME : + hooks = (1 <<NF_NETDEV_INGRESS ); +break ; +case NFT_FIB_RESULT_ADDRTYPE : +if (priv->flags &NFTA_FIB_F_IIF ) + hooks = (1 <<NF_NETDEV_INGRESS ); +else if (priv->flags &NFTA_FIB_F_OIF ) + hooks = (1 <<NF_NETDEV_EGRESS ); +else + hooks = (1 <<NF_NETDEV_INGRESS ) | + (1 <<NF_NETDEV_EGRESS ); +break ; +default : +return -EINVAL ; + } + +return nft_chain_validate_hooks (ctx->chain, hooks); +} +static struct nft_expr_type nft_fib_netdev_type;static const struct nft_expr_ops nft_fib_netdev_ops = { .type = &nft_fib_netdev_type,
@@ -57,7 +84,7 @@ static const struct nft_expr_ops nft_fib .eval = nft_fib_netdev_eval, .init = nft_fib_init, .dump = nft_fib_dump, - .validate = nft_fib_validate, + .validate = nft_fib_netdev_validate, };static struct nft_expr_type nft_fib_netdev_type__read_mostly = {
Greg Kroah-Hartman
maintainerPATCH 620/675 netfilter: nf_conntrack_sip: remove net variable shadowing
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit 7970d6aaf710db166de98c5356a260089896fae5 ]
net is already set, derived from nf_conn.
I don't see how the device could be living in a different netns than the conntrack entry.
Remove the extra variable and re-use existing one.
Stable-dep-of: e5e24a365a5e ("netfilter: nf_conntrack_sip: validate skb_dst() before accessing it")
--- net/netfilter/nf_conntrack_sip.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
net/netfilter/nf_conntrack_sip.c +1 -2
@@ -948,9 +948,8 @@ static int set_expected_rtp_rtcp(struct saddr = &ct->tuplehash[!dir].tuple.src.u3; }else if (sip_external_media) {struct net_device *dev =skb_dst (skb)->dev; -struct net *net =dev_net (dev); -struct flowi fl;struct dst_entry *dst =NULL ; +struct flowi fl;memset (&fl,0 ,sizeof (fl));
Greg Kroah-Hartman
maintainerPATCH 621/675 netfilter: nf_conntrack_sip: validate skb_dst() before accessing it
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso <[email protected]>
[ Upstream commit e5e24a365a5e024efef63cc49abb345fbd4852c5 ]
tc ingress and openvswitch do not guarantee routing information to be available. These subsystems use the conntrack helper infrastructure, and the SIP helper relies on the skb_dst() to be present if sip_external_media is set to 1 (which is disabled by default as a module parameter).
This effectively disables the sip_external_media toggle for these subsystems without resulting in a crash.
--- net/netfilter/nf_conntrack_sip.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
net/netfilter/nf_conntrack_sip.c +5 -2
@@ -947,7 +947,6 @@ static int set_expected_rtp_rtcp(structreturn NF_ACCEPT ; saddr = &ct->tuplehash[!dir].tuple.src.u3; }else if (sip_external_media) { -struct net_device *dev =skb_dst (skb)->dev;struct dst_entry *dst =NULL ;struct flowi fl;
@@ -969,7 +968,11 @@ static int set_expected_rtp_rtcp(struct* through the same interface as the signalling peer. */ if (dst) { -bool external_media = (dst->dev == dev); +const struct dst_entry *this_dst =skb_dst (skb); +bool external_media = false; + +if (this_dst && dst->dev == this_dst->dev) + external_media = true;dst_release (dst);if (external_media)
Greg Kroah-Hartman
maintainerPATCH 622/675 gpu: Move DRM buddy allocator one level up (part two)
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joel Fernandes <[email protected]>
[ Upstream commit ba110db8e1bc206c13fd7d985e79b033f53bfdea ]
Move the DRM buddy allocator one level up so that it can be used by GPU drivers (example, nova-core) that have usecases other than DRM (such as VFIO vGPU support). Modify the API, structures and Kconfigs to use "gpu_buddy" terminology. Adapt the drivers and tests to use the new API.
The commit cannot be split due to bisectability, however no functional change is intended. Verified by running K-UNIT tests and build tested various configurations.
[airlied: I've split this into two so git can find copies easier. I've also just nuked drm_random library, that stuff needs to be done elsewhere and only the buddy tests seem to be using it].
Stable-dep-of: 56bc6384314f ("gpu/buddy: bail out of try_harder when alignment cannot be honoured")
---
Documentation/gpu/drm-mm.rst | 10
MAINTAINERS | 13
drivers/gpu/Kconfig | 13
drivers/gpu/Makefile | 3
drivers/gpu/buddy.c | 1322 +++++++++++++++++++
drivers/gpu/drm/Kconfig | 5
drivers/gpu/drm/Kconfig.debug | 1
drivers/gpu/drm/Makefile | 1
drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 2
drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h | 12
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | 79 -
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h | 20
drivers/gpu/drm/drm_buddy.c | 1278 ------------------
drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 3
drivers/gpu/drm/i915/i915_scatterlist.c | 10
drivers/gpu/drm/i915/i915_ttm_buddy_manager.c | 59
drivers/gpu/drm/i915/i915_ttm_buddy_manager.h | 4
drivers/gpu/drm/i915/selftests/intel_memory_region.c | 20
drivers/gpu/drm/lib/drm_random.c | 44
drivers/gpu/drm/lib/drm_random.h | 28
drivers/gpu/drm/tests/Makefile | 1
drivers/gpu/drm/tests/drm_buddy_test.c | 788 -----------
drivers/gpu/drm/tests/drm_exec_test.c | 2
drivers/gpu/drm/tests/drm_mm_test.c | 2
drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c | 4
drivers/gpu/drm/ttm/tests/ttm_mock_manager.c | 18
drivers/gpu/drm/ttm/tests/ttm_mock_manager.h | 4
drivers/gpu/drm/xe/xe_res_cursor.h | 34
drivers/gpu/drm/xe/xe_svm.c | 12
drivers/gpu/drm/xe/xe_ttm_vram_mgr.c | 71 -
drivers/gpu/drm/xe/xe_ttm_vram_mgr_types.h | 4
drivers/gpu/tests/Makefile | 4
drivers/gpu/tests/gpu_buddy_test.c | 788 +++++++++++
drivers/gpu/tests/gpu_random.c | 44
drivers/gpu/tests/gpu_random.h | 28
drivers/video/Kconfig | 1
include/drm/drm_buddy.h | 165 --
include/linux/gpu_buddy.h | 177 ++
38 files changed, 2597 insertions(+), 2477 deletions(-)
create mode 100644 drivers/gpu/Kconfig
create mode 100644 drivers/gpu/buddy.c
create mode 100644 drivers/gpu/tests/Makefile
rename drivers/gpu/{drm/tests/drm_buddy_test.c => tests/gpu_buddy_test.c} (66%)
rename drivers/gpu/{drm/lib/drm_random.c => tests/gpu_random.c} (59%)
rename drivers/gpu/{drm/lib/drm_random.h => tests/gpu_random.h} (53%)
create mode 100644 include/linux/gpu_buddy.hDocumentation/gpu/drm-mm.rst +8 -2
@@ -509,8 +509,14 @@ DRM GPUVM Function References DRM Buddy Allocator =================== -DRM Buddy Function References ------------------------------ +Buddy Allocator Function References (GPU buddy) +----------------------------------------------- + +.. kernel-doc:: drivers/gpu/buddy.c + :export: + +DRM Buddy Specific Logging Function References +---------------------------------------------- .. kernel-doc:: drivers/gpu/drm/drm_buddy.c :export:
MAINTAINERS +13 -0
@@ -8656,6 +8656,19 @@ T: git https://gitlab.freedesktop.org/dr F: drivers/gpu/drm/ttm/ F: include/drm/ttm/ +GPU BUDDY ALLOCATOR +M: Matthew Auld <[email protected]> +M: Arun Pravin <[email protected]> +R: Christian Koenig <[email protected]> +L: [email protected] +S: Maintained +T: git https://gitlab.freedesktop.org/drm/misc/kernel.git +F: drivers/gpu/drm_buddy.c +F: drivers/gpu/buddy.c +F: drivers/gpu/tests/gpu_buddy_test.c +F: include/linux/gpu_buddy.h +F: include/drm/drm_buddy.h + DRM AUTOMATED TESTING M: Helen Koike <[email protected]> M: Vignesh Raman <[email protected]>
drivers/gpu/Kconfig new file +13 -0
@@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0 + +config GPU_BUDDY + bool + help + A page based buddy allocator for GPU memory. + +config GPU_BUDDY_KUNIT_TEST + tristate "KUnit tests for GPU buddy allocator" if !KUNIT_ALL_TESTS + depends on GPU_BUDDY && KUNIT + default KUNIT_ALL_TESTS + help + KUnit tests for the GPU buddy allocator.
drivers/gpu/Makefile +2 -1
@@ -2,7 +2,8 @@ # drm/tegra depends on host1x, so if both drivers are built-in care must be # taken to initialize them in the correct order. Link order is the only way # to ensure this currently. -obj-y += host1x/ drm/ vga/ +obj-y += host1x/ drm/ vga/ tests/ obj-$(CONFIG_IMX_IPUV3_CORE) += ipu-v3/ obj-$(CONFIG_TRACE_GPU_MEM) += trace/ obj-$(CONFIG_NOVA_CORE) += nova-core/ +obj-$(CONFIG_GPU_BUDDY) += buddy.o
drivers/gpu/buddy.c new file +1322 -0
1,322 lines not on this page · raw message
drivers/gpu/drm/Kconfig +1 -4
@@ -220,6 +220,7 @@ config DRM_GPUSVM config DRM_BUDDY tristate depends on DRM + select GPU_BUDDY help A page based buddy allocator
@@ -416,10 +417,6 @@ config DRM_HYPERV config DRM_PANEL_BACKLIGHT_QUIRKS tristate -config DRM_LIB_RANDOM - bool - default n - config DRM_PRIVACY_SCREEN bool default n
drivers/gpu/drm/Kconfig.debug +0 -1
@@ -69,7 +69,6 @@ config DRM_KUNIT_TEST select DRM_EXPORT_FOR_TESTS if m select DRM_GEM_SHMEM_HELPER select DRM_KUNIT_TEST_HELPERS - select DRM_LIB_RANDOM select DRM_SYSFB_HELPER select PRIME_NUMBERS default KUNIT_ALL_TESTS
drivers/gpu/drm/Makefile +0 -1
@@ -77,7 +77,6 @@ drm-$(CONFIG_DRM_CLIENT) += \ drm_client.o \ drm_client_event.o \ drm_client_modeset.o -drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o drm-$(CONFIG_COMPAT) += drm_ioc32.o drm-$(CONFIG_DRM_PANEL) += drm_panel.o drm-$(CONFIG_OF) += drm_of.o
drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +1 -1
@@ -5416,7 +5416,7 @@ int amdgpu_ras_add_critical_region(strucstruct amdgpu_ras *con =amdgpu_ras_get_context (adev);struct amdgpu_vram_mgr_resource *vres;struct ras_critical_region *region; -struct drm_buddy_block *block; +struct gpu_buddy_block *block;int ret =0 ;if (!bo || !bo->tbo.resource)
drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h +6 -6
@@ -55,7 +55,7 @@ static inline void amdgpu_res_first(stru uint64_t start, uint64_t size, struct amdgpu_res_cursor *cur) { - struct drm_buddy_block *block; + struct gpu_buddy_block *block;struct list_head *head, *next;struct drm_mm_node *node;
@@ -71,7 +71,7 @@ static inline void amdgpu_res_first(stru head = &to_amdgpu_vram_mgr_resource (res)->blocks; block =list_first_entry_or_null (head, - struct drm_buddy_block, + struct gpu_buddy_block, link);if (!block) goto fallback;
@@ -81,7 +81,7 @@ static inline void amdgpu_res_first(stru next = block->link.next;if (next != head) - block = list_entry(next, struct drm_buddy_block, link); + block = list_entry(next, struct gpu_buddy_block, link); } cur->start =amdgpu_vram_mgr_block_start (block) + start;
@@ -125,7 +125,7 @@ fallback:*/ static inline void amdgpu_res_next (struct amdgpu_res_cursor *cur,uint64_t size) { -struct drm_buddy_block *block; +struct gpu_buddy_block *block;struct drm_mm_node *node;struct list_head *next;
@@ -146,7 +146,7 @@ static inline void amdgpu_res_next(struc block = cur->node; next = block->link.next; - block = list_entry(next, struct drm_buddy_block, link); + block = list_entry(next, struct gpu_buddy_block, link); cur->node = block; cur->start =amdgpu_vram_mgr_block_start (block);
@@ -175,7 +175,7 @@ static inline void amdgpu_res_next(struc*/ static inline bool amdgpu_res_cleared (struct amdgpu_res_cursor *cur) { -struct drm_buddy_block *block; +struct gpu_buddy_block *block;switch (cur->mem_type) {case TTM_PL_VRAM :
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c +40 -39
259 lines not on this page · raw message
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h +10 -10
@@ -24,11 +24,11 @@ #ifndef __AMDGPU_VRAM_MGR_H__ #define __AMDGPU_VRAM_MGR_H__ -#include <drm/drm_buddy.h> +#include <linux/gpu_buddy.h> struct amdgpu_vram_mgr { struct ttm_resource_manager manager; - struct drm_buddy mm; + struct gpu_buddy mm; /* protects access to buffer objects */ struct mutex lock; struct list_head reservations_pending;
@@ -57,19 +57,19 @@ struct amdgpu_vram_mgr_resource {struct amdgpu_vres_task task; }; -static inline u64 amdgpu_vram_mgr_block_start (struct drm_buddy_block *block) +static inline u64 amdgpu_vram_mgr_block_start (struct gpu_buddy_block *block) { -return drm_buddy_block_offset (block); +return gpu_buddy_block_offset (block); } -static inline u64 amdgpu_vram_mgr_block_size (struct drm_buddy_block *block) +static inline u64 amdgpu_vram_mgr_block_size (struct gpu_buddy_block *block) { -return (u64 )PAGE_SIZE <<drm_buddy_block_order (block); +return (u64 )PAGE_SIZE <<gpu_buddy_block_order (block); } -static inline bool amdgpu_vram_mgr_is_cleared (struct drm_buddy_block *block) +static inline bool amdgpu_vram_mgr_is_cleared (struct gpu_buddy_block *block) { -return drm_buddy_block_is_clear (block); +return gpu_buddy_block_is_clear (block); } static inline struct amdgpu_vram_mgr_resource *
@@ -82,8 +82,8 @@ static inline void amdgpu_vram_mgr_set_c {struct amdgpu_vram_mgr_resource *ares =to_amdgpu_vram_mgr_resource (res); -WARN_ON (ares->flags &DRM_BUDDY_CLEARED ); - ares->flags |=DRM_BUDDY_CLEARED ; +WARN_ON (ares->flags &GPU_BUDDY_CLEARED ); + ares->flags |=GPU_BUDDY_CLEARED ; } int amdgpu_vram_mgr_query_address_block_info(struct amdgpu_vram_mgr *mgr,
drivers/gpu/drm/drm_buddy.c +10 -1268
1,227 lines not on this page · raw message
drivers/gpu/drm/i915/gem/i915_gem_ttm.c +2 -1
Lines of this file are not shown. View the raw message.
drivers/gpu/drm/i915/i915_scatterlist.c +5 -5
Lines of this file are not shown. View the raw message.
drivers/gpu/drm/i915/i915_ttm_buddy_manager.c +30 -29
59 lines not on this page · raw message
drivers/gpu/drm/i915/i915_ttm_buddy_manager.h +2 -2
Lines of this file are not shown. View the raw message.
drivers/gpu/drm/i915/selftests/intel_memory_region.c +10 -10
Lines of this file are not shown. View the raw message.
drivers/gpu/drm/lib/drm_random.c deleted +0 -44
44 lines not on this page · raw message
drivers/gpu/drm/lib/drm_random.h deleted +0 -28
Lines of this file are not shown. View the raw message.
drivers/gpu/drm/tests/Makefile +0 -1
Lines of this file are not shown. View the raw message.
drivers/gpu/drm/tests/drm_buddy_test.c deleted +0 -788
788 lines not on this page · raw message
drivers/gpu/drm/tests/drm_exec_test.c +0 -2
Lines of this file are not shown. View the raw message.
drivers/gpu/drm/tests/drm_mm_test.c +0 -2
Lines of this file are not shown. View the raw message.
drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c +2 -2
Lines of this file are not shown. View the raw message.
drivers/gpu/drm/ttm/tests/ttm_mock_manager.c +9 -9
Lines of this file are not shown. View the raw message.
drivers/gpu/drm/ttm/tests/ttm_mock_manager.h +2 -2
Lines of this file are not shown. View the raw message.
drivers/gpu/drm/xe/xe_res_cursor.h +17 -17
Lines of this file are not shown. View the raw message.
drivers/gpu/drm/xe/xe_svm.c +6 -6
Lines of this file are not shown. View the raw message.
drivers/gpu/drm/xe/xe_ttm_vram_mgr.c +36 -35
71 lines not on this page · raw message
drivers/gpu/drm/xe/xe_ttm_vram_mgr_types.h +2 -2
Lines of this file are not shown. View the raw message.
drivers/gpu/tests/Makefile new file +4 -0
Lines of this file are not shown. View the raw message.
drivers/gpu/tests/gpu_buddy_test.c new file +788 -0
788 lines not on this page · raw message
drivers/gpu/tests/gpu_random.c new file +44 -0
44 lines not on this page · raw message
drivers/gpu/tests/gpu_random.h new file +28 -0
Lines of this file are not shown. View the raw message.
drivers/video/Kconfig +1 -0
Lines of this file are not shown. View the raw message.
include/drm/drm_buddy.h +6 -159
165 lines not on this page · raw message
include/linux/gpu_buddy.h new file +177 -0
177 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Part of the diff is not shown here. View the raw message.
Greg Kroah-Hartman
maintainerPATCH 623/675 gpu/buddy: bail out of try_harder when alignment cannot be honoured
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arunpravin Paneer Selvam <[email protected]>
[ Upstream commit 56bc6384314fb9ae98975fb2af8b143097ede3dc ]
The try_harder contiguous fallback could return a range whose start offset did not match the caller's min_block_size. When a candidate's start is misaligned, realign it: free the misaligned run and reallocate exactly @size at the next lower min_block_size boundary. This keeps the returned size unchanged with no surplus to trim, and rejects the request only when no aligned candidate fits.
v2: align misaligned candidates down to min_block_size instead of
bailing out, for both the RHS and LHS paths (Matthew).
--- drivers/gpu/buddy.c | 65 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 20 deletions(-)
drivers/gpu/buddy.c +45 -20
@@ -901,22 +901,30 @@ static int __gpu_buddy_alloc_range(struc blocks, total_allocated_on_err); } +static int __alloc_contig_aligned_retry (struct gpu_buddy *mm, +u64 unaligned_offset, +u64 size, +u64 min_block_size, +struct list_head *blocks) +{ +u64 aligned_offset =round_down (unaligned_offset, min_block_size); + +return __gpu_buddy_alloc_range (mm, aligned_offset, size,NULL , blocks); +} +static int __alloc_contig_try_harder (struct gpu_buddy *mm,u64 size,u64 min_block_size,struct list_head *blocks) { -u64 rhs_offset, lhs_offset, lhs_size, filled; +u64 rhs_offset, lhs_offset, filled;struct gpu_buddy_block *block;unsigned int tree, order; -LIST_HEAD (blocks_lhs); -unsigned long pages;u64 modify_size;int err; modify_size =rounddown_pow_of_two (size); - pages = modify_size >>ilog2 (mm->chunk_size); - order =fls (pages) -1 ; + order =ilog2 (modify_size) -ilog2 (mm->chunk_size);if (order ==0 )return -ENOSPC ;
@@ -932,31 +940,48 @@ static int __alloc_contig_try_harder(strwhile (iter) { block =rbtree_get_free_block (iter); -/* Allocate blocks traversing RHS */ rhs_offset =gpu_buddy_block_offset (block); + +/* Allocate blocks traversing RHS */ err =__gpu_buddy_alloc_range (mm, rhs_offset, size, &filled, blocks); -if (!err || err != -ENOSPC ) +if (err && err != -ENOSPC )return err; - - lhs_size =max ((size - filled), min_block_size); -if (!IS_ALIGNED (lhs_size, min_block_size)) - lhs_size =round_up (lhs_size, min_block_size); - -/* Allocate blocks traversing LHS */ - lhs_offset =gpu_buddy_block_offset (block) - lhs_size; - err =__gpu_buddy_alloc_range (mm, lhs_offset, lhs_size, -NULL , &blocks_lhs); +if (!err &&IS_ALIGNED (rhs_offset, min_block_size)) +return 0 ;if (!err) { -list_splice (&blocks_lhs, blocks); +/* Allocate the unaligned RHS offset using round_down */ +gpu_buddy_free_list_internal (mm, blocks); + err =__alloc_contig_aligned_retry (mm, rhs_offset, + size, + min_block_size, + blocks); +if (!err) +return 0 ; +if (err != -ENOSPC ) { +gpu_buddy_free_list_internal (mm, blocks); +return err; + } + goto next; + } + +if (size - filled > rhs_offset) + goto next; + + lhs_offset = rhs_offset - (size - filled); + +/* Allocate the unaligned LHS offset using round_down */ +gpu_buddy_free_list_internal (mm, blocks); + err =__alloc_contig_aligned_retry (mm, lhs_offset, size, + min_block_size, blocks); +if (!err)return 0 ; - }else if (err != -ENOSPC ) { +if (err != -ENOSPC ) {gpu_buddy_free_list_internal (mm, blocks);return err; } -/* Free blocks for the next iteration */ +next:gpu_buddy_free_list_internal (mm, blocks); - iter =rb_prev (iter); } }
Greg Kroah-Hartman
maintainerPATCH 624/675 pinctrl: renesas: rzg2l: Use -ENOTSUPP instead of -EOPNOTSUPP
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Claudiu Beznea <[email protected]>
[ Upstream commit c1492da3939c89372929e062d731f328f7693f1e ]
The pinctrl and GPIO core code make exceptions for the -ENOTSUPP error code. One such example is gpio_set_config_with_argument_optional(), which returns success when gpio_set_config_with_argument() returns -ENOTSUPP, but reports failure for all other error codes.
Returning -EOPNOTSUPP from the pinctrl driver on the unsupported pinctrl operation may lead to boot failures when pinctrl drivers implements struct gpio_chip::set_config, the system uses GPIO hogs, and the struct gpio_chip::set_config implementation returns -EOPNOTSUPP for the unsupported operations.
Return -ENOTSUPP for the unsupported pinctrl operation.
--- drivers/pinctrl/renesas/pinctrl-rzg2l.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/pinctrl/renesas/pinctrl-rzg2l.c +4 -4
@@ -1097,7 +1097,7 @@ static int rzg2l_read_oen(struct rzg2l_pint bit;if (!pctrl->data->pin_to_oen_bit) -return -EOPNOTSUPP ; +return -ENOTSUPP ; bit = pctrl->data->pin_to_oen_bit (pctrl, _pin);if (bit <0 )
@@ -1115,7 +1115,7 @@ static int rzg2l_write_oen(struct rzg2l_int bit;if (!pctrl->data->pin_to_oen_bit) -return -EOPNOTSUPP ; +return -ENOTSUPP ; bit = pctrl->data->pin_to_oen_bit (pctrl, _pin);if (bit <0 )
@@ -1552,7 +1552,7 @@ static int rzg2l_pinctrl_pinconf_set(strbreak ;default : -return -EOPNOTSUPP ; +return -ENOTSUPP ; } }
@@ -1634,7 +1634,7 @@ static int rzg2l_pinctrl_pinconf_group_g/* Check config matching between to pin */ if (i && prev_config != *config) -return -EOPNOTSUPP ; +return -ENOTSUPP ; prev_config = *config; }
Greg Kroah-Hartman
maintainerPATCH 625/675 NFSD: pass nfsd_file to nfsd_iter_read()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mike Snitzer <[email protected]>
[ Upstream commit 803bc849f0039291f546ba0e2237faebeb5c073e ]
Prepare for nfsd_iter_read() to use the DIO alignment stored in nfsd_file by passing the nfsd_file to nfsd_iter_read() rather than just the file which is associaed with the nfsd_file.
This means nfsd4_encode_readv() now also needs the nfsd_file rather than the file. Instead of changing the file arg to be the nfsd_file, we discard the file arg as the nfsd_file (and indeed the file) is already available via the "read" argument.
Stable-dep-of: 18c1cc698861 ("SUNRPC: Return an error from xdr_buf_to_bvec() on overflow")
--- fs/nfsd/nfs4xdr.c | 8 ++++---- fs/nfsd/vfs.c | 7 ++++--- fs/nfsd/vfs.h | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-)
fs/nfsd/nfs4xdr.c +4 -4
@@ -4478,7 +4478,7 @@ out_err:static __be32 nfsd4_encode_readv (struct nfsd4_compoundres *resp,struct nfsd4_read *read, -struct file *file,unsigned long maxcount) +unsigned long maxcount) {struct xdr_stream *xdr = resp->xdr;unsigned int base = xdr->buf->page_len & ~PAGE_MASK ;
@@ -4489,7 +4489,7 @@ static __be32 nfsd4_encode_readv(structif (xdr_reserve_space_vec (xdr, maxcount) <0 )return nfserr_resource; - nfserr =nfsd_iter_read (resp->rqstp, read->rd_fhp, file, + nfserr =nfsd_iter_read (resp->rqstp, read->rd_fhp, read->rd_nf, read->rd_offset, &maxcount, base, &read->rd_eof); read->rd_length = maxcount;
@@ -4536,7 +4536,7 @@ nfsd4_encode_read(struct nfsd4_compoundrif (file->f_op->splice_read && splice_ok) nfserr =nfsd4_encode_splice_read (resp, read, file, maxcount);else - nfserr =nfsd4_encode_readv (resp, read, file, maxcount); + nfserr =nfsd4_encode_readv (resp, read, maxcount);if (nfserr) {xdr_truncate_encode (xdr, eof_offset);return nfserr;
@@ -5432,7 +5432,7 @@ nfsd4_encode_read_plus_data(struct nfsd4if (file->f_op->splice_read && splice_ok) nfserr =nfsd4_encode_splice_read (resp, read, file, maxcount);else - nfserr =nfsd4_encode_readv (resp, read, file, maxcount); + nfserr =nfsd4_encode_readv (resp, read, maxcount);if (nfserr)return nfserr;
fs/nfsd/vfs.c +4 -3
@@ -1078,7 +1078,7 @@ __be32 nfsd_splice_read(struct svc_rqst* nfsd_iter_read - Perform a VFS read using an iterator * @rqstp: RPC transaction context * @fhp: file handle of file to be read -* @file: opened struct file of file to be read +* @nf: opened struct nfsd_file of file to be read * @offset: starting byte offset * @count: IN: requested number of bytes; OUT: number of bytes read * @base: offset in first page of read buffer
@@ -1091,9 +1091,10 @@ __be32 nfsd_splice_read(struct svc_rqst* returned. */ __be32 nfsd_iter_read (struct svc_rqst *rqstp,struct svc_fh *fhp, -struct file *file,loff_t offset,unsigned long *count, +struct nfsd_file *nf,loff_t offset,unsigned long *count,unsigned int base,u32 *eof) { +struct file *file = nf->nf_file;unsigned long v, total;struct iov_iter iter;struct kiocb kiocb;
@@ -1346,7 +1347,7 @@ __be32 nfsd_read(struct svc_rqst *rqstp,if (file->f_op->splice_read &&nfsd_read_splice_ok (rqstp)) err =nfsd_splice_read (rqstp, fhp, file, offset, count, eof);else - err =nfsd_iter_read (rqstp, fhp, file, offset, count,0 , eof); + err =nfsd_iter_read (rqstp, fhp, nf, offset, count,0 , eof);nfsd_file_put (nf);trace_nfsd_read_done (rqstp, fhp, offset, *count);
fs/nfsd/vfs.h +1 -1
@@ -122,7 +122,7 @@ __be32 nfsd_splice_read(struct svc_rqstunsigned long *count, u32 *eof);__be32 nfsd_iter_read (struct svc_rqst *rqstp,struct svc_fh *fhp, -struct file *file,loff_t offset, +struct nfsd_file *nf,loff_t offset,unsigned long *count,unsigned int base,u32 *eof);bool nfsd_read_splice_ok (struct svc_rqst *rqstp);
Greg Kroah-Hartman
maintainerPATCH 626/675 sunrpc: allocate a separate bvec array for socket sends
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Layton <[email protected]>
[ Upstream commit 6b3b697d65d46a0f640216a3f6c72856c159c567 ]
svc_tcp_sendmsg() calls xdr_buf_to_bvec() with the second slot of rq_bvec as the start, but doesn't reduce the array length by one, which could lead to an array overrun. Also, rq_bvec is always rq_maxpages in length, which can be too short in some cases, since the TCP record marker consumes a slot.
Fix both problems by adding a separate bvec array to the svc_sock that is specifically for sending. For TCP, make this array one slot longer than rq_maxpages, to account for the record marker. For UDP, only allocate as large an array as we need since it's limited to 64k of payload.
Stable-dep-of: 18c1cc698861 ("SUNRPC: Return an error from xdr_buf_to_bvec() on overflow")
--- include/linux/sunrpc/svcsock.h | 3 ++ net/sunrpc/svcsock.c | 55 +++++++++++++++++++++++++++++++++++------ 2 files changed, 51 insertions(+), 7 deletions(-)
include/linux/sunrpc/svcsock.h +3 -0
@@ -26,6 +26,9 @@ struct svc_sock {void (*sk_odata)(struct sock *);void (*sk_owspace)(struct sock *); +/* For sends (protected by xpt_mutex) */ +struct bio_vec *sk_bvec; +/* private TCP part */ /* On-the-wire fragment header: */ __be32 sk_marker;
net/sunrpc/svcsock.c +48 -7
116 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 627/675 SUNRPC: Add helpers to convert xdr_buf byte ranges to scatterlists
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit e9be933959b581effd426f93b86654f5fbf0c574 ]
The crypto/krb5 library accepts data in scatterlist form, but the GSS-API layer presents RPC payloads as struct xdr_buf. Bridge that gap with a pair of helper functions:
xdr_buf_to_sg() - populate a caller-supplied scatterlist
array from a byte range
xdr_buf_to_sg_alloc() - populate a caller-supplied inline
scatterlist, chaining to a heap- allocated overflow for large payloads
The inline array (typically stack-allocated at eight entries) covers the common case of small RPCs with no heap allocation on the encrypt/decrypt path. Only buffers spanning many pages incur a kmalloc for the chained extension.
The segment-walking logic follows the same head, page array, tail traversal as xdr_process_buf(), but populates a scatterlist directly rather than invoking a per-segment callback. sg_next() traversal makes the walker safe for chained scatterlists. Once subsequent patches reroute all per-message crypto operations through crypto/krb5, xdr_process_buf() loses its last callers and is removed.
Stable-dep-of: 18c1cc698861 ("SUNRPC: Return an error from xdr_buf_to_bvec() on overflow")
--- include/linux/sunrpc/xdr.h | 15 +++ net/sunrpc/xdr.c | 199 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 214 insertions(+)
include/linux/sunrpc/xdr.h +15 -0
@@ -140,6 +140,21 @@ int xdr_alloc_bvec(struct xdr_buf *buf,void xdr_free_bvec (struct xdr_buf *buf);unsigned int xdr_buf_to_bvec (struct bio_vec *bvec,unsigned int bvec_size,const struct xdr_buf *xdr); +int xdr_buf_to_sg (const struct xdr_buf *buf,unsigned int offset, +unsigned int len,struct scatterlist *sg,unsigned int nsg); +int xdr_buf_to_sg_alloc (const struct xdr_buf *buf,unsigned int offset, +unsigned int len,struct scatterlist *sg_head, +unsigned int sg_head_nents, +struct scatterlist **sg_overflow,gfp_t gfp); + +/* +* Inline scatterlist entries for xdr_buf_to_sg_alloc(). Sized to cover the +* head kvec, tail kvec, and a few page fragments without any heap allocation. +*/ +enum { +XDR_BUF_TO_SG_NENTS =8 , +}; +static inline __be32 *xdr_encode_array (__be32 *p,const void *s,unsigned int len) {
net/sunrpc/xdr.c +199 -0
205 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 628/675 SUNRPC: Return an error from xdr_buf_to_bvec() on overflow
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 18c1cc69886192e33536498289d26dba6894e3d5 ]
xdr_buf_to_bvec() returns a slot count even when the caller's bvec budget is exhausted partway through the xdr_buf. Callers feed that count into iov_iter_bvec() and continue as if the conversion had succeeded, silently sending or writing fewer bytes than the data length declares. For an NFS WRITE the server reports the truncated transfer to the client as full success.
The overflow represents an internal invariant violation: a higher layer reserved a bvec budget too small for the xdr_buf it then asked the encoder to convert. That is a server-side fault, not a media I/O failure and not a malformed client argument.
Change xdr_buf_to_bvec() to return a signed int and have the overflow label return -ESERVERFAULT. Update the three callers to detect the negative return and fail the request: nfsd_vfs_write() folds the error into host_err, which nfserrno() translates to nfserr_serverfault for the WRITE reply; svc_udp_sendto() and svc_tcp_sendmsg() propagate the error out of the send path.
--- fs/nfsd/vfs.c | 8 +++++++- include/linux/sunrpc/xdr.h | 4 ++-- net/sunrpc/svcsock.c | 14 ++++++++++++-- net/sunrpc/xdr.c | 11 ++++++----- 4 files changed, 27 insertions(+), 10 deletions(-)
fs/nfsd/vfs.c +7 -1
@@ -1203,7 +1203,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, sunsigned long exp_op_flags =0 ;unsigned int pflags = current->flags;bool restore_flags = false; -unsigned int nvecs; +int nvecs;trace_nfsd_write_opened (rqstp, fhp, offset, *cnt);
@@ -1243,7 +1243,13 @@ nfsd_vfs_write(struct svc_rqst *rqstp, s } nvecs =xdr_buf_to_bvec (rqstp->rq_bvec, rqstp->rq_maxpages, payload); +if (nvecs <0 ) { + host_err = nvecs; + goto out_nfserr; + } +iov_iter_bvec (&iter,ITER_SOURCE , rqstp->rq_bvec, nvecs, *cnt); + since =READ_ONCE (file->f_wb_err);if (verf)nfsd_copy_write_verifier (verf, nn);
include/linux/sunrpc/xdr.h +2 -2
@@ -138,8 +138,8 @@ void xdr_terminate_string(const struct xsize_t xdr_buf_pagecount (const struct xdr_buf *buf);int xdr_alloc_bvec (struct xdr_buf *buf,gfp_t gfp);void xdr_free_bvec (struct xdr_buf *buf); -unsigned int xdr_buf_to_bvec (struct bio_vec *bvec,unsigned int bvec_size, -const struct xdr_buf *xdr); +int xdr_buf_to_bvec (struct bio_vec *bvec,unsigned int bvec_size, +const struct xdr_buf *xdr);int xdr_buf_to_sg (const struct xdr_buf *buf,unsigned int offset,unsigned int len,struct scatterlist *sg,unsigned int nsg); int xdr_buf_to_sg_alloc(const struct xdr_buf *buf, unsigned int offset,
net/sunrpc/svcsock.c +12 -2
@@ -748,7 +748,7 @@ static int svc_udp_sendto(struct svc_rqs .msg_flags = MSG_SPLICE_PAGES, .msg_controllen = sizeof(buffer), }; -unsigned int count; +int count;int err;svc_udp_release_ctxt (xprt, rqstp->rq_xprt_ctxt);
@@ -762,6 +762,10 @@ static int svc_udp_sendto(struct svc_rqs goto out_notconn; count =xdr_buf_to_bvec (svsk->sk_bvec,SUNRPC_MAX_UDP_SENDPAGES , xdr); +if (count <0 ) { + err = count; + goto out_trace; + }iov_iter_bvec (&msg.msg_iter,ITER_SOURCE , svsk->sk_bvec, count, rqstp->rq_res.len);
@@ -773,6 +777,7 @@ static int svc_udp_sendto(struct svc_rqs err =sock_sendmsg (svsk->sk_sock, &msg); } +out_trace:trace_svcsock_udp_send (xprt, err);mutex_unlock (&xprt->xpt_mutex);
@@ -1251,7 +1256,7 @@ static int svc_tcp_sendmsg(struct svc_sostruct msghdr msg = { .msg_flags =MSG_SPLICE_PAGES , }; -unsigned int count; +int count;void *buf;int ret;
@@ -1267,10 +1272,15 @@ static int svc_tcp_sendmsg(struct svc_so count =xdr_buf_to_bvec (svsk->sk_bvec +1 , rqstp->rq_maxpages, &rqstp->rq_res); +if (count <0 ) { + ret = count; + goto out; + }iov_iter_bvec (&msg.msg_iter,ITER_SOURCE , svsk->sk_bvec,1 + count,sizeof (marker) + rqstp->rq_res.len); ret =sock_sendmsg (svsk->sk_sock, &msg); +out:page_frag_free (buf);return ret; }
net/sunrpc/xdr.c +6 -5
@@ -139,13 +139,14 @@ xdr_free_bvec(struct xdr_buf *buf)/** * xdr_buf_to_bvec - Copy components of an xdr_buf into a bio_vec array * @bvec: bio_vec array to populate -* @bvec_size: element count of @bio_vec +* @bvec_size: element count of @bvec * @xdr: xdr_buf to be copied * -* Returns the number of entries consumed in @bvec. +* Returns the number of entries consumed in @bvec on success, or +* -ESERVERFAULT when @xdr does not fit within @bvec_size entries. */ -unsigned int xdr_buf_to_bvec (struct bio_vec *bvec,unsigned int bvec_size, -const struct xdr_buf *xdr) +int xdr_buf_to_bvec (struct bio_vec *bvec,unsigned int bvec_size, +const struct xdr_buf *xdr) {const struct kvec *head = xdr->head;const struct kvec *tail = xdr->tail;
@@ -187,7 +188,7 @@ unsigned int xdr_buf_to_bvec(struct bio_ bvec_overflow:pr_warn_once ("%s: bio_vec array overflow\n" , __func__); -return count; +return -ESERVERFAULT ; }EXPORT_SYMBOL_GPL (xdr_buf_to_bvec);
Greg Kroah-Hartman
maintainerPATCH 629/675 cxl/pci: Remove unnecessary CXL Endpoint handling helper functions
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Terry Bowman <[email protected]>
[ Upstream commit ca3d1a53e62093d17436abd447463da9c0f4e56b ]
The CXL driver's cxl_handle_endpoint_cor_ras()/cxl_handle_endpoint_ras() are unnecessary helper functions used only for Endpoints. Remove these functions as they are not common for all CXL devices and do not provide value for EP handling.
Rename __cxl_handle_ras to cxl_handle_ras() and __cxl_handle_cor_ras() to cxl_handle_cor_ras().
Stable-dep-of: c268f949e219 ("cxl: Fix CXL_HEADERLOG_SIZE to match RAS Capability size")
--- drivers/cxl/core/pci.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-)
drivers/cxl/core/pci.c +8 -18
@@ -711,8 +711,8 @@ err: }EXPORT_SYMBOL_NS_GPL (read_cdat_data,"CXL" ); -static void __cxl_handle_cor_ras (struct cxl_dev_state *cxlds, -void __iomem *ras_base) +static void cxl_handle_cor_ras (struct cxl_dev_state *cxlds, +void __iomem *ras_base) {void __iomem *addr;u32 status;
@@ -728,11 +728,6 @@ static void __cxl_handle_cor_ras(struct } } -static void cxl_handle_endpoint_cor_ras (struct cxl_dev_state *cxlds) -{ -return __cxl_handle_cor_ras (cxlds, cxlds->regs.ras); -} -/* CXL spec rev3.0 8.2.4.16.1 */ static void header_log_copy (void __iomem *ras_base,u32 *log) {
@@ -754,8 +749,8 @@ static void header_log_copy(void __iomem* Log the state of the RAS status registers and prepare them to log the * next error status. Return 1 if reset needed. */ -static bool __cxl_handle_ras (struct cxl_dev_state *cxlds, -void __iomem *ras_base) +static bool cxl_handle_ras (struct cxl_dev_state *cxlds, +void __iomem *ras_base) {u32 hl[CXL_HEADERLOG_SIZE_U32 ];void __iomem *addr;
@@ -788,11 +783,6 @@ static bool __cxl_handle_ras(struct cxl_return true; } -static bool cxl_handle_endpoint_ras (struct cxl_dev_state *cxlds) -{ -return __cxl_handle_ras (cxlds, cxlds->regs.ras); -} -#ifdef CONFIG_PCIEAER_CXL static void cxl_dport_map_rch_aer (struct cxl_dport *dport)
@@ -871,13 +861,13 @@ EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_static void cxl_handle_rdport_cor_ras (struct cxl_dev_state *cxlds,struct cxl_dport *dport) { -return __cxl_handle_cor_ras (cxlds, dport->regs.ras); +return cxl_handle_cor_ras (cxlds, dport->regs.ras); }static bool cxl_handle_rdport_ras (struct cxl_dev_state *cxlds,struct cxl_dport *dport) { -return __cxl_handle_ras (cxlds, dport->regs.ras); +return cxl_handle_ras (cxlds, dport->regs.ras); }/*
@@ -974,7 +964,7 @@ void cxl_cor_error_detected(struct pci_dif (cxlds->rcd)cxl_handle_rdport_errors (cxlds); -cxl_handle_endpoint_cor_ras (cxlds); +cxl_handle_cor_ras (cxlds, cxlds->regs.ras); } }EXPORT_SYMBOL_NS_GPL (cxl_cor_error_detected,"CXL" );
@@ -1003,7 +993,7 @@ pci_ers_result_t cxl_error_detected(stru* chance the situation is recoverable dump the status of the RAS * capability registers and bounce the active state of the memdev. */ - ue =cxl_handle_endpoint_ras (cxlds); + ue =cxl_handle_ras (cxlds, cxlds->regs.ras); }
Greg Kroah-Hartman
maintainerPATCH 630/675 cxl/pci: Remove unnecessary CXL RCH handling helper functions
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Terry Bowman <[email protected]>
[ Upstream commit eb78ef4d6f0e51243c1ee117f801dbc503e886ab ]
cxl_handle_rdport_cor_ras() and cxl_handle_rdport_ras() are specific to Restricted CXL Host (RCH) handling. Improve readability and maintainability by replacing these and instead using the common cxl_handle_cor_ras() and cxl_handle_ras() functions.
Stable-dep-of: c268f949e219 ("cxl: Fix CXL_HEADERLOG_SIZE to match RAS Capability size")
--- drivers/cxl/core/pci.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-)
drivers/cxl/core/pci.c +2 -14
@@ -858,18 +858,6 @@ void cxl_dport_init_ras_reporting(struct }EXPORT_SYMBOL_NS_GPL (cxl_dport_init_ras_reporting,"CXL" ); -static void cxl_handle_rdport_cor_ras (struct cxl_dev_state *cxlds, -struct cxl_dport *dport) -{ -return cxl_handle_cor_ras (cxlds, dport->regs.ras); -} - -static bool cxl_handle_rdport_ras (struct cxl_dev_state *cxlds, -struct cxl_dport *dport) -{ -return cxl_handle_ras (cxlds, dport->regs.ras); -} -/* * Copy the AER capability registers using 32 bit read accesses. * This is necessary because RCRB AER capability is MMIO mapped. Clear the
@@ -939,9 +927,9 @@ static void cxl_handle_rdport_errors(strpci_print_aer (pdev, severity, &aer_regs);if (severity ==AER_CORRECTABLE ) -cxl_handle_rdport_cor_ras (cxlds, dport); +cxl_handle_cor_ras (cxlds, dport->regs.ras);else - cxl_handle_rdport_ras(cxlds, dport); + cxl_handle_ras(cxlds, dport->regs.ras); }#else
Greg Kroah-Hartman
maintainerPATCH 631/675 cxl/pci: Remove CXL VH handling in CONFIG_PCIEAER_CXL conditional blocks from core/pci.c
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dave Jiang <[email protected]>
[ Upstream commit 7ff8b1d60881c5f97b5ae426e14d2822917d3b69 ]
Create new config CONFIG_CXL_RAS and put all CXL RAS items behind the config. The config will depend on CPER and PCIE AER to build. Move the related VH RAS code from core/pci.c to core/ras.c.
Restricted CXL host (RCH) RAS functions will be moved in a future patch.
Stable-dep-of: c268f949e219 ("cxl: Fix CXL_HEADERLOG_SIZE to match RAS Capability size")
--- drivers/cxl/Kconfig | 4 drivers/cxl/core/Makefile | 2 drivers/cxl/core/core.h | 31 +++++++ drivers/cxl/core/pci.c | 189 ---------------------------------------------- drivers/cxl/core/ras.c | 176 ++++++++++++++++++++++++++++++++++++++++++ drivers/cxl/cxl.h | 8 - drivers/cxl/cxlpci.h | 16 +++ tools/testing/cxl/Kbuild | 2 8 files changed, 233 insertions(+), 195 deletions(-)
drivers/cxl/Kconfig +4 -0
@@ -234,4 +234,8 @@ config CXL_MCE def_bool y depends on X86_MCE && MEMORY_FAILURE +config CXL_RAS + def_bool y + depends on ACPI_APEI_GHES && PCIEAER && CXL_PCI + endif
drivers/cxl/core/Makefile +1 -1
@@ -14,9 +14,9 @@ cxl_core-y += pci.o cxl_core-y += hdm.o cxl_core-y += pmu.o cxl_core-y += cdat.o -cxl_core-y += ras.o cxl_core-$(CONFIG_TRACING) += trace.o cxl_core-$(CONFIG_CXL_REGION) += region.o cxl_core-$(CONFIG_CXL_MCE) += mce.o cxl_core-$(CONFIG_CXL_FEATURES) += features.o cxl_core-$(CONFIG_CXL_EDAC_MEM_FEATURES) += edac.o +cxl_core-$(CONFIG_CXL_RAS) += ras.o
drivers/cxl/core/core.h +31 -0
@@ -144,8 +144,39 @@ int cxl_pci_get_bandwidth(struct pci_devint cxl_port_get_switch_dport_bandwidth (struct cxl_port *port,struct access_coordinate *c); +#ifdef CONFIG_CXL_RAS int cxl_ras_init (void );void cxl_ras_exit (void ); +bool cxl_handle_ras (struct cxl_dev_state *cxlds,void __iomem *ras_base); +void cxl_handle_cor_ras (struct cxl_dev_state *cxlds,void __iomem *ras_base); +#else +static inline int cxl_ras_init (void ) +{ +return 0 ; +} + +static inline void cxl_ras_exit (void ) +{ +} + +static inline bool cxl_handle_ras (struct cxl_dev_state *cxlds,void __iomem *ras_base) +{ +return false; +} +static inline void cxl_handle_cor_ras (struct cxl_dev_state *cxlds,void __iomem *ras_base) { } +#endif /* CONFIG_CXL_RAS */ + +/* Restricted CXL Host specific RAS functions */ +#ifdef CONFIG_CXL_RAS +void cxl_dport_map_rch_aer (struct cxl_dport *dport); +void cxl_disable_rch_root_ints (struct cxl_dport *dport); +void cxl_handle_rdport_errors (struct cxl_dev_state *cxlds); +#else +static inline void cxl_dport_map_rch_aer (struct cxl_dport *dport) { } +static inline void cxl_disable_rch_root_ints (struct cxl_dport *dport) { } +static inline void cxl_handle_rdport_errors (struct cxl_dev_state *cxlds) { } +#endif /* CONFIG_CXL_RAS */ +int cxl_gpf_port_setup (struct cxl_dport *dport);struct cxl_hdm ;
drivers/cxl/core/pci.c +4 -185
221 lines not on this page · raw message
drivers/cxl/core/ras.c +176 -0
185 lines not on this page · raw message
drivers/cxl/cxl.h +0 -8
@@ -781,14 +781,6 @@ struct cxl_dport *devm_cxl_add_rch_dport struct device *dport_dev, int port_id, resource_size_t rcrb); -#ifdef CONFIG_PCIEAER_CXL -void cxl_setup_parent_dport (struct device *host,struct cxl_dport *dport); -void cxl_dport_init_ras_reporting (struct cxl_dport *dport,struct device *host); -#else -static inline void cxl_dport_init_ras_reporting (struct cxl_dport *dport, -struct device *host) { } -#endif -struct cxl_decoder *to_cxl_decoder (struct device *dev);struct cxl_root_decoder *to_cxl_root_decoder (struct device *dev);struct cxl_switch_decoder *to_cxl_switch_decoder (struct device *dev);
drivers/cxl/cxlpci.h +16 -0
@@ -130,7 +130,23 @@ static inline bool cxl_pci_flit_256(struint devm_cxl_port_enumerate_dports (struct cxl_port *port);struct cxl_dev_state ;void read_cdat_data (struct cxl_port *port); + +#ifdef CONFIG_CXL_RAS void cxl_cor_error_detected (struct pci_dev *pdev);pci_ers_result_t cxl_error_detected (struct pci_dev *pdev,pci_channel_state_t state); +void cxl_dport_init_ras_reporting (struct cxl_dport *dport,struct device *host); +#else +static inline void cxl_cor_error_detected (struct pci_dev *pdev) { } + +static inline pci_ers_result_t cxl_error_detected (struct pci_dev *pdev, +pci_channel_state_t state) +{ +return PCI_ERS_RESULT_NONE ; +} + +static inline void cxl_dport_init_ras_reporting (struct cxl_dport *dport, +struct device *host) { } +#endif +#endif /* __CXL_PCI_H__ */
tools/testing/cxl/Kbuild +1 -1
@@ -58,12 +58,12 @@ cxl_core-y += $(CXL_CORE_SRC)/pci.o cxl_core-y += $(CXL_CORE_SRC)/hdm.o cxl_core-y += $(CXL_CORE_SRC)/pmu.o cxl_core-y += $(CXL_CORE_SRC)/cdat.o -cxl_core-y += $(CXL_CORE_SRC)/ras.o cxl_core-$(CONFIG_TRACING) += $(CXL_CORE_SRC)/trace.o cxl_core-$(CONFIG_CXL_REGION) += $(CXL_CORE_SRC)/region.o cxl_core-$(CONFIG_CXL_MCE) += $(CXL_CORE_SRC)/mce.o cxl_core-$(CONFIG_CXL_FEATURES) += $(CXL_CORE_SRC)/features.o cxl_core-$(CONFIG_CXL_EDAC_MEM_FEATURES) += $(CXL_CORE_SRC)/edac.o +cxl_core-$(CONFIG_CXL_RAS) += $(CXL_CORE_SRC)/ras.o cxl_core-y += config_check.o cxl_core-y += cxl_core_test.o cxl_core-y += cxl_core_exports.o
Greg Kroah-Hartman
maintainerPATCH 632/675 cxl: Fix CXL_HEADERLOG_SIZE to match RAS Capability size
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Terry Bowman <[email protected]>
[ Upstream commit c268f949e219f9e179558e836f457f6c5fbec416 ]
The CXL r4.0 8.2.4.17.7 RAS Capability Structure has total length 0x58 bytes (CXL_RAS_CAPABILITY_LENGTH); the Header Log occupies the trailing 64 bytes at offset 0x18. CXL_HEADERLOG_SIZE was defined as SZ_512, eight times the actual on-device size.
header_log_copy() reads CXL_HEADERLOG_SIZE_U32 (128) dwords from the RAS capability iomap, overrunning the 88-byte mapping by 448 bytes. The cxl_aer_uncorrectable_error trace event memcpy()s CXL_HEADERLOG_SIZE
(512) bytes from its source. For the CPER caller the source is struct cxl_ras_capability_regs::header_log[16] (64 bytes) embedded in a stack-local cxl_cper_prot_err_work_data, so the memcpy reads 448 bytes of kernel stack into the trace event ring buffer where userspace can read it via tracefs.
Set CXL_HEADERLOG_SIZE to 64 and derive CXL_HEADERLOG_SIZE_U32 from it, bringing all iomap readers into agreement on 16 dwords. Userspace tools such as rasdaemon have grown a dependency on the buggy 512-byte (128 u32) header_log layout in the cxl_aer_uncorrectable_error trace event. Add CXL_HEADERLOG_TRACE_SIZE_U32 = 128 and use it for the trace event __array and its memcpy to preserve that ABI. Both callers now pass a zero-filled u32[CXL_HEADERLOG_TRACE_SIZE_U32] staging buffer with only the first CXL_HEADERLOG_SIZE_U32 (16) entries populated from hardware; the remaining 112 u32s are zero-padded, keeping the 512-byte trace ring buffer layout intact.
[ dj: Replaced 64 with SZ_64 per RichardC ]
--- drivers/cxl/core/ras.c | 27 ++++++++++++++++++++------- drivers/cxl/core/trace.h | 24 ++++++++++++++++-------- drivers/cxl/cxl.h | 14 ++++++++++++-- 3 files changed, 48 insertions(+), 17 deletions(-)
drivers/cxl/core/ras.c +20 -7
@@ -8,6 +8,10 @@#include <cxlpci.h> #include "trace.h" +/* Check that UCE header definition is maintained to keep ABI intact */ +static_assert (CXL_HEADERLOG_TRACE_SIZE_U32 ==128 , +"rasdaemon ABI requires exactly 128 u32s" ); +static void cxl_cper_trace_corr_port_prot_err (struct pci_dev *pdev,struct cxl_ras_capability_regs ras_cap) {
@@ -19,6 +23,7 @@ static void cxl_cper_trace_corr_port_prostatic void cxl_cper_trace_uncorr_port_prot_err (struct pci_dev *pdev,struct cxl_ras_capability_regs ras_cap) { +u32 hl[CXL_HEADERLOG_TRACE_SIZE_U32 ] = {};u32 status = ras_cap.uncor_status & ~ras_cap.uncor_mask;u32 fe;
@@ -28,8 +33,8 @@ static void cxl_cper_trace_uncorr_port_pelse fe = status; -trace_cxl_port_aer_uncorrectable_error (&pdev->dev, status, fe, - ras_cap.header_log); +memcpy (hl, ras_cap.header_log,CXL_HEADERLOG_SIZE ); +trace_cxl_port_aer_uncorrectable_error (&pdev->dev, status, fe, hl); } static void cxl_cper_trace_corr_prot_err(struct cxl_memdev *cxlmd,
@@ -44,6 +49,7 @@ static void cxl_cper_trace_uncorr_prot_err(struct cxl_memdev *cxlmd, struct cxl_ras_capability_regs ras_cap) { + u32 hl[CXL_HEADERLOG_TRACE_SIZE_U32] = {};u32 status = ras_cap.uncor_status & ~ras_cap.uncor_mask;u32 fe;
@@ -53,8 +59,15 @@ cxl_cper_trace_uncorr_prot_err(struct cxelse fe = status; -trace_cxl_aer_uncorrectable_error (cxlmd, status, fe, - ras_cap.header_log); +/* +* ras_cap.header_log[] holds CXL_HEADERLOG_SIZE_U32 (16) hardware +* dwords. Copy them into the front of a zero-filled +* CXL_HEADERLOG_TRACE_SIZE_U32 (128) u32 staging buffer so the trace +* event memcpy sees a full 512-byte source and the userspace ABI +* (rasdaemon) is preserved. +*/ +memcpy (hl, ras_cap.header_log,CXL_HEADERLOG_SIZE ); +trace_cxl_aer_uncorrectable_error (cxlmd, status, fe, hl); }static int match_memdev_by_parent (struct device *dev,const void *uport)
@@ -181,12 +194,12 @@ static void header_log_copy(void __iomem {void __iomem *addr;u32 *log_addr; -int i, log_u32_size =CXL_HEADERLOG_SIZE /sizeof (u32); +int i; addr = ras_base +CXL_RAS_HEADER_LOG_OFFSET ; log_addr = log; -for (i =0 ; i < log_u32_size; i++) { +for (i =0 ; i <CXL_HEADERLOG_SIZE_U32 ; i++) { *log_addr =readl (addr); log_addr++; addr +=sizeof (u32);
@@ -199,7 +212,7 @@ static void header_log_copy(void __iomem*/ bool cxl_handle_ras (struct cxl_dev_state *cxlds,void __iomem *ras_base) { -u32 hl[CXL_HEADERLOG_SIZE_U32 ]; +u32 hl[CXL_HEADERLOG_TRACE_SIZE_U32 ] = {};void __iomem *addr;u32 status;u32 fe;
drivers/cxl/core/trace.h +16 -8
@@ -56,7 +56,7 @@ TRACE_EVENT(cxl_port_aer_uncorrectable_e __string(host, dev_name(dev->parent)) __field(u32, status) __field(u32, first_error) -__array (u32, header_log,CXL_HEADERLOG_SIZE_U32 ) +__array (u32, header_log,CXL_HEADERLOG_TRACE_SIZE_U32 ) ),TP_fast_assign ( __assign_str(device);
@@ -64,10 +64,14 @@ TRACE_EVENT(cxl_port_aer_uncorrectable_e __entry->status = status; __entry->first_error = fe;/* -* Embed the 512B headerlog data for user app retrieval and -* parsing, but no need to print this in the trace buffer. +* Embed headerlog data for user app retrieval and parsing, +* but no need to print in the trace buffer. Only +* CXL_HEADERLOG_SIZE_U32 (16) dwords are hardware data; +* the remaining entries preserve the 512-byte ABI layout +* rasdaemon depends on and are zero-filled by the caller. */ -memcpy (__entry->header_log, hl,CXL_HEADERLOG_SIZE ); +memcpy (__entry->header_log, hl, +CXL_HEADERLOG_TRACE_SIZE_U32 *sizeof (u32)); ), TP_printk("device=%s host=%s status: '%s' first_error: '%s'", __get_str(device), __get_str(host),
@@ -85,7 +89,7 @@ TRACE_EVENT(cxl_aer_uncorrectable_error, __field(u64, serial) __field(u32, status) __field(u32, first_error) -__array (u32, header_log,CXL_HEADERLOG_SIZE_U32 ) +__array (u32, header_log,CXL_HEADERLOG_TRACE_SIZE_U32 ) ),TP_fast_assign ( __assign_str(memdev);
@@ -94,10 +98,14 @@ TRACE_EVENT(cxl_aer_uncorrectable_error, __entry->status = status; __entry->first_error = fe;/* -* Embed the 512B headerlog data for user app retrieval and -* parsing, but no need to print this in the trace buffer. +* Embed headerlog data for user app retrieval and parsing, +* but no need to print in the trace buffer. Only +* CXL_HEADERLOG_SIZE_U32 (16) dwords are hardware data; +* the remaining entries preserve the 512-byte ABI layout +* rasdaemon depends on and are zero-filled by the caller. */ -memcpy (__entry->header_log, hl,CXL_HEADERLOG_SIZE ); +memcpy (__entry->header_log, hl, +CXL_HEADERLOG_TRACE_SIZE_U32 *sizeof (u32)); ), TP_printk("memdev=%s host=%s serial=%lld: status: '%s' first_error: '%s'", __get_str(memdev), __get_str(host), __entry->serial,
drivers/cxl/cxl.h +12 -2
@@ -148,8 +148,18 @@ static inline int ways_to_eiw(unsigned i#define CXL_RAS_CAP_CONTROL_FE_MASK GENMASK(5, 0)#define CXL_RAS_HEADER_LOG_OFFSET 0x18#define CXL_RAS_CAPABILITY_LENGTH 0x58 -#define CXL_HEADERLOG_SIZE SZ_512 -#define CXL_HEADERLOG_SIZE_U32 SZ_512 / sizeof(u32) +#define CXL_HEADERLOG_SIZE SZ_64 +#define CXL_HEADERLOG_SIZE_U32 (CXL_HEADERLOG_SIZE / sizeof(u32)) + +/* +* The RAS UCE trace event header array was originally sized at SZ_512/sizeof(u32) +* = 128 u32s due to a bug. Userspace tools (rasdaemon) have grown a dependency +* on that 512-byte layout. Keep the trace array at 128 u32s to preserve the +* ABI; only CXL_HEADERLOG_SIZE_U32 (16) dwords are valid hardware data, the +* remainder are zero-filled. +*/ +#define CXL_HEADERLOG_TRACE_SIZE SZ_512 +#define CXL_HEADERLOG_TRACE_SIZE_U32 (CXL_HEADERLOG_TRACE_SIZE / sizeof(u32))/* CXL 2.0 8.2.8.1 Device Capabilities Array Register */ #define CXLDEV_CAP_ARRAY_OFFSET 0x0
Greg Kroah-Hartman
maintainerPATCH 633/675 remoteproc: xlnx: Check remote core state
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tanmay Shah <[email protected]>
[ Upstream commit a48df51d23138388900995add2854cda4aa68e55 ]
The remote state is set to RPROC_DETACHED if the resource table is found in the memory. However, this can be wrong if the remote is not started, but firmware is still loaded in the memory. Use PM_GET_NODE_STATUS call to the firmware to request the state of the RPU node. If the RPU is actually out of reset and running, only then move the remote state to RPROC_DETACHED, otherwise keep the remote state to RPROC_OFFLINE.
--- drivers/firmware/xilinx/zynqmp.c | 1 drivers/remoteproc/xlnx_r5_remoteproc.c | 50 +++++++++++++++++++++++++------- include/linux/firmware/xlnx-zynqmp.h | 13 ++++++++ 3 files changed, 54 insertions(+), 10 deletions(-)
drivers/firmware/xilinx/zynqmp.c +1 -0
@@ -461,6 +461,7 @@ int zynqmp_pm_invoke_fn(u32 pm_api_id, ureturn do_fw_call (ret_payload,8 , smc_arg[0 ], smc_arg[1 ], smc_arg[2 ], smc_arg[3 ], smc_arg[4 ], smc_arg[5 ], smc_arg[6 ], smc_arg[7 ]); } +EXPORT_SYMBOL_GPL (zynqmp_pm_invoke_fn);static u32 pm_api_version;static u32 pm_tz_version;
drivers/remoteproc/xlnx_r5_remoteproc.c +40 -10
68 lines not on this page · raw message
include/linux/firmware/xlnx-zynqmp.h +13 -0
@@ -164,6 +164,7 @@ enum pm_api_cb_id {enum pm_api_id {PM_API_FEATURES =0 ,PM_GET_API_VERSION =1 , +PM_GET_NODE_STATUS =3 ,PM_REGISTER_NOTIFIER =5 ,PM_FORCE_POWERDOWN =8 ,PM_REQUEST_WAKEUP =10 ,
@@ -545,6 +546,18 @@ enum pm_gem_config_type { };/** +* enum pm_node_status - Device node status provided by xilpm fw +* @PM_NODE_UNUSED: Device is not used +* @PM_NODE_RUNNING: Device is power-on and out of reset +* @PM_NODE_HALT: Device is power-on but in the reset state +*/ +enum pm_node_status { +PM_NODE_UNUSED =0 , +PM_NODE_RUNNING =1 , +PM_NODE_HALT =12 , +}; + +/** * struct zynqmp_pm_query_data - PM query data * @qid: query ID * @arg1: Argument 1 of query data