6.18.53-rc1 review
Subsystems (6)
Greg Kroah-Hartman
maintainerPATCH 848/1250 netfilter: nfnetlink_log: cope with concurrent instance destruction
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 387d744fa7e499d2c3748a4e60e02ebb24e7fb16 ]
Instances are refcounted. However, only memory release happens on the 1 -> 0 transition; the unlink from hashes can occur with any refcount.
Uncooperative userspace can force a situation where a queue is pending for destruction from netlink event while a different socket with same portid processes an UNBIND request.
With right timing, this will unhash the instance again:
Oops: general protection fault, [..] Call Trace: <TASK> nfulnl_recv_config+0x31a/0xd50 nfnetlink_rcv_msg+0x7c2/0xeb0
--- net/netfilter/nfnetlink_log.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
net/netfilter/nfnetlink_log.c +9 -4
@@ -228,13 +228,18 @@ static void __nfulnl_flush(struct nfulnl_instance *inst);static void __instance_destroy (struct nfulnl_instance *inst) { +spin_lock (&inst->lock); +if (inst->copy_mode ==NFULNL_COPY_DISABLED ) { +/* attempt to UNBIND a queue already pending +* destruction via netlink close event. Ignore. +*/ +spin_unlock (&inst->lock); +return ; + } +/* first pull it out of the global list */ hlist_del_rcu (&inst->hlist); -/* then flush all pending packets from skb */ - -spin_lock (&inst->lock); -/* lockless readers wont be able to use us */ inst->copy_mode =NFULNL_COPY_DISABLED ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 849/1250 netfilter: ip6_tables: set F_PROTO when proto value is nonzero
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 da4afc5a956d407443988e97a4d4ca14c2e999c7 ]
The ip6tables traverser doesn't search the extension header chain unless userspace did set the IP6T_F_PROTO flag.
This also means that userspace that sets the e->ipv6.proto flag can bypass the protocol check for the rule by not setting this flag.
That in turn means that all ip6_tables modules and targets that want to reject rules without '-p' flag MUST also check for that flag.
Not all do, likely because they got copied from iptables which lacks this flag (no extension headers).
Instead of fixing up all the relevant targets, emulate ip6tables behaviour in the kernel (like nft_compat.c) and set the flag if the protocol is set.
--- net/ipv6/netfilter/ip6_tables.c | 5 +++++ 1 file changed, 5 insertions(+)
net/ipv6/netfilter/ip6_tables.c +5 -0
@@ -647,6 +647,11 @@ check_entry_size_and_hooks(struct ip6t_entry *e,/* Clear counters and comefrom */ e->counters = ((struct xt_counters ) {0 ,0 }); e->comefrom =0 ; + +/* set F_PROTO, else ip6_packet_match won't do the right thing. */ +if (e->ipv6.proto) + e->ipv6.flags |=IP6T_F_PROTO ; +return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 850/1250 ASoC: mt6351: Publish the OF module alias
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: hpp.iscas <[email protected]>
[ Upstream commit 9c3882ec10399c14c59b7e4599d33c4395367c37 ]
The MT6351 codec platform driver uses mt6351_of_match to bind devices with compatible mediatek,mt6351-sound. The codec can be a separate module, but the OF table is not exported to module alias metadata.
Publish the existing table without changing codec matching, register access or the machine-driver configuration.
--- sound/soc/codecs/mt6351.c | 1 + 1 file changed, 1 insertion(+)
sound/soc/codecs/mt6351.c +1 -0
@@ -1479,6 +1479,7 @@ static const struct of_device_id mt6351_of_match[] = { {.compatible = "mediatek,mt6351-sound",}, {} }; +MODULE_DEVICE_TABLE (of, mt6351_of_match);static struct platform_driver mt6351_codec_driver = { .driver = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 851/1250 irqchip/gic-v5: Preserve ICC_CR0_EL1 state
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sascha Bischoff <[email protected]>
[ Upstream commit 1017911fcc03584b6854b1b8f0aafeb25f5a8d25 ]
In addition to EN, ICC_CR0_EL1 contains other fields, such as LINK and LINK_IDLE. The driver only needs to modify EN, and must preserve the values of all other fields when enabling or disabling the CPU interface.
Define the missing LINK and LINK_IDLE fields, and use read-modify-write accesses to update EN without affecting the rest of ICC_CR0_EL1.
--- arch/arm64/tools/sysreg | 4 +++- drivers/irqchip/irq-gic-v5.c | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-)
arch/arm64/tools/sysreg +3 -1
@@ -3672,7 +3672,9 @@ Sysreg ICC_CR0_EL1 3 1 12 0 1 Res0 63:39 Field 38 PID Field 37:32 IPPT -Res0 31:1 +Res0 31:3 +Field 2 LINK_IDLE +Field 1 LINK Field 0 EN EndSysreg
drivers/irqchip/irq-gic-v5.c +4 -2
@@ -929,7 +929,8 @@ static void gicv5_cpu_disable_interrupts(void) {u64 cr0; - cr0 =FIELD_PREP (ICC_CR0_EL1_EN ,0 ); + cr0 =read_sysreg_s (SYS_ICC_CR0_EL1 ); + cr0 &= ~ICC_CR0_EL1_EN_MASK ;write_sysreg_s (cr0,SYS_ICC_CR0_EL1 );isb (); }
@@ -946,7 +947,8 @@ static void gicv5_cpu_enable_interrupts(void) pcr =FIELD_PREP (ICC_PCR_EL1_PRIORITY ,GICV5_IRQ_PRI_MI );write_sysreg_s (pcr,SYS_ICC_PCR_EL1 ); - cr0 =FIELD_PREP (ICC_CR0_EL1_EN ,1 ); + cr0 =read_sysreg_s (SYS_ICC_CR0_EL1 ); + cr0 |=ICC_CR0_EL1_EN_MASK ;write_sysreg_s (cr0,SYS_ICC_CR0_EL1 ); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 852/1250 virtio: fix use-after-free in unregister_virtio_device()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit 3f9a0fceb730f5107d52421ead5568eae25a0049 ]
device_unregister() is device_del() plus put_device(). When the caller holds no extra reference, that drops the last one and runs the release callback, which for several transports frees the memory the embedded struct virtio_device sits in. unregister_virtio_device() then calls virtio_debug_device_exit(), which reads dev->debugfs_dir out of the freed object.
Affected transports are the ones whose release callback frees and whose remove path takes no reference: virtio_mmio, virtio_vdpa, virtio_uml, mlxbf-tmfifo and virtio_ccw. virtio_pci is unaffected because virtio_pci_remove() brackets the call with get_device() and put_device().
Remove the debugfs entries before the device can go away. They are only accessed through the protected debugfs interface, so debugfs_remove_recursive() waits for in-progress file operations before returning. Tearing them down while the device is still alive is therefore safe.
Reproduced on User-Mode Linux with CONFIG_KASAN and CONFIG_VIRTIO_DEBUG by unbinding a virtio-uml device:
BUG: KASAN: slab-use-after-free in virtio_debug_device_exit+0x36/0x4d Read of size 8 at addr 00000000616e0b10 by task init/1 __asan_report_load8_noabort virtio_debug_device_exit+0x36/0x4d unregister_virtio_device+0x48/0x75 virtio_uml_remove platform_remove device_release_driver_internal unbind_store Freed by task 1: kfree virtio_uml_release_dev device_release kobject_put put_device device_unregister
With this applied, the report is gone and unbind is clean.
Message-ID: <[email protected]>
--- drivers/virtio/virtio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/virtio/virtio.c +1 -1
@@ -595,8 +595,8 @@ void unregister_virtio_device(struct virtio_device *dev) {int index = dev->index;/* save for after device release */ -device_unregister (&dev->dev);virtio_debug_device_exit (dev); +device_unregister (&dev->dev);ida_free (&virtio_index_ida, index); }EXPORT_SYMBOL_GPL (unregister_virtio_device);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 853/1250 virtio_console: do not free control-out buffers on remove
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jia Jia <[email protected]>
[ Upstream commit 894f98e73983f37354214a89a3a7fd35bf9e3072 ]
__send_control_msg() publishes &portdev->cpkt as the control-out virtqueue cookie. remove_vqs() walks every virtqueue and passes leftover cookies to free_buf(), which treats them as struct port_buffer and reads sgpages.
If a control message is still on c_ovq when the device is unbound, free_buf() reads past the ports_device object.
KASAN reported slab-out-of-bounds in free_buf():
free_buf
remove_vqs
virtcons_remove
unbind_store
The object was the ports_device allocated in virtcons_probe().
Drain c_ovq without freeing. The packet lives in portdev and is released with it.
Message-ID: <[email protected]>
--- drivers/char/virtio_console.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-)
drivers/char/virtio_console.c +18 -3
@@ -1893,13 +1893,28 @@ static const struct file_operations portdev_fops = {static void remove_vqs (struct ports_device *portdev) {struct virtqueue *vq; +bool multiport =use_multiport (portdev);virtio_device_for_each_vq (portdev->vdev, vq) {struct port_buffer *buf; +unsigned int len; -flush_bufs (vq, true); -while ((buf =virtqueue_detach_unused_buf (vq))) -free_buf (buf, true); +/* +* c_ovq cookies are &portdev->cpkt, not port_buffer. +* Detach them but do not free_buf(). +*/ +if (multiport && vq == portdev->c_ovq) { +spin_lock (&portdev->c_ovq_lock); +while (virtqueue_get_buf (vq, &len)) + ; +while (virtqueue_detach_unused_buf (vq)) + ; +spin_unlock (&portdev->c_ovq_lock); + }else { +flush_bufs (vq, true); +while ((buf =virtqueue_detach_unused_buf (vq))) +free_buf (buf, true); + }cond_resched (); } portdev->vdev->config->del_vqs (portdev->vdev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 854/1250 vhost/vdpa: reject VRING_NUM larger than device max
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jia Jia <[email protected]>
[ Upstream commit ccb1dc7c527f8c925925cf92afc76ae590dac311 ]
vhost_vring_set_num() accepts any non-zero power-of-two queue size that fits in 16 bits. vhost-vdpa then passes that value to set_vq_num() without comparing it with get_vq_num_max().
A process with access to /dev/vhost-vdpa-* can therefore configure a queue larger than the device advertises. With vdpa_sim, the worker can walk descriptors beyond the mapped descriptor ring. KASAN reports a 16-byte out-of-bounds read, corresponding to one vring_desc, in the vringh IOTLB path:
BUG: KASAN: out-of-bounds in _copy_from_iter Read of size 16 copy_from_iotlb copydesc_iotlb vringh_getdesc_iotlb vdpasim_net_work
Cache get_vq_num_max() immediately after reset. Some backends derive it from writable queue-size state, so querying it after SET_NUM may return the current size instead of the device capability. Invalidate the cached value before reset so a failed reset leaves SET_NUM disabled.
For VHOST_SET_VRING_NUM, copy the complete vring state once and use the same index and size for validation, vq->num, and set_vq_num(). This ensures that validation and use operate on the same copied values.
Message-ID: <[email protected]>
--- drivers/vhost/vdpa.c | 44 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 7 deletions(-)
drivers/vhost/vdpa.c +37 -7
@@ -53,6 +53,7 @@ struct vhost_vdpa {struct cdev cdev;atomic_t opened;u32 nvqs; +u16 vq_num_max;int virtio_id;int minor;struct eventfd_ctx *config_ctx;
@@ -229,7 +230,9 @@ static void vhost_vdpa_unsetup_vq_irq(struct vhost_vdpa *v, u16 qid)static int _compat_vdpa_reset (struct vhost_vdpa *v) {struct vdpa_device *vdpa = v->vdpa; +const struct vdpa_config_ops *ops = vdpa->config;u32 flags =0 ; +int ret; v->suspended = false;
@@ -239,7 +242,14 @@ static int _compat_vdpa_reset(struct vhost_vdpa *v) VDPA_RESET_F_CLEAN_MAP :0 ; } -return vdpa_reset (vdpa, flags); + v->vq_num_max =0 ; + ret =vdpa_reset (vdpa, flags); +if (!ret) { +/* Some backends derive the max from mutable queue state. */ + v->vq_num_max = ops->get_vq_num_max (vdpa); + } + +return ret; }static int vhost_vdpa_reset (struct vhost_vdpa *v)
@@ -641,9 +651,15 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd,u32 idx;long r; - r =get_user (idx, (u32 __user *)argp); -if (r <0 ) -return r; +if (cmd ==VHOST_SET_VRING_NUM ) { +if (copy_from_user (&s, argp,sizeof (s))) +return -EFAULT ; + idx = s.index; + }else { + r =get_user (idx, (u32 __user *)argp); +if (r <0 ) +return r; + }if (idx >= v->nvqs)return -ENOBUFS ;
@@ -652,6 +668,23 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd, vq = &v->vqs[idx];switch (cmd) { +case VHOST_SET_VRING_NUM : +mutex_lock (&vq->mutex); +if (vq->private_data) { + r = -EBUSY ; + }else if (!s.num || s.num >0xffff || + s.num > v->vq_num_max || + (s.num & (s.num -1 ))) { + r = -EINVAL ; + }else { + vq->num = s.num; + r =0 ; + } +mutex_unlock (&vq->mutex); +if (r) +return r; + ops->set_vq_num (vdpa, idx, s.num); +return 0 ;case VHOST_VDPA_SET_VRING_ENABLE :if (copy_from_user (&s, argp,sizeof (s)))return -EFAULT ;
@@ -763,9 +796,6 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd, ops->set_vq_cb (vdpa, idx, &cb);break ; -case VHOST_SET_VRING_NUM : - ops->set_vq_num (vdpa, idx, vq->num); -break ; }return r;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 855/1250 vhost-vdpa: dont install the eventfd_ctx_fdget() error in config_ctx
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yu Zhang <[email protected]>
[ Upstream commit e74a9fa50749b9940b4fb13199652325e08d3c4a ]
vhost_vdpa_set_config_call() swaps the eventfd_ctx_fdget() return value into v->config_ctx before checking it, so on failure the field briefly holds an ERR_PTR:
ctx = fd == VHOST_FILE_UNBIND ? NULL : eventfd_ctx_fdget(fd);
swap(ctx, v->config_ctx);
if (!IS_ERR_OR_NULL(ctx))
eventfd_ctx_put(ctx);
if (IS_ERR(v->config_ctx)) {
long ret = PTR_ERR(v->config_ctx);
v->config_ctx = NULL;
return ret;
}Commit 0bde59c1723a ("vhost-vdpa: set v->config_ctx to NULL if eventfd_ctx_fdget() fails") added that clearing, and spelled out the invariant the rest of the file relies on: "we consider 'v->config_ctx' valid if it is not NULL". The window between the swap and the clearing still breaks it. vhost_vdpa_config_cb() only tests for NULL, so a config interrupt delivered inside the window hands the ERR_PTR to eventfd_signal().
Check the fd before installing it instead. That closes the window and matches how vhost_vring_ioctl() handles the same failure for the vq call fd.
It also stops a rejected fd from tearing down a config interrupt that was
working: until now the swap replaced the live context and put it, so after an EBADF the device silently stopped delivering config interrupts until userspace installed a new fd.
Message-ID: <[email protected]>
--- drivers/vhost/vdpa.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-)
drivers/vhost/vdpa.c +4 -8
@@ -539,18 +539,14 @@ static long vhost_vdpa_set_config_call(struct vhost_vdpa *v, u32 __user *argp)return -EFAULT ; ctx = fd ==VHOST_FILE_UNBIND ?NULL :eventfd_ctx_fdget (fd); +if (IS_ERR (ctx)) +return PTR_ERR (ctx); +swap (ctx, v->config_ctx); -if (!IS_ERR_OR_NULL (ctx)) +if (ctx)eventfd_ctx_put (ctx); -if (IS_ERR (v->config_ctx)) { -long ret =PTR_ERR (v->config_ctx); - - v->config_ctx =NULL ; -return ret; - } - v->vdpa->config->set_config_cb (v->vdpa, &cb);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 856/1250 vhost-vdpa: protect config_ctx from being freed under the config callback
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yu Zhang <[email protected]>
[ Upstream commit 62be4e3e5f5f947fbf765b914cebdc478f715d12 ]
vhost_vdpa_config_cb() loads v->config_ctx and signals it without taking a reference and without holding any lock:
struct eventfd_ctx *config_ctx = v->config_ctx; if (config_ctx) eventfd_signal(config_ctx);
VHOST_VDPA_SET_CONFIG_CALL replaces that field and drops what is normally the last reference to the old context:
swap(ctx, v->config_ctx); if (ctx) eventfd_ctx_put(ctx);
eventfd_ctx_put() drops the last kref and frees the context immediately, with no RCU grace period, so a callback that has already loaded the pointer goes on to dereference freed memory. The two sides share no
lock: the ioctl runs under vhost_dev.mutex, while the parent invokes the callback from its own interrupt or workqueue context.
This is not the reopen refcount underflow fixed by commit f6bbf0010ba0 ("vhost-vdpa: fix use-after-free of v->config_ctx"), which was about vhost_vdpa_config_put() leaving a stale pointer behind. Here the pointer is maintained correctly and it is the read side that is unprotected.
With VDUSE as the parent this is reachable from userspace with access to /dev/vduse (root by default). VDUSE_DEV_INJECT_CONFIG_IRQ queues dev->inject, and vduse_dev_irq_inject() runs the callback under VDUSE's own dev->irq_lock, which vhost does not hold. vduse_dev_reset() does flush_work(&dev->inject), but VHOST_VDPA_SET_CONFIG_CALL never goes through reset, so an inject already in flight is not waited for. A process that injects config interrupts on the VDUSE fd while another thread swaps the call fd on the vhost-vdpa fd hits it in seconds:
BUG: KASAN: slab-use-after-free in native_queued_spin_lock_slowpath Read of size 4 at addr ffff888107d21808 by task kworker/u17:1/2993 Workqueue: vduse-irq vduse_dev_irq_inject Call Trace: native_queued_spin_lock_slowpath+0x97/0x5b0 _raw_spin_lock_irqsave+0xd4/0xe0 eventfd_signal_mask+0x69/0x120 vhost_vdpa_config_cb+0x34/0x50 vduse_dev_irq_inject+0x46/0x60 process_one_work+0x468/0x950 Allocated by task 2992: do_eventfd+0x50/0x200 __x64_sys_eventfd2+0x2e/0x40 Freed by task 2992: eventfd_ctx_put+0xb9/0xc0 vhost_vdpa_unlocked_ioctl+0x116c/0x2190
Add a spinlock covering every access to config_ctx, so the callback either signals a context that is still alive or observes NULL, and the put happens only once no callback can reach the old value.
Clearing the parent's callback before the put would not be enough: of the in-tree set_config_cb() implementations only VDUSE takes a lock, the rest store the pointer unlocked, so that would not order against an in-flight invocation.
Message-ID: <[email protected]>
--- drivers/vhost/vdpa.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-)
drivers/vhost/vdpa.c +25 -7
@@ -57,6 +57,8 @@ struct vhost_vdpa {int virtio_id;int minor;struct eventfd_ctx *config_ctx; +/* Serialises vhost_vdpa_config_cb() against config_ctx being replaced. */ +spinlock_t config_lock;int in_batch;struct vdpa_iova_range range;u32 batch_asid;
@@ -188,10 +190,12 @@ static irqreturn_t vhost_vdpa_virtqueue_cb(void *private)static irqreturn_t vhost_vdpa_config_cb (void *private) {struct vhost_vdpa *v = private; -struct eventfd_ctx *config_ctx = v->config_ctx; +unsigned long flags; -if (config_ctx) -eventfd_signal (config_ctx); +spin_lock_irqsave (&v->config_lock, flags); +if (v->config_ctx) +eventfd_signal (v->config_ctx); +spin_unlock_irqrestore (&v->config_lock, flags);return IRQ_HANDLED ; }
@@ -521,15 +525,22 @@ static long vhost_vdpa_get_vring_num(struct vhost_vdpa *v, u16 __user *argp)static void vhost_vdpa_config_put (struct vhost_vdpa *v) { -if (v->config_ctx) { -eventfd_ctx_put (v->config_ctx); - v->config_ctx =NULL ; - } +struct eventfd_ctx *ctx; +unsigned long flags; + +spin_lock_irqsave (&v->config_lock, flags); + ctx = v->config_ctx; + v->config_ctx =NULL ; +spin_unlock_irqrestore (&v->config_lock, flags); + +if (ctx) +eventfd_ctx_put (ctx); }static long vhost_vdpa_set_config_call (struct vhost_vdpa *v,u32 __user *argp) {struct vdpa_callback cb; +unsigned long flags;int fd;struct eventfd_ctx *ctx;
@@ -542,8 +553,14 @@ static long vhost_vdpa_set_config_call(struct vhost_vdpa *v, u32 __user *argp)if (IS_ERR (ctx))return PTR_ERR (ctx); +spin_lock_irqsave (&v->config_lock, flags);swap (ctx, v->config_ctx); +spin_unlock_irqrestore (&v->config_lock, flags); +/* +* The callback can no longer reach the old context, so this is the +* last reference to it. +*/ if (ctx)eventfd_ctx_put (ctx);
@@ -1630,6 +1647,7 @@ static int vhost_vdpa_probe(struct vdpa_device *vdpa) }atomic_set (&v->opened,0 ); +spin_lock_init (&v->config_lock); v->minor = minor; v->vdpa = vdpa; v->nvqs = vdpa->nvqs;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 857/1250 vdpa_sim_blk: reject out-of-range sector starts
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linfeng Sun <[email protected]>
[ Upstream commit 0a8693f00c408d85f086ad85d29e7030bf1e2055 ]
vdpasim_blk_check_range() logs an invalid start sector but continues validating the request. The subsequent unsigned capacity subtraction can underflow and let an out-of-range buffer offset reach the data path.
The invalid offset is used by three request paths. VIRTIO_BLK_T_OUT copies guest data to blk->buffer + offset through vringh_iov_pull_iotlb(), causing an out-of-bounds write in _copy_from_iter() or memcpy(). VIRTIO_BLK_T_IN copies from blk->buffer + offset to the guest through vringh_iov_push_iotlb(), causing an out-of-bounds read in _copy_to_iter(). VIRTIO_BLK_T_WRITE_ZEROES passes blk->buffer + offset to memset(), causing an out-of-bounds write.
Reject starts at or beyond the capacity before the subtraction. Treat the capacity boundary as invalid because the IN and OUT paths round byte counts down to sectors for validation but later copy the original byte counts. A sub-sector request at the capacity boundary would otherwise still access past the end of the buffer.
I found this bug myself, though the patch was written with AI assistance.
Message-ID: <[email protected]>
--- drivers/vdpa/vdpa_sim/vdpa_sim_blk.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/vdpa/vdpa_sim/vdpa_sim_blk.c +2 -1
@@ -79,10 +79,11 @@ static void vdpasim_blk_buffer_unlock(struct vdpasim_blk *blk)static bool vdpasim_blk_check_range (struct vdpasim *vdpasim,u64 start_sector,u64 num_sectors,u64 max_sectors) { -if (start_sector >VDPASIM_BLK_CAPACITY ) { +if (start_sector >=VDPASIM_BLK_CAPACITY ) {dev_dbg (&vdpasim->vdpa.dev,"starting sector exceeds the capacity - start: 0x%llx capacity: 0x%x\n" , start_sector,VDPASIM_BLK_CAPACITY ); +return false; }if (num_sectors > max_sectors) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 858/1250 vdpa_sim_net: check TX pull result before RX copy
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linfeng Sun <[email protected]>
[ Upstream commit 0d195797a80b77f2ec56718cd26d3ee65d0093e8 ]
vringh_iov_pull_iotlb() returns a signed byte count. A failed TX pull is currently added to the unsigned byte counter and then passed as a size_t length to receive_filter() and vringh_iov_push_iotlb(). A negative error can therefore become a large length in the RX path.
Handle non-positive pull results before every length use. Count the TX error and complete the consumed TX descriptor with zero bytes.
I found this bug myself, though the patch was written with AI assistance.
Message-ID: <[email protected]>
--- drivers/vdpa/vdpa_sim/vdpa_sim_net.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/vdpa/vdpa_sim/vdpa_sim_net.c +6 -1
@@ -225,10 +225,15 @@ static void vdpasim_net_work(struct vdpasim *vdpasim)break ; } - ++tx_pkts; read =vringh_iov_pull_iotlb (&txq->vring, &txq->out_iov, net->buffer,PAGE_SIZE ); +if (read <=0 ) { + ++tx_errors; +vdpasim_net_complete (txq,0 ); +continue ; + } + ++tx_pkts; tx_bytes += read;if (!receive_filter (vdpasim, read)) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 859/1250 virtio-pci: return IRQ_HANDLED after non-zero ISR
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andrew Stellman <[email protected]>
[ Upstream commit 93fa09455fb1a9624b73d42ac1f83771f4818e80 ]
vp_interrupt() reads the ISR before dispatching config-change and vring handling. Reading the ISR also clears it, so once the read returns non-zero the interrupt was from this device and has already been consumed.
Currently vp_interrupt() returns the result of vp_vring_interrupt(). For a config-change interrupt with no vring work, that can return IRQ_NONE even though the ISR was non-zero and the interrupt was handled.
Call vp_vring_interrupt() for any queue work, but once the ISR is non-zero return IRQ_HANDLED.
Tested with QEMU virtio-blk-pci forced to INTx using vectors=0 and pci=nomsi. On an idle device, 200 config-change interrupts were generated using QMP block_resize.
Before this change, irq_handler_exit reported ret=unhandled and /proc/irq/11/spurious increased from 0 to 200 unhandled interrupts. After this change, irq_handler_exit reported ret=handled and the unhandled count remained at 0.
The issue was found during an LLM-assisted Quality Playbook review.
Message-ID: <[email protected]>
--- drivers/virtio/virtio_pci_common.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/virtio/virtio_pci_common.c +3 -1
@@ -120,7 +120,9 @@ static irqreturn_t vp_interrupt(int irq, void *opaque)if (isr &VIRTIO_PCI_ISR_CONFIG )vp_config_changed (irq, opaque); -return vp_vring_interrupt (irq, opaque); +vp_vring_interrupt (irq, opaque); + +return IRQ_HANDLED ; } static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 860/1250 virtio_input: reset device if input_register_device() fails
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiong Weimin <[email protected]>
[ Upstream commit 81489b32a21c9360f8750d1fb600155d27452e19 ]
Probe marks the device DRIVER_OK with virtio_device_ready() before calling input_register_device(). If registration fails, the error path cleared vi->ready and called del_vqs() while the device was still live, so the device could keep DMA to queues that were already torn down.
Match remove/freeze: call virtio_reset_device() on that path before tearing down the virtqueues.
Message-ID: <[email protected]>
--- drivers/virtio/virtio_input.c | 1 + 1 file changed, 1 insertion(+)
drivers/virtio/virtio_input.c +1 -0
@@ -328,6 +328,7 @@ static int virtinput_probe(struct virtio_device *vdev)spin_lock_irqsave (&vi->lock, flags); vi->ready = false;spin_unlock_irqrestore (&vi->lock, flags); +virtio_reset_device (vdev); err_mt_init_slots:input_free_device (vi->idev); err_input_alloc:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 861/1250 virtio_input: stop callbacks before unregistering input device
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit d7808b37da0a619cf1fa541c2384e783fecc2480 ]
virtinput_remove() unregisters the input device before resetting the virtio device. virtinput_recv_events() drops vi->lock around input_event(), so clearing vi->ready does not stop a callback that passed the entry check. It can still use vi->idev, requeue buffers and kick the queue.
Reset first, as virtinput_freeze() already does. With the preceding core change, reset waits for callbacks before input_unregister_device() can free vi->idev. Recheck vi->ready after taking the lock again: keep draining completed events so an input packet is not truncated, but stop requeueing buffers and kicking the queue.
With evdev attached, input_unregister_handle() currently waits for an RCU grace period, which also waits out IRQ callbacks. This masks the lifetime bug on PCI and MMIO, but does not protect sleepable callbacks on other transports.
Message-ID: <[email protected]>
--- drivers/virtio/virtio_input.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/virtio/virtio_input.c +6 -2
@@ -46,9 +46,12 @@ static void virtinput_recv_events(struct virtqueue *vq)le16_to_cpu (event->code), le32_to_cpu(event->value));spin_lock_irqsave (&vi->lock, flags); +if (!vi->ready) +continue ;virtinput_queue_evtbuf (vi, event); } -virtqueue_kick (vq); +if (vi->ready) +virtqueue_kick (vq); }spin_unlock_irqrestore (&vi->lock, flags); }
@@ -348,8 +351,9 @@ static void virtinput_remove(struct virtio_device *vdev) vi->ready = false;spin_unlock_irqrestore (&vi->lock, flags); -input_unregister_device (vi->idev); +/* Callbacks use vi->idev. */ virtio_reset_device (vdev); +input_unregister_device (vi->idev);while ((buf =virtqueue_detach_unused_buf (vi->sts)) !=NULL )kfree (buf); vdev->config->del_vqs (vdev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 862/1250 af_unix: Update last skb marker in manage_oob().
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <[email protected]>
[ Upstream commit 94fd4debd2e3a69cf93e766c8b328a810c228119 ]
Fahad Alharbi reported that blocking recv(MSG_PEEK) could hog CPU due to OOB skb.
In the following cases, manage_oob() skips OOB skb(s) and returns NULL for the last recv(MSG_PEEK):
socketpair(AF_UNIX, SOCK_STREAM, 0, sk);
1) skb -> OOB skb -> NULL
send(sk[0], "ab", 2, MSG_OOB);
recv(sk[1], buf, 0, MSG_PEEK);
2) skb -> consumed OOB skb -> NULL
send(sk[0], "ab", 2, MSG_OOB);
recv(sk[1], buf, 1, MSG_OOB);
recv(sk[1], buf, 0, MSG_PEEK);
3) consumed OOB skb -> OOB skb -> NULL
send(sk[0], "a", 1, MSG_OOB);
recv(sk[1], buf, 0, MSG_OOB);
send(sk[0], "b", 1, MSG_OOB);
recv(sk[1], buf, 1, MSG_PEEK);Then, @copied is 0 in unix_stream_read_generic() (zero-length buffer, or non-OOB skb is not yet consumed), and unix_stream_data_wait() is called.
However, it returns immediately because @last is not updated in unix_stream_read_generic(), and the thread busy-waits for a new skb.
Let's update @last in manage_oob().
For MSG_PEEK, @last is updated with the skipped OOB, and for the non-peek case, @last matches the returned value (when !copied) because OOB is unlinked.
Note that manage_oob() is inlined and no stack canary is added.
--- net/unix/af_unix.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
net/unix/af_unix.c +7 -3
@@ -2831,8 +2831,8 @@ static int unix_stream_recv_urg(struct unix_stream_read_state *state)return 1 ; } -static struct sk_buff *manage_oob (struct sk_buff *skb,struct sock *sk, -int flags,int copied) +static struct sk_buff *manage_oob (struct sk_buff *skb,struct sk_buff **last, +struct sock *sk,int flags,int copied) {struct sk_buff *read_skb =NULL , *unread_skb =NULL ;struct unix_sock *u =unix_sk (sk);
@@ -2846,11 +2846,13 @@ static struct sk_buff *manage_oob(struct sk_buff *skb, struct sock *sk,if (copied && (!u->oob_skb || skb == u->oob_skb)) { skb =NULL ; }else if (flags &MSG_PEEK ) { + *last = skb; skb =skb_peek_next (skb, &sk->sk_receive_queue); }else { read_skb = skb; skb =skb_peek_next (skb, &sk->sk_receive_queue);__skb_unlink (read_skb, &sk->sk_receive_queue); + *last = skb; }if (!skb)
@@ -2869,8 +2871,10 @@ static struct sk_buff *manage_oob(struct sk_buff *skb, struct sock *sk,__skb_unlink (skb, &sk->sk_receive_queue); unread_skb = skb; skb =skb_peek (&sk->sk_receive_queue); + *last = skb; } }else if (!sock_flag (sk,SOCK_URGINLINE )) { + *last = skb; skb =skb_peek_next (skb, &sk->sk_receive_queue); }
@@ -2990,7 +2994,7 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state, again:#if IS_ENABLED (CONFIG_AF_UNIX_OOB )if (skb) { - skb =manage_oob (skb, sk, flags, copied); + skb =manage_oob (skb, &last, sk, flags, copied);if (!skb && copied) {unix_state_unlock (sk);break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 863/1250 af_unix: Return immediately when manage_oob() returns NULL for 0-length buffer.
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <[email protected]>
[ Upstream commit 6e5ee08eb5858d175da6768d75d163817b6a9d4a ]
Fahad Alharbi reported that recv(0, MSG_PEEK) triggers busy-wait in unix_stream_read_generic() if recv() is blocking and the last skb in the queue is MSG_OOB skb.
In such a situation, TCP returns 0 immediately regardless of blocking or non-blocking.
Let's follow the behaviour.
--- net/unix/af_unix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/unix/af_unix.c +1 -1
@@ -2995,7 +2995,7 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state,#if IS_ENABLED (CONFIG_AF_UNIX_OOB )if (skb) { skb =manage_oob (skb, &last, sk, flags, copied); -if (!skb && copied) { +if (!skb && (copied || !state->size)) {unix_state_unlock (sk);break ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 864/1250 net: ipv4: Fix UDP length overflow with PMTU discover and big MTU
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alice Mikityanska <[email protected]>
[ Upstream commit b83641e0ab8b20eefcc4cdc5a059f897375291a2 ]
This commit bounds cork->base.fragsize to IP_MAX_MTU to avoid a possible overflow of UDP length that triggers a WARN in udp_set_len_short when setsockopt IP_MTU_DISCOVER is set to IP_PMTUDISC_PROBE, and a large packet is sent over a netdev with an unusually large MTU.
Steps to reproduce:
1. Set device MTU bigger than IP_MAX_MTU + 20. cork->base.fragsize will be set to that MTU in ip_setup_cork.
2. Set IP_MTU_DISCOVER to IP_PMTUDISC_PROBE. It lets maxnonfragsize be set to device MTU (cork->fragsize) in __ip_append_data, rather than to IP_MAX_MTU.
3. Send 65528 bytes of payload (+8 bytes of UDP header, +20 bytes of IPv4 header). Device MTU allows it (it's only one byte bigger than IP_MAX_MTU + IPv4 header, and the device MTU is bigger than that).
4. The UDP length in the built packet is 65536, which overflows the 16-bit length field and triggers the WARN in udp_set_len_short.
Note: IP_PMTUDISC_DO with IPv4 is safe, because ip_dst_mtu_maybe_forward always clamps at IP_MAX_MTU, unlike ip6_dst_mtu_maybe_forward.
The Fixes tag points at the first commit where I could reproduce the overflow with IPv4 and IP_PMTUDISC_PROBE.
--- net/ipv4/ip_output.c | 1 + 1 file changed, 1 insertion(+)
net/ipv4/ip_output.c +1 -0
@@ -1304,6 +1304,7 @@ static int ip_setup_cork(struct sock *sk, struct inet_cork *cork, cork->fragsize =ip_sk_use_pmtu (sk) ?dst4_mtu (&rt->dst) :READ_ONCE (rt->dst.dev->mtu); + cork->fragsize =min (cork->fragsize,IP_MAX_MTU );if (!inetdev_valid_mtu (cork->fragsize))return -ENETUNREACH ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 865/1250 net: ipv6: Fix UDP length overflow with PMTU discover and big MTU
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alice Mikityanska <[email protected]>
[ Upstream commit 0ae10b6be49b425827659b23bcce498f80eb7182 ]
This commit bounds cork->base.fragsize to IP6_MAX_MTU for UDP sockets to avoid a possible overflow of UDP length that triggers a WARN in udp_set_len_short when setsockopt IPV6_MTU_DISCOVER is set to IPV6_PMTUDISC_DO or IPV6_PMTUDISC_PROBE, and a large packet is sent over a netdev with an unusually large MTU.
Steps to reproduce (included in the new selftest):
1. Set device MTU bigger than IP6_MAX_MTU. cork->base.fragsize will be set to that MTU in ip6_setup_cork.
2. Set IPV6_MTU_DISCOVER to IPV6_PMTUDISC_PROBE or IPV6_PMTUDISC_DO. It lets maxnonfragsize be set to device MTU (cork->fragsize) in __ip6_append_data, rather than to IP6_MAX_MTU.
3. Send 65528 bytes of payload (+8 bytes of UDP header, +40 bytes of IPv6 header). Device MTU allows it (it's only one byte bigger than IP6_MAX_MTU, and the device MTU is bigger than that).
4. The UDP length in the built packet is 65536, which overflows the 16-bit length field and triggers the WARN in udp_set_len_short.
To avoid breaking sending UDP jumbograms over raw IPv6 sockets, limit the change to UDP sockets only.
The original overflow bug with IPv6 and IPV6_PMTUDISC_DO seems to predate git history (verified reproduction on 2.6.21), was fixed later, and then reappeared in commit 427faee167bc ("net: ipv6: introduce ip6_dst_mtu_maybe_forward"), which is chosen as the Fixes tag here. The overflow with IPV6_PMTUDISC_PROBE reproduces since its introduction in commit 628a5c561890 ("[INET]: Add IP(V6)_PMTUDISC_RPOBE").
--- net/ipv6/ip6_output.c | 2 ++ 1 file changed, 2 insertions(+)
net/ipv6/ip6_output.c +2 -0
@@ -1414,6 +1414,8 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork,if (frag_size && frag_size < mtu) mtu = frag_size; +if (sk_is_udp (sk)) + mtu =min (mtu,IP6_MAX_MTU ); cork->base.fragsize = mtu; cork->base.gso_size = ipc6->gso_size; cork->base.tx_flags =0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 866/1250 net: ipv6: Clamp to IP6_MAX_MTU in ip6_dst_mtu_maybe_forward
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alice Mikityanska <[email protected]>
[ Upstream commit 199271ebc71c1e0913b2fad988a7bff330a8828a ]
Commit 427faee167bc ("net: ipv6: introduce ip6_dst_mtu_maybe_forward") dropped the IP6_MAX_MTU clamp that used to be present in ip6_mtu(). A similar IPv4 commit ac6627a28dbf ("net: ipv4: Consolidate ipv4_mtu and ip_dst_mtu_maybe_forward") preserves the IP_MAX_MTU clamp.
Restore the upper bound in the IPv6 flow to avoid potential 16-bit overflows in forwarding paths.
--- include/net/ip6_route.h | 2 ++ 1 file changed, 2 insertions(+)
include/net/ip6_route.h +2 -0
@@ -349,6 +349,8 @@ static inline unsigned int ip6_dst_mtu_maybe_forward(const struct dst_entry *dstrcu_read_unlock (); out: + mtu = min_t(unsigned int, mtu, IP6_MAX_MTU); +return mtu -lwtunnel_headroom (dst->lwtstate, mtu); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 867/1250 net: ethernet: cortina: Fix budget accounting
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linus Walleij <[email protected]>
[ Upstream commit a0de06d0da78a3db53de65dfd7452cc6d111f703 ]
The gmac_rx() function returns the remaining NAPI budget, but its caller treats the return value as the number of packets received. An idle poll therefore reports a full budget and remains scheduled.
Return the number of received packets instead. Preserve the existing free queue refill accounting by adding that count directly; continuing to subtract it from the budget would invert the refill behavior.
--- drivers/net/ethernet/cortina/gemini.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/net/ethernet/cortina/gemini.c +5 -3
@@ -1451,6 +1451,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)unsigned int frame_len, frag_len;struct gmac_rxdesc *rx =NULL ;struct gmac_queue_page *gpage; +unsigned int received =0 ;union gmac_rxdesc_0 word0;union gmac_rxdesc_1 word1;union gmac_rxdesc_3 word3;
@@ -1546,7 +1547,8 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)napi_gro_frags (&port->napi); skb =NULL ; frag_nr =0 ; - --budget; + budget--; + received++; }continue ;
@@ -1566,7 +1568,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) port->rx_skb = skb; port->rx_frag_nr = frag_nr;writew (r, ptr_reg); -return budget; +return received; }static int gmac_napi_poll (struct napi_struct *napi,int budget)
@@ -1587,7 +1589,7 @@ static int gmac_napi_poll(struct napi_struct *napi, int budget) ++port->rx_napi_exits; } - port->freeq_refill += (budget - received); + port->freeq_refill += received;if (port->freeq_refill > freeq_threshold) { port->freeq_refill -= freeq_threshold;geth_fill_freeq (geth, true);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 868/1250 net: ethernet: cortina: Finish RX updates before NAPI completion
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linus Walleij <[email protected]>
[ Upstream commit baa26841cb9a2cdc7e0e99d6854a4e3359bf7393 ]
napi_complete_done() releases ownership of the NAPI instance, but the Gemini poll keeps the RX statistics writer section open and updates the free queue after calling it. A new poll can therefore start while the old writer is still active.
Finish the statistics and free queue updates before releasing ownership. Only re-enable RX interrupts when napi_complete_done() reports successful completion.
--- drivers/net/ethernet/cortina/gemini.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/net/ethernet/cortina/gemini.c +6 -6
@@ -1582,12 +1582,10 @@ static int gmac_napi_poll(struct napi_struct *napi, int budget)u64_stats_update_begin (&port->rx_stats_syncp); received =gmac_rx (napi->dev, budget); -if (received < budget) { -napi_gro_flush (napi, false); -napi_complete_done (napi, received); -gmac_enable_rx_irq (napi->dev,1 ); +if (received < budget) ++port->rx_napi_exits; - } + +u64_stats_update_end (&port->rx_stats_syncp); port->freeq_refill += received;if (port->freeq_refill > freeq_threshold) {
@@ -1595,7 +1593,9 @@ static int gmac_napi_poll(struct napi_struct *napi, int budget)geth_fill_freeq (geth, true); } -u64_stats_update_end (&port->rx_stats_syncp); +if (received < budget &&napi_complete_done (napi, received)) +gmac_enable_rx_irq (napi->dev,1 ); +return received; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 869/1250 net: ethernet: cortina: Count dropped frames as NAPI work
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linus Walleij <[email protected]>
[ Upstream commit b856c552f556bc0341c1dbe0bf88e630fd1dc4b7 ]
The RX loop only consumes budget when it successfully delivers a frame. Error paths keep consuming descriptors without reducing the budget, so a stream of bad frames can process the entire receive ring in one poll.
Move the budget accounting to a common end-of-frame path. This counts each completed frame as NAPI work whether it was delivered or dropped, matching the behavior of the vendor driver.
--- drivers/net/ethernet/cortina/gemini.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
drivers/net/ethernet/cortina/gemini.c +10 -5
@@ -1502,7 +1502,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) skb =NULL ; frag_nr =0 ; } -continue ; + goto next_desc; } page = gpage->page;
@@ -1524,7 +1524,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) }else if (!skb) {put_page (page); -continue ; + goto next_desc; }if (word3.bits32 &EOF_BIT )
@@ -1547,10 +1547,8 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)napi_gro_frags (&port->napi); skb =NULL ; frag_nr =0 ; - budget--; - received++; } -continue ; + goto next_desc; err_drop:if (skb) {
@@ -1563,6 +1561,13 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)put_page (page); port->stats.rx_dropped++; + +next_desc: +/* Final or single-descriptor fragment, advance things */ +if (word3.bits32 &EOF_BIT ) { + budget--; + received++; + } } port->rx_skb = skb;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 870/1250 net: ethernet: cortina: No mapping is a dropped rx
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linus Walleij <[email protected]>
[ Upstream commit 2cb156213093a62b80cf40b1ec71738e93491971 ]
Increase stats.rx_dropped++ even if this is the first fragment (skb == NULL) so we are doing proper accounting.
Stable-dep-of: 6520198c430c ("net: ethernet: cortina: Count RX drops once per frame")
--- drivers/net/ethernet/cortina/gemini.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/cortina/gemini.c +1 -1
@@ -1496,9 +1496,9 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) gpage =gmac_get_queue_page (geth, port, mapping +PAGE_SIZE );if (!gpage) {dev_err (geth->dev,"could not find mapping\n" ); + port->stats.rx_dropped++;if (skb) {napi_free_frags (&port->napi); - port->stats.rx_dropped++; skb =NULL ; frag_nr =0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 871/1250 net: ethernet: cortina: Count RX drops once per frame
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linus Walleij <[email protected]>
[ Upstream commit 6520198c430c81bcc367f0dd5e32f2fb740b9d51 ]
The absence of a partial skb means either that the driver is not assembling a frame or that the current frame was already dropped. Consequently, repeated descriptor errors can increment rx_dropped more than once, while an orphaned descriptor chain can reach EOF without being counted at all.
Track the dropping state across NAPI polls. Clear it at frame boundaries and route mapping failures and orphaned continuations through the common drop path so each discarded frame is counted exactly once.
--- drivers/net/ethernet/cortina/gemini.c | 41 +++++++++++++++------------ 1 file changed, 23 insertions(+), 18 deletions(-)
drivers/net/ethernet/cortina/gemini.c +23 -18
@@ -124,6 +124,7 @@ struct gemini_ethernet_port {unsigned int rx_coalesce_nsecs;struct sk_buff *rx_skb;unsigned int rx_frag_nr; +bool rx_dropping;unsigned int freeq_refill;struct gmac_txq txq[TX_QUEUE_NUM ];
@@ -1452,6 +1453,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)struct gmac_rxdesc *rx =NULL ;struct gmac_queue_page *gpage;unsigned int received =0 ; +bool dropping = port->rx_dropping;union gmac_rxdesc_0 word0;union gmac_rxdesc_1 word1;union gmac_rxdesc_3 word3;
@@ -1473,6 +1475,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) w = rw.bits.wptr;while (budget && w != r) { + page =NULL ; rx = port->rxq_ring + r; word0 = rx->word0; word1 = rx->word1;
@@ -1486,6 +1489,16 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) frame_len = word1.bits.byte_count; page_offs = mapping & ~PAGE_MASK ; +if (word3.bits32 &SOF_BIT ) { +if (skb) { +napi_free_frags (&port->napi); + port->stats.rx_dropped++; + skb =NULL ; + frag_nr =0 ; + } + dropping = false; + } +if (!mapping) {netdev_err (netdev,"rxq[%u]: HW BUG: zero DMA desc\n" , r);
@@ -1496,24 +1509,11 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) gpage =gmac_get_queue_page (geth, port, mapping +PAGE_SIZE );if (!gpage) {dev_err (geth->dev,"could not find mapping\n" ); - port->stats.rx_dropped++; -if (skb) { -napi_free_frags (&port->napi); - skb =NULL ; - frag_nr =0 ; - } - goto next_desc; + goto err_drop; } page = gpage->page;if (word3.bits32 &SOF_BIT ) { -if (skb) { -napi_free_frags (&port->napi); - port->stats.rx_dropped++; - skb =NULL ; - frag_nr =0 ; - } - skb =gmac_skb_if_good_frame (port, word0, frame_len);if (!skb) goto err_drop;
@@ -1523,8 +1523,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) frag_nr =0 ; }else if (!skb) { -put_page (page); - goto next_desc; + goto err_drop; }if (word3.bits32 &EOF_BIT )
@@ -1557,21 +1556,26 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) frag_nr =0 ; } -if (mapping) +if (page)put_page (page); - port->stats.rx_dropped++; +if (!dropping) { + port->stats.rx_dropped++; + dropping = true; + } next_desc:/* Final or single-descriptor fragment, advance things */ if (word3.bits32 &EOF_BIT ) { budget--; received++; + dropping = false; } } port->rx_skb = skb; port->rx_frag_nr = frag_nr; + port->rx_dropping = dropping;writew (r, ptr_reg);return received; }
@@ -1901,6 +1905,7 @@ static int gmac_stop(struct net_device *netdev)napi_disable (&port->napi); port->rx_skb =NULL ; port->rx_frag_nr =0 ; + port->rx_dropping = false;gmac_enable_irq (netdev,0 );gmac_cleanup_rxq (netdev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 872/1250 net: ethernet: cortina: Count RX descriptors for freeq refill
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linus Walleij <[email protected]>
[ Upstream commit e89e88ad41d9f31c829c2af39c48313e8e48d5b0 ]
The software free queue provides one buffer fragment for every descriptor moved to an RX queue. The refill heuristic instead advances by NAPI work, which counts frames. A fragmented or discarded frame can consume several queue entries while adding only one to the refill count.
Count the RX descriptors as they are consumed and report that separately from NAPI work. Use the descriptor count to drive free queue refills.
--- drivers/net/ethernet/cortina/gemini.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/net/ethernet/cortina/gemini.c +8 -3
@@ -1441,7 +1441,8 @@ static struct sk_buff *gmac_skb_if_good_frame(struct gemini_ethernet_port *port,return skb; } -static unsigned int gmac_rx (struct net_device *netdev,unsigned int budget) +static unsigned int gmac_rx (struct net_device *netdev,unsigned int budget, +unsigned int *freeq_consumed) {struct gemini_ethernet_port *port =netdev_priv (netdev);unsigned short m = (1 << port->rxq_order) -1 ;
@@ -1449,6 +1450,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)void __iomem *ptr_reg = port->rxq_rwptr;unsigned int frag_nr = port->rx_frag_nr;struct sk_buff *skb = port->rx_skb; +unsigned int consumed =0 ;unsigned int frame_len, frag_len;struct gmac_rxdesc *rx =NULL ;struct gmac_queue_page *gpage;
@@ -1484,6 +1486,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) r++; r &= m; + consumed++; frag_len = word0.bits.buffer_size; frame_len = word1.bits.byte_count;
@@ -1576,6 +1579,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) port->rx_skb = skb; port->rx_frag_nr = frag_nr; port->rx_dropping = dropping; + *freeq_consumed = consumed;writew (r, ptr_reg);return received; }
@@ -1585,18 +1589,19 @@ static int gmac_napi_poll(struct napi_struct *napi, int budget)struct gemini_ethernet_port *port =netdev_priv (napi->dev);struct gemini_ethernet *geth = port->geth;unsigned int freeq_threshold; +unsigned int freeq_consumed;unsigned int received; freeq_threshold =1 << (geth->freeq_order -1 );u64_stats_update_begin (&port->rx_stats_syncp); - received =gmac_rx (napi->dev, budget); + received =gmac_rx (napi->dev, budget, &freeq_consumed);if (received < budget) ++port->rx_napi_exits;u64_stats_update_end (&port->rx_stats_syncp); - port->freeq_refill += received; + port->freeq_refill += freeq_consumed;if (port->freeq_refill > freeq_threshold) { port->freeq_refill -= freeq_threshold;geth_fill_freeq (geth, true);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 873/1250 drm/adp: Drop the select of the nonexistent CONFIG_DRM_KMS_DMA_HELPER
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit fedf002d7d08bee36693aacd1ade2ba39351ea91 ]
There is no Kconfig symbol CONFIG_DRM_KMS_DMA_HELPER. The former CONFIG_DRM_KMS_CMA_HELPER was removed by commit 09717af7d13d ("drm:
Remove CONFIG_DRM_KMS_CMA_HELPER option") before this driver was added, so the select does nothing. The driver already selects CONFIG_DRM_GEM_DMA_HELPER, which is what it needs.
Remove the dead line.
--- drivers/gpu/drm/adp/Kconfig | 1 - 1 file changed, 1 deletion(-)
drivers/gpu/drm/adp/Kconfig +0 -1
@@ -6,7 +6,6 @@ config DRM_ADP select DRM_KMS_HELPER select DRM_BRIDGE_CONNECTOR select DRM_DISPLAY_HELPER - select DRM_KMS_DMA_HELPER select DRM_GEM_DMA_HELPER select DRM_PANEL_BRIDGE select VIDEOMODE_HELPERS
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 874/1250 drm/logicvc: Drop the select of the nonexistent CONFIG_DRM_KMS_DMA_HELPER
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit f97802dd98b27e45c04293f9926f07642578b23f ]
CONFIG_DRM_KMS_CMA_HELPER was removed by commit 09717af7d13d ("drm:
Remove CONFIG_DRM_KMS_CMA_HELPER option"). When commit 6bcfe8eaeef0 ("drm/fb: rename FB CMA helpers to FB DMA helpers") later renamed the select in this Kconfig to CONFIG_DRM_KMS_DMA_HELPER, no symbol of that name existed, and git log -S finds no Kconfig file that has defined one since. The select is silently ignored. The driver already selects CONFIG_DRM_GEM_DMA_HELPER, which is what it needs.
Remove the dead line.
--- drivers/gpu/drm/logicvc/Kconfig | 1 - 1 file changed, 1 deletion(-)
drivers/gpu/drm/logicvc/Kconfig +0 -1
@@ -4,7 +4,6 @@ config DRM_LOGICVC depends on OF || COMPILE_TEST select DRM_CLIENT_SELECTION select DRM_KMS_HELPER - select DRM_KMS_DMA_HELPER select DRM_GEM_DMA_HELPER select REGMAP select REGMAP_MMIO
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 875/1250 ALSA: hda: Report a change when only the channel status bytes move
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: HyeongJun An <[email protected]>
[ Upstream commit 7284788743121ec8bed556b00f830dc52ad9955d ]
The put() callback of "IEC958 Playback Default" returns whether the converted register value moved. The convert_from_spdif_status() helper reads part of the first two channel status bytes and none of the last two, while the get() callback returns all four. So a write that lands only in the bits it does not read changes what userspace reads back and reports no change. Of the 31 bits above the mode bit, 20 are such bits in consumer mode and 29 in professional mode. The core notifies only on a positive return.
Toggling status[2] bit 0 on an HDA HDMI codec moves the read-back from 04 00 00 00 to 04 00 01 00 with no event. Toggling the non-audio bit in status[0] gives one.
Compare the stored status as well, the way the ac97 code does. The write to the codec stays gated on the converted value.
--- sound/hda/common/codec.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
sound/hda/common/codec.c +3 -1
@@ -2277,6 +2277,7 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,int idx = kcontrol->private_value;struct hda_spdif_out *spdif;hda_nid_t nid; +unsigned int old_status;unsigned short val;int change;
@@ -2285,6 +2286,7 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,guard (mutex)(&codec->spdif_mutex); spdif =snd_array_elem (&codec->spdif_out, idx); nid = spdif->nid; + old_status = spdif->status; spdif->status = ucontrol->value.iec958.status[0 ] | ((unsigned int )ucontrol->value.iec958.status[1 ] <<8 ) | ((unsigned int)ucontrol->value.iec958.status[2] << 16) |
@@ -2295,7 +2297,7 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol, spdif->ctls = val;if (change && nid != (u16)-1 )set_dig_out_convert (codec, nid, val &0xff , (val >>8 ) &0xff ); -return change; +return change || spdif->status != old_status; }#define snd_hda_spdif_out_switch_info snd_ctl_boolean_mono_info
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 876/1250 idpf: account for VLAN header when parsing RSC packet header
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joshua Hay <[email protected]>
[ Upstream commit cc6d60ef92278a31ffc2e94966a0921b9646af18 ]
While parsing the header of a Receive Side Coalesced (RSC) packet, check if a VLAN tag is present and adjust the header parsing accordingly. Otherwise, Rx TCP traffic is completely broken for any VLAN interface whose underlying interface has RSC (rx-gro-hw) enabled.
We only need to worry about one VLAN header since Rx packets with multiple VLAN headers are not candidates for RSC.
--- drivers/net/ethernet/intel/idpf/idpf_txrx.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/net/ethernet/intel/idpf/idpf_txrx.c +7 -3
@@ -3277,6 +3277,7 @@ static int idpf_rx_rsc(struct idpf_rx_queue *rxq, struct sk_buff *skb, struct libeth_rx_pt decoded) {u16 rsc_segments, rsc_seg_len; +u16 l3_start =0 ;bool ipv4, ipv6;int len;
@@ -3299,7 +3300,10 @@ static int idpf_rx_rsc(struct idpf_rx_queue *rxq, struct sk_buff *skb,NAPI_GRO_CB (skb)->count = rsc_segments;skb_shinfo (skb)->gso_size = rsc_seg_len; -skb_reset_network_header (skb); +if (unlikely (eth_type_vlan (skb->protocol))) + l3_start =VLAN_HLEN ; + +skb_set_network_header (skb, l3_start);if (ipv4) {struct iphdr *ipv4h =ip_hdr (skb);
@@ -3307,7 +3311,7 @@ static int idpf_rx_rsc(struct idpf_rx_queue *rxq, struct sk_buff *skb,skb_shinfo (skb)->gso_type =SKB_GSO_TCPV4 ;/* Reset and set transport header offset in skb */ -skb_set_transport_header (skb,sizeof (struct iphdr )); +skb_set_transport_header (skb, l3_start +sizeof (struct iphdr )); len = skb->len -skb_transport_offset (skb);/* Compute the TCP pseudo header checksum*/
@@ -3317,7 +3321,7 @@ static int idpf_rx_rsc(struct idpf_rx_queue *rxq, struct sk_buff *skb,struct ipv6hdr *ipv6h =ipv6_hdr (skb);skb_shinfo (skb)->gso_type =SKB_GSO_TCPV6 ; -skb_set_transport_header (skb,sizeof (struct ipv6hdr )); +skb_set_transport_header (skb, l3_start +sizeof (struct ipv6hdr )); len = skb->len -skb_transport_offset (skb);tcp_hdr (skb)->check = ~tcp_v6_check (len, &ipv6h->saddr, &ipv6h->daddr,0 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 877/1250 ice: add missing xa_destroy for sched_node_ids
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jacob Keller <[email protected]>
[ Upstream commit 53432c4c3e869076350aef319534431af8ba99c1 ]
Commit 16dfa49406bc ("ice: Introduce new parameters in ice_sched_node") added a sched_node_ids xarray to the port info structure, but never called xa_destroy on it.
Since xarrays can allocate internal memory, this can result in a memory leak even if every element in the xarray has been removed.
The xarray is currently embedded in the port_info structure. This appears to have been done because its use is within functions that take the port_info as a primary argument.
However, this complicates managing the lifecycle of the field. The port_info structure is allocated in ice_init_hw() using devm, and it is not released until the devm cleanup when the driver is unloaded.
The ice_init_hw() function is called in many places, including devlink reload, and possibly during DDP load after updating the Tx scheduler layout.
Adding a call of xa_destroy to the ice_deinit_hw() causes Sashiko to raise multiple concerns due to potential ordering issues and possible ways that port_info could be a dangling reference.
To handle this, move the sched_node_ids out of port_info and into the hw structure. All users of the array already have a pointer to hw anyways, and there is only one sched_node_ids per adapter. While here, remove the overly verbose comment explaining the nature of the sched_node_ids xarray.
Add the missing xa_destroy to the cleanup path and to ice_deinit_hw(), ensuring that we properly release the xarray memory.
This was caught by Sashiko during development of unrelated code.
--- drivers/net/ethernet/intel/ice/ice_common.c | 9 ++++++--- drivers/net/ethernet/intel/ice/ice_sched.c | 4 ++-- drivers/net/ethernet/intel/ice/ice_type.h | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-)
drivers/net/ethernet/intel/ice/ice_common.c +6 -3
@@ -1086,14 +1086,13 @@ int ice_init_hw(struct ice_hw *hw) hw->evb_veb = true; -/* init xarray for identifying scheduling nodes uniquely */ -xa_init_flags (&hw->port_info->sched_node_ids,XA_FLAGS_ALLOC ); +xa_init_flags (&hw->sched_node_ids,XA_FLAGS_ALLOC );/* Query the allocated resources for Tx scheduler */ status =ice_sched_query_res_alloc (hw);if (status) {ice_debug (hw,ICE_DBG_SCHED ,"Failed to get scheduler allocated resources\n" ); - goto err_unroll_alloc; + goto err_unroll_xarray; }ice_sched_get_psm_clk_freq (hw);
@@ -1184,6 +1183,8 @@ int ice_init_hw(struct ice_hw *hw)ice_cleanup_fltr_mgmt_struct (hw); err_unroll_sched:ice_sched_cleanup_all (hw); +err_unroll_xarray: +xa_destroy (&hw->sched_node_ids); err_unroll_alloc:devm_kfree (ice_hw_to_dev (hw), hw->port_info); err_unroll_cqinit:
@@ -1224,6 +1225,8 @@ void ice_deinit_hw(struct ice_hw *hw)/* Clear VSI contexts if not already cleared */ ice_clear_all_vsi_ctx (hw); + +xa_destroy (&hw->sched_node_ids); }/**
drivers/net/ethernet/intel/ice/ice_sched.c +2 -2
@@ -371,7 +371,7 @@ void ice_free_sched_node(struct ice_port_info *pi, struct ice_sched_node *node)devm_kfree (ice_hw_to_dev (hw), node->children);kfree (node->name); -xa_erase (&pi->sched_node_ids, node->id); +xa_erase (&hw->sched_node_ids, node->id);devm_kfree (ice_hw_to_dev (hw), node); }
@@ -977,7 +977,7 @@ ice_sched_add_elems(struct ice_port_info *pi, struct ice_sched_node *tc_node,if (!new_node->name)return -ENOMEM ; - status =xa_alloc (&pi->sched_node_ids, &new_node->id,NULL ,XA_LIMIT (0 ,UINT_MAX ), + status =xa_alloc (&hw->sched_node_ids, &new_node->id,NULL ,XA_LIMIT (0 ,UINT_MAX ),GFP_KERNEL );if (status) { ice_debug(hw, ICE_DBG_SCHED, "xa_alloc failed for sched node status =%d\n",
drivers/net/ethernet/intel/ice/ice_type.h +1 -1
@@ -759,7 +759,6 @@ struct ice_port_info {/* List contain profile ID(s) and other params per layer */ struct list_head rl_prof_list[ICE_AQC_TOPO_MAX_LEVEL_NUM ];struct ice_qos_cfg qos_cfg; -struct xarray sched_node_ids; u8 is_vf:1; u8 is_custom_tx_enabled:1; };
@@ -922,6 +921,7 @@ struct ice_hw {u8 sw_entry_point_layer;u16 max_children[ICE_AQC_TOPO_MAX_LEVEL_NUM ];struct list_head agg_list;/* lists all aggregator */ +struct xarray sched_node_ids;struct ice_vsi_ctx *vsi_ctx[ICE_MAX_VSI ];u8 evb_veb;/* true for VEB, false for VEPA */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 878/1250 eth: ice: dont dereference pointers from TP_printk()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jakub Kicinski <[email protected]>
[ Upstream commit b8bf9bfda5f62e11444e483c2b4aaff90c5cfc6b ]
After forwarding net-next during the v7.3 merge window we started seeing:
TRACE EVENT ERROR: Event ice_tx_dim_work has double dereference in TP_printk: REC->q_vector->tx.tx_ring->q_index
WARNING: kernel/trace/trace_events.c:420 at test_double_dereference.cold+0x39/0x4b
this is due to extra checks added in tracing subsystem in
commit b5cc230af5e5 ("tracing: Warn when an event dereferences a pointer in TP_printk()").
Printing happens long after the event was recorded, by which point the pointers may be invalid (the ring or the dim instance). Copy the eight scalars into the event instead.
--- drivers/net/ethernet/intel/ice/ice_trace.h | 64 ++++++++++++++-------- 1 file changed, 42 insertions(+), 22 deletions(-)
drivers/net/ethernet/intel/ice/ice_trace.h +42 -22
@@ -63,23 +63,33 @@DECLARE_EVENT_CLASS (ice_rx_dim_template, TP_PROTO(struct ice_q_vector *q_vector, struct dim *dim),TP_ARGS (q_vector, dim), - TP_STRUCT__entry(__field(struct ice_q_vector *, q_vector) - __field(struct dim *, dim) + TP_STRUCT__entry(__field(u16, q_index) + __field(u8, state) + __field(u8, profile_ix) + __field(u8, tune_state) + __field(u8, steps_right) + __field(u8, steps_left) + __field(u8, tired)__string (devname, q_vector->rx.rx_ring->netdev->name)), - TP_fast_assign(__entry->q_vector = q_vector; - __entry->dim = dim; + TP_fast_assign(__entry->q_index = q_vector->rx.rx_ring->q_index; + __entry->state = dim->state; + __entry->profile_ix = dim->profile_ix; + __entry->tune_state = dim->tune_state; + __entry->steps_right = dim->steps_right; + __entry->steps_left = dim->steps_left; + __entry->tired = dim->tired; __assign_str(devname);),TP_printk ("netdev: %s Rx-Q: %d dim-state: %d dim-profile: %d dim-tune: %d dim-st-right: %d dim-st-left: %d dim-tired: %d" ,__get_str (devname), - __entry->q_vector->rx.rx_ring->q_index, - __entry->dim->state, - __entry->dim->profile_ix, - __entry->dim->tune_state, - __entry->dim->steps_right, - __entry->dim->steps_left, - __entry->dim->tired) + __entry->q_index, + __entry->state, + __entry->profile_ix, + __entry->tune_state, + __entry->steps_right, + __entry->steps_left, + __entry->tired) ); DEFINE_EVENT(ice_rx_dim_template, ice_rx_dim_work,
@@ -90,23 +100,33 @@ DEFINE_EVENT(ice_rx_dim_template, ice_rx_dim_work,DECLARE_EVENT_CLASS (ice_tx_dim_template, TP_PROTO(struct ice_q_vector *q_vector, struct dim *dim),TP_ARGS (q_vector, dim), - TP_STRUCT__entry(__field(struct ice_q_vector *, q_vector) - __field(struct dim *, dim) + TP_STRUCT__entry(__field(u16, q_index) + __field(u8, state) + __field(u8, profile_ix) + __field(u8, tune_state) + __field(u8, steps_right) + __field(u8, steps_left) + __field(u8, tired)__string (devname, q_vector->tx.tx_ring->netdev->name)), - TP_fast_assign(__entry->q_vector = q_vector; - __entry->dim = dim; + TP_fast_assign(__entry->q_index = q_vector->tx.tx_ring->q_index; + __entry->state = dim->state; + __entry->profile_ix = dim->profile_ix; + __entry->tune_state = dim->tune_state; + __entry->steps_right = dim->steps_right; + __entry->steps_left = dim->steps_left; + __entry->tired = dim->tired; __assign_str(devname);),TP_printk ("netdev: %s Tx-Q: %d dim-state: %d dim-profile: %d dim-tune: %d dim-st-right: %d dim-st-left: %d dim-tired: %d" ,__get_str (devname), - __entry->q_vector->tx.tx_ring->q_index, - __entry->dim->state, - __entry->dim->profile_ix, - __entry->dim->tune_state, - __entry->dim->steps_right, - __entry->dim->steps_left, - __entry->dim->tired) + __entry->q_index, + __entry->state, + __entry->profile_ix, + __entry->tune_state, + __entry->steps_right, + __entry->steps_left, + __entry->tired) ); DEFINE_EVENT(ice_tx_dim_template, ice_tx_dim_work,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 879/1250 Bluetooth: btusb: Fix UAF of btusb_data by rx_work
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luiz Augusto von Dentz <[email protected]>
[ Upstream commit 1c12c3117639e78940959d956519c758c57d0849 ]
btusb_close() and btusb_flush() cancel data->rx_work with the asynchronous cancel_delayed_work(), so if btusb_rx_work() is already running on another CPU it keeps running after the cancel returns.
btusb_disconnect() calls hci_unregister_dev(), which invokes btusb_close(), and then frees the btusb_data. A still running btusb_rx_work() then dereferences the freed data:
while ((skb = skb_dequeue(&data->acl_q))) data->recv_acl(data->hdev, skb);
Use cancel_delayed_work_sync() instead. In btusb_close() the cancel also has to happen after btusb_stop_traffic(), otherwise an URB completion racing with the cancel can requeue the work right after it has been waited for.
--- drivers/bluetooth/btusb.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
drivers/bluetooth/btusb.c +10 -4
@@ -2022,18 +2022,24 @@ static int btusb_close(struct hci_dev *hdev)BT_DBG ("%s" , hdev->name); -cancel_delayed_work (&data->rx_work);cancel_work_sync (&data->work);cancel_work_sync (&data->waker); -skb_queue_purge (&data->acl_q); -clear_bit (BTUSB_ISOC_RUNNING , &data->flags);clear_bit (BTUSB_BULK_RUNNING , &data->flags);clear_bit (BTUSB_INTR_RUNNING , &data->flags);clear_bit (BTUSB_DIAG_RUNNING , &data->flags);btusb_stop_traffic (data); + +/* rx_work must only be canceled once the URBs that can rearm it are +* gone, and it must be canceled synchronously since btusb_disconnect() +* frees the btusb_data it dereferences right after hci_unregister_dev(). +*/ +cancel_delayed_work_sync (&data->rx_work); + +skb_queue_purge (&data->acl_q); +btusb_free_frags (data); err =usb_autopm_get_interface (data->intf);
@@ -2059,7 +2065,7 @@ static int btusb_flush(struct hci_dev *hdev)BT_DBG ("%s" , hdev->name); -cancel_delayed_work (&data->rx_work); +cancel_delayed_work_sync (&data->rx_work);skb_queue_purge (&data->acl_q);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 880/1250 Bluetooth: btintel_pcie: validate packet_len before skb_put_data
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kiran K <[email protected]>
[ Upstream commit 6436e1b5331b1aebf905c13e0880a37032719b75 ]
btintel_pcie_submit_rx_work() reads packet_len from rfh_hdr without checking if it exceeds the RX buffer size. An oversized packet_len can lead to an out-of-bounds read in skb_put_data().
Validate packet_len to ensure it is non-zero and does not exceed BTINTEL_PCIE_BUFFER_SIZE - sizeof(*rfh_hdr), logging an error when invalid.
This issue was reported by Claude Mythos. It can be simulated either by using customized firmware configured to return an invalid packet_len or by modifying rfh_hdr->packet_len in the driver before calling btintel_pcie_submit_rx_work().
--- drivers/bluetooth/btintel_pcie.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/bluetooth/btintel_pcie.c +3 -1
@@ -1365,7 +1365,9 @@ static int btintel_pcie_submit_rx_work(struct btintel_pcie_data *data, u8 status rfh_hdr = buf; len = rfh_hdr->packet_len; -if (len <=0 ) { +if (len ==0 || len >BTINTEL_PCIE_BUFFER_SIZE -sizeof (*rfh_hdr)) { +bt_dev_err (data->hdev,"Invalid packet_len %d (max %zu)" , len, +BTINTEL_PCIE_BUFFER_SIZE -sizeof (*rfh_hdr)); ret = -EINVAL ; goto resubmit; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 881/1250 Bluetooth: btintel_pcie: fix tx_handle bounds off-by-one
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kiran K <[email protected]>
[ Upstream commit 3dd1b41f96aad08444be1b7626c89de2b9f2abd4 ]
Valid indices into txq->urbd0s/tfds/bufs are 0..txq->count-1, so tfd_index == txq->count is already out of range. Change the guard in btintel_pcie_msix_tx_handle() from '> txq->count' to '>= txq->count'.
This issue was reported by Claude Mythos.
--- drivers/bluetooth/btintel_pcie.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/bluetooth/btintel_pcie.c +1 -1
@@ -1018,7 +1018,7 @@ static void btintel_pcie_msix_tx_handle(struct btintel_pcie_data *data) urbd0 = &txq->urbd0s[cr_tia]; -if (urbd0->tfd_index > txq->count) +if (urbd0->tfd_index >= txq->count)return ; cr_tia = (cr_tia +1 ) % txq->count;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 882/1250 Bluetooth: btmtk: Declare MT7920 (MT7961 1a) Bluetooth firmware
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ivan Hu <[email protected]>
[ Upstream commit 3d8a8e81ea8ad8813d4c82a12ba53ecb597b217d ]
btmtk_fw_get_filename() constructs the firmware name at runtime, so for the MT7920 variant (dev_id 0x7961 with fw_flavor set) it requests "mediatek/BT_RAM_CODE_MT7961_1a_2_hdr.bin" without ever declaring it via MODULE_FIRMWARE(). Tools that select firmware from module metadata (e.g. "modinfo -F firmware") therefore omit this blob, so request_firmware() fails and Bluetooth does not initialise on MT7920, even though the file is present in linux-firmware.
Declare it with MODULE_FIRMWARE(), as the mt76 driver already does for the corresponding MT7920 wifi firmware.
--- drivers/bluetooth/btmtk.c | 1 + drivers/bluetooth/btmtk.h | 1 + 2 files changed, 2 insertions(+)
drivers/bluetooth/btmtk.c +1 -0
@@ -1564,5 +1564,6 @@ MODULE_FIRMWARE(FIRMWARE_MT7663);MODULE_FIRMWARE (FIRMWARE_MT7668 );MODULE_FIRMWARE (FIRMWARE_MT7922 );MODULE_FIRMWARE (FIRMWARE_MT7961 ); +MODULE_FIRMWARE (FIRMWARE_MT7920 );MODULE_FIRMWARE (FIRMWARE_MT7925 );MODULE_FIRMWARE (FIRMWARE_MT7927 );
drivers/bluetooth/btmtk.h +1 -0
@@ -7,6 +7,7 @@#define FIRMWARE_MT7922 "mediatek/BT_RAM_CODE_MT7922_1_1_hdr.bin"#define FIRMWARE_MT7902 "mediatek/BT_RAM_CODE_MT7902_1_1_hdr.bin"#define FIRMWARE_MT7961 "mediatek/BT_RAM_CODE_MT7961_1_2_hdr.bin" +#define FIRMWARE_MT7920 "mediatek/BT_RAM_CODE_MT7961_1a_2_hdr.bin"#define FIRMWARE_MT7925 "mediatek/mt7925/BT_RAM_CODE_MT7925_1_1_hdr.bin"#define FIRMWARE_MT7927 "mediatek/mt7927/BT_RAM_CODE_MT6639_2_1_hdr.bin"
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 883/1250 Bluetooth: hci_sysfs: Fix NULL pointer dereference in device_del()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Krystian Kaniewski <[email protected]>
[ Upstream commit 9b851b09b392da68bd715601f10a5adb2d8d19b8 ]
A NULL pointer dereference in klist_put() occurs when a child device (such as a BNEP network device in bnep_session) is concurrently being unregistered while hci_conn_del_sysfs() reparents child devices.
This is caused by a race condition between hci_conn_del_sysfs() and concurrent child device unregistration (e.g. bnep_session calling unregister_netdev()). During device unregistration, device_del() snapshots a non-NULL parent pointer. Concurrently, hci_conn_del_sysfs() finds the child device using device_find_any_child() and calls device_move() to reparent it to NULL, which removes the node from its parent's klist and clears knode_parent. Subsequently, device_del() calls klist_del(&dev->p->knode_parent) using the stale parent snapshot, causing klist_put() to dereference knode_klist(n)->put on an already removed node, resulting in a NULL pointer dereference.
This race was introduced by commit 27aabf27fd01 ("Bluetooth: fix use-after-free in device_for_each_child()"), which replaced device_find_child(..., __match_tty) with device_find_any_child() in hci_conn_del_sysfs(). That change was intended to avoid a use-after-free where conn->dev outlived its parent hdev->dev when child devices held references to conn->dev, because conn->dev only held a reference to hdev->dev while registered in sysfs.
Fix the issue properly by taking an explicit reference to the parent device with get_device(&hdev->dev) in hci_conn_init_sysfs() and dropping it with put_device(parent) in bt_link_release() when the conn device is freed. This ensures that hdev->dev remains valid for the entire lifecycle of conn->dev, resolving the underlying use-after-free. With the parent reference held properly, restore the __match_tty filter in hci_conn_del_sysfs() so that device_move() is only invoked on persistent RFCOMM TTY devices as originally intended, eliminating the race condition with unregistering network devices.
--- net/bluetooth/hci_sysfs.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
net/bluetooth/hci_sysfs.c +15 -2
@@ -13,7 +13,10 @@ static const struct class bt_class = {static void bt_link_release (struct device *dev) {struct hci_conn *conn =to_hci_conn (dev); +struct device *parent = dev->parent; +kfree (conn); +put_device (parent); }static const struct device_type bt_link = {
@@ -21,6 +24,16 @@ static const struct device_type bt_link = { .release = bt_link_release, }; +/* +* The rfcomm tty device will possibly retain even when conn +* is down, and sysfs doesn't support move zombie device, +* so we should move the device before conn device is destroyed. +*/ +static int __match_tty (struct device *dev,const void *data) +{ +return !strncmp (dev_name (dev),"rfcomm" ,6 ); +} +void hci_conn_init_sysfs (struct hci_conn *conn) {struct hci_dev *hdev = conn->hdev;
@@ -29,7 +42,7 @@ void hci_conn_init_sysfs(struct hci_conn *conn) conn->dev.type = &bt_link; conn->dev.class = &bt_class; - conn->dev.parent = &hdev->dev; + conn->dev.parent =get_device (&hdev->dev);device_initialize (&conn->dev); }
@@ -69,7 +82,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn)while (1 ) {struct device *dev; - dev =device_find_any_child (&conn->dev); + dev =device_find_child (&conn->dev,NULL , __match_tty);if (!dev)break ;device_move (dev,NULL ,DPM_ORDER_DEV_LAST );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 884/1250 Bluetooth: btusb: mediatek: Fix leaked runtime PM reference in reset
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiajia Liu <[email protected]>
[ Upstream commit e486a891c412d9d82ee865987f4eead6196e1f96 ]
MT7925 on HP Pro Mini 260 sometimes timed out during reloading driver and reset usb device. btusb_suspend is not called again after closing bluetooth interface.
usbcore: registered new interface driver btusb
Bluetooth: hci0: HW/SW Version: 0x00000000, Build Time: 20260605184935
Bluetooth: hci0: Execution of wmt command timed out
Bluetooth: hci0: Failed to send wmt patch dwnld (-110)
Bluetooth: hci0: Failed to set up firmware (-110)
usb 3-10: reset high-speed USB device number 4 using xhci_hcd
Bluetooth: hci0: HW/SW Version: 0x00000000, Build Time: 20260605184935
Bluetooth: hci0: Device setup in 1856545 usecs
Bluetooth: hci0: AOSP extensions version v1.00
Bluetooth: hci0: AOSP quality report is supported
Bluetooth: MGMT ver 1.23
btusb_mtk_reset calls usb_autopm_get_interface to resume the device before driving the hardware reset, but never calls the matching usb_autopm_put_interface. Every hardware reset therefore leaks a PM usage reference of the interface, preventing the device from being runtime suspended again until it is unbound.
Add the BTUSB_RESET flag. It is set before usb_queue_reset_device and is cleared in btusb_disconnect, which drops the reference as well. If the flag is already set when a new reset is requested, drop one reference.
Also clear BTMTK_HW_RESET_ACTIVE if usb_autopm_get_interface fails, otherwise no further reset could ever be attempted.
--- drivers/bluetooth/btusb.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
drivers/bluetooth/btusb.c +13 -1
@@ -936,6 +936,7 @@ struct qca_dump_info {#define BTUSB_USE_ALT3_FOR_WBS 15#define BTUSB_ALT6_CONTINUOUS_TX 16#define BTUSB_HW_SSR_ACTIVE 17 +#define BTUSB_RESET 19struct btusb_data {struct hci_dev *hdev;
@@ -2858,8 +2859,11 @@ static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data) } err =usb_autopm_get_interface (data->intf); -if (err <0 ) +if (err <0 ) { +bt_dev_err (hdev,"Failed usb_autopm_get_interface: %d" , err); +clear_bit (BTMTK_HW_RESET_ACTIVE , &btmtk_data->flags);return err; + }/* Release MediaTek ISO data interface */ btusb_mtk_release_iso_intf (hdev);
@@ -2869,6 +2873,11 @@ static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data) err =btmtk_usb_subsys_reset (hdev, btmtk_data->dev_id); +if (test_and_set_bit (BTUSB_RESET , &data->flags)) { +bt_dev_err (hdev,"last usb reset failed? Resetting again" ); +usb_autopm_put_interface_no_suspend (data->intf); + } +usb_queue_reset_device (data->intf);clear_bit (BTMTK_HW_RESET_ACTIVE , &btmtk_data->flags);
@@ -4445,6 +4454,9 @@ static void btusb_disconnect(struct usb_interface *intf)if (data->reset_gpio)gpiod_put (data->reset_gpio); +if (test_and_clear_bit (BTUSB_RESET , &data->flags)) +usb_autopm_put_interface_no_suspend (data->intf); +if (intf == data->intf) {if (data->isoc)usb_driver_release_interface (&btusb_driver, data->isoc);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 885/1250 Bluetooth: btusb: Fix leaked runtime PM reference in btusb_reset
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiajia Liu <[email protected]>
[ Upstream commit c93922dd316b7273a8667d29084632066fa8a2d3 ]
btusb_reset calls usb_autopm_get_interface to resume the device before queuing a reset of it, but never calls the matching usb_autopm_put_interface.
usb_queue_reset_device ends up in usb_reset_device(), and since btusb provides no pre_reset/post_reset callbacks the interface is merely unbound and rebound: the interface device object survives this cycle, and so does its PM usage count, which is not cleared when the driver is unbound.
As a result every reset permanently leaks a PM usage reference, preventing the interface from being runtime suspended again until it is unbound.
Set BTUSB_RESET flag before usb_queue_reset_device so that btusb_disconnect drops the reference. If the flag is already set, drop one reference.
--- drivers/bluetooth/btusb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/bluetooth/btusb.c +3 -1
@@ -1013,13 +1013,15 @@ static void btusb_reset(struct hci_dev *hdev)int err; data =hci_get_drvdata (hdev); -/* This is not an unbalanced PM reference since the device will reset */ err =usb_autopm_get_interface (data->intf);if (err) {bt_dev_err (hdev,"Failed usb_autopm_get_interface: %d" , err);return ; } +if (test_and_set_bit (BTUSB_RESET , &data->flags)) +usb_autopm_put_interface_no_suspend (data->intf); +bt_dev_err (hdev,"Resetting usb device." );usb_queue_reset_device (data->intf); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 886/1250 net: mana: Clear RDMA teardown and suspend state in mana_rdma_probe()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Long Li <[email protected]>
[ Upstream commit f6d61fe4c19cf448e5cba6d8767b4e6966f58606 ]
mana_rdma_remove() sets gd->rdma_teardown to stop mana_rdma_service_handle() from acting on servicing events, but nothing ever clears it. A hardware service reset (GDMA_EQE_HWC_RESET_REQUEST) goes through mana_gd_suspend() -> mana_rdma_remove() and mana_gd_resume() -> mana_rdma_probe(), so from the first reset onwards every GDMA_EQE_HWC_SOC_SERVICE event returns early and RDMA suspend/resume servicing is silently dropped for the life of the device.
gd->is_suspended has the same problem: it is set when servicing removes the adev and is cleared only by a matching resume. A reset while RDMA is suspended re-adds the adev but leaves is_suspended set, so a later resume event calls add_adev() on top of a live gd->adev and leaks it. This is currently masked by the rdma_teardown bug.
Clear both in mana_rdma_probe(). On the reset path mana_rdma_remove() has closed the gate and drained the service workqueue, so clear is_suspended first and re-open the gate with smp_store_release(), paired with smp_load_acquire() in the handler, so the handler cannot observe an open gate with a stale is_suspended. On the initial probe path the gate was never closed and both flags are already clear.
This does not order gd->adev, which add_adev() publishes afterwards. A servicing event arriving in that window is still dropped, as it is in mainline today on the initial probe path; closing it needs probe and the handler to be serialized and is left to a separate change.
--- drivers/net/ethernet/microsoft/mana/mana_en.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-)
drivers/net/ethernet/microsoft/mana/mana_en.c +17 -1
@@ -3541,7 +3541,8 @@ static void mana_rdma_service_handle(struct work_struct *work)struct device *dev = gd->gdma_context->dev;int ret; -if (READ_ONCE (gd->rdma_teardown)) +/* Pairs with the smp_store_release() in mana_rdma_probe(). */ +if (smp_load_acquire (&gd->rdma_teardown)) goto out;switch (serv_work->event) {
@@ -3823,6 +3824,21 @@ int mana_rdma_probe(struct gdma_dev *gd)if (err)return err; +/* Clear the state left by a previous mana_rdma_remove() so servicing +* events are handled again after a reset cycle. +*/ + gd->is_suspended = false; + +/* Publish is_suspended before re-opening the gate, so the handler +* cannot observe an open gate with a stale is_suspended. Pairs +* with the smp_load_acquire() in mana_rdma_service_handle(). This +* matters on the reset path, where mana_rdma_remove() closed the +* gate and drained the workqueue; on the initial probe path the +* gate was never closed and both flags are already clear. It does +* not order gd->adev, which add_adev() publishes below. +*/ +smp_store_release (&gd->rdma_teardown, false); + err =add_adev (gd,"rdma" );if (err)mana_gd_deregister_device (gd);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 887/1250 ipv6: null-check fib6_node before accessing in __ip6_del_rt_siblings()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Naman Gulati <[email protected]>
[ Upstream commit cdca92eddc025fdb90071be97738f7d55a65f8dd ]
syzbot reported a null-ptr-deref in __ip6_del_rt_siblings() [0].
The stack trace hinted towards a null dereference of rt->fib6_node when fn->leaf is accessed in __ip6_del_rt_siblings(). With RTNL_FLAG_DOIT_UNLOCKED set, inet6_rtm_delroute() operations run concurrently without acquiring the RTNL lock. In ip6_route_del(), the route lookup happens under rcu_read_lock() without acquiring table->tb6_lock.
Between ip6_route_del() looking up the route and __ip6_del_rt_siblings() acquiring table->tb6_lock, another thread can modify the routing table. For example, when an ECMP route is replaced via RTM_NEWROUTE with NLM_F_REPLACE, fib6_add_rt2node() unlinks all old siblings and sets iter->fib6_node = NULL. A reproducer was found that triggers this [1].
Add a check to ensure rt->fib6_node is non-null before accessing it.
[0]
KASAN: null-ptr-deref in range [0x0000000000000020-0x0000000000000027] RIP: 0010:__ip6_del_rt_siblings+0x31e/0x7c0 net/ipv6/route.c:4056 Call Trace: <TASK> ip6_route_del+0x1054/0x1110 net/ipv6/route.c:4232 inet6_rtm_delroute+0x5d7/0x6d0 net/ipv6/route.c:5669 rtnetlink_rcv_msg+0x802/0xc00 net/core/rtnetlink.c:7132 netlink_rcv_skb+0x226/0x4a0 net/netlink/af_netlink.c:2556 netlink_unicast_kernel net/netlink/af_netlink.c:1319 [inline] netlink_unicast+0x7f5/0x990 net/netlink/af_netlink.c:1345 netlink_sendmsg+0x813/0xb40 net/netlink/af_netlink.c:1900 sock_sendmsg_nosec+0x13a/0x180 net/socket.c:800 __sock_sendmsg net/socket.c:815 [inline] ____sys_sendmsg+0x565/0x870 net/socket.c:2713 ___sys_sendmsg+0x2a5/0x360 net/socket.c:2767 __sys_sendmsg net/socket.c:2799 [inline] __do_sys_sendmsg net/socket.c:2804 [inline] __se_sys_sendmsg net/socket.c:2802 [inline] __x64_sys_sendmsg+0x1b7/0x290 net/socket.c:2802 do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline] do_syscall_64+0x166/0x520 arch/x86/entry/syscall_64.c:84 entry_SYSCALL_64_after_hwframe+0x77/0x7f </TASK>
[1] https://gist.github.com/NamanGulati/0766a1159b6ca61928faaf87425ff899
--- net/ipv6/route.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
net/ipv6/route.c +6 -3
@@ -4004,6 +4004,7 @@ static int __ip6_del_rt_siblings(struct fib6_info *rt, struct fib6_config *cfg)struct net *net = info->nl_net;struct sk_buff *skb =NULL ;struct fib6_table *table; +struct fib6_node *fn;int err = -ENOENT ;if (rt == net->ipv6.fib6_null_entry)
@@ -4011,9 +4012,13 @@ static int __ip6_del_rt_siblings(struct fib6_info *rt, struct fib6_config *cfg) table = rt->fib6_table;spin_lock_bh (&table->tb6_lock); + fn =rcu_dereference_protected (rt->fib6_node, +lockdep_is_held (&table->tb6_lock)); +if (!fn) + goto out_unlock; +if (rt->fib6_nsiblings && cfg->fc_delete_all_nh) {struct fib6_info *sibling, *next_sibling; -struct fib6_node *fn;/* prefer to send a single notification with all hops */ skb =nlmsg_new (rt6_nlmsg_size (rt),GFP_ATOMIC );
@@ -4035,8 +4040,6 @@ static int __ip6_del_rt_siblings(struct fib6_info *rt, struct fib6_config *cfg)* and emit a replace or delete notification, respectively. */ info->skip_notify_kernel =1 ; - fn =rcu_dereference_protected (rt->fib6_node, -lockdep_is_held (&table->tb6_lock));if (rcu_access_pointer (fn->leaf) == rt) {struct fib6_info *last_sibling, *replace_rt;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 888/1250 net: macb: destroy the phylink instance on the probe error path
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolai Buchwitz <[email protected]>
[ Upstream commit 7d059f390750152b9bd69df934198651b94fc26d ]
macb_mii_init() creates a phylink instance on both of its success paths, but the probe unwind frees the netdev without destroying it, so a failing macb_alloc_tieoff() or register_netdev() leaks the instance.
Destroy it at err_out_unregister_mdio, which is only reachable once macb_mii_init() has succeeded, so bp->phylink is valid there.
--- drivers/net/ethernet/cadence/macb_main.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ethernet/cadence/macb_main.c +1 -0
@@ -5752,6 +5752,7 @@ static int macb_probe(struct platform_device *pdev)mdiobus_unregister (bp->mii_bus);mdiobus_free (bp->mii_bus); } +phylink_destroy (bp->phylink); err_out_phy_exit:phy_exit (bp->phy);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 889/1250 net: macb: put the "mdio" child node reference on success
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolai Buchwitz <[email protected]>
[ Upstream commit 382a373d9ea7a6ac4de9c022385b6217f65ae3cc ]
macb_mii_init() holds the reference returned by of_get_child_by_name() for macb_mdiobus_register() and drops it only on the error paths, so every successful probe leaks a node reference. On a CM5, overlay removal after four bind cycles reports
OF: ERROR: memory leak, expected refcount 1 instead of 5
Drop the reference after registration, where __mdiobus_register() has already taken its own for the lifetime of the bus.
--- drivers/net/ethernet/cadence/macb_main.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/ethernet/cadence/macb_main.c +2 -0
@@ -1058,6 +1058,8 @@ static int macb_mii_init(struct macb *bp)if (err) goto err_out_unregister_bus; +of_node_put (mdio_np); +return 0 ; err_out_unregister_bus:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 890/1250 mptcp: remove unneeded READ_ONCE() annotation
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paolo Abeni <[email protected]>
[ Upstream commit caa4a79f74f32084ce28aee8653bc04df745970d ]
The subflow->fully_established flag is always written under the subflow socket lock. Reading such value under the same lock does not require any ONCE annotation.
--- net/mptcp/options.c | 4 ++-- net/mptcp/protocol.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-)
net/mptcp/options.c +2 -2
@@ -530,7 +530,7 @@ static bool mptcp_established_options_mp(struct sock *sk, struct sk_buff *skb,return false;/* MPC/MPJ needed only on 3rd ack packet, DATA_FIN and TCP shutdown take precedence */ -if (READ_ONCE (subflow->fully_established) || snd_data_fin_enable || +if (subflow->fully_established || snd_data_fin_enable || subflow->snd_isn !=TCP_SKB_CB (skb)->seq || sk->sk_state !=TCP_ESTABLISHED )return false;
@@ -997,7 +997,7 @@ static bool check_fully_established(struct mptcp_sock *msk, struct sock *ssk,/* here we can process OoO, in-window pkts, only in-sequence 4th ack * will make the subflow fully established */ -if (likely (READ_ONCE (subflow->fully_established))) { +if (likely (subflow->fully_established)) {/* on passive sockets, check for 3rd ack retransmission * note that msk is always set by subflow_syn_recv_sock() * for mp_join subflows
net/mptcp/protocol.c +1 -1
@@ -3614,7 +3614,7 @@ static void schedule_3rdack_retransmission(struct sock *ssk)struct tcp_sock *tp =tcp_sk (ssk);unsigned long timeout; -if (READ_ONCE (mptcp_subflow_ctx (ssk)->fully_established)) +if (mptcp_subflow_ctx (ssk)->fully_established)return ;/* reschedule with a timeout above RTT, as we must look only for drop */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 891/1250 watchdog: fix hrtimer start when pretimeout is zero
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Arcari <[email protected]>
[ Upstream commit 0fa37512eb747e4ffdcf367274f9e72845f1bca4 ]
Per the watchdog API, a pretimeout value of 0 disables the feature. However, watchdog_hrtimer_pretimeout_start() fails to verify if the pretimeout is non-zero before arming the timer.
This omission inadvertently starts the software pretimeout timer, which could result in the pretimeout handler executing incorrectly when the watchdog timeout is reached.
Fix this by adding a check for wdd->pretimeout before calling hrtimer_start(), ensuring the disabled state is respected.
--- drivers/watchdog/watchdog_hrtimer_pretimeout.c | 1 + 1 file changed, 1 insertion(+)
drivers/watchdog/watchdog_hrtimer_pretimeout.c +1 -0
@@ -30,6 +30,7 @@ void watchdog_hrtimer_pretimeout_init(struct watchdog_device *wdd)void watchdog_hrtimer_pretimeout_start (struct watchdog_device *wdd) {if (!(wdd->info->options &WDIOF_PRETIMEOUT ) && + wdd->pretimeout && !watchdog_pretimeout_invalid (wdd, wdd->pretimeout)) hrtimer_start(&wdd->wd_data->pretimeout_timer, ktime_set(wdd->timeout - wdd->pretimeout, 0),
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 892/1250 watchdog: msc313e: Avoid division by zero
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tzung-Bi Shih <[email protected]>
[ Upstream commit 3c73a37f5e40972ce26d8eeb98e8b938d719b069 ]
clk_get_rate() could return 0. Avoid a division by zero panic.
--- drivers/watchdog/msc313e_wdt.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/watchdog/msc313e_wdt.c +5 -1
@@ -98,6 +98,7 @@ static int msc313e_wdt_probe(struct platform_device *pdev) {struct device *dev = &pdev->dev;struct msc313e_wdt_priv *priv; +unsigned long rate; priv =devm_kzalloc (&pdev->dev,sizeof (*priv),GFP_KERNEL );if (!priv)
@@ -117,7 +118,10 @@ static int msc313e_wdt_probe(struct platform_device *pdev) priv->wdev.ops = &msc313e_wdt_ops, priv->wdev.parent = dev; priv->wdev.min_timeout =MSC313E_WDT_MIN_TIMEOUT ; - priv->wdev.max_timeout =U32_MAX /clk_get_rate (priv->clk); + rate =clk_get_rate (priv->clk); +if (!rate) +return -EINVAL ; + priv->wdev.max_timeout =U32_MAX / rate; priv->wdev.timeout =MSC313E_WDT_DEFAULT_TIMEOUT ;/* If the period is non-zero the WDT is running */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 893/1250 watchdog: msc313e: Fix clock leak and spurious timer in settimeout()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tzung-Bi Shih <[email protected]>
[ Upstream commit 3db30f315935c2fb0d95f46b7a593b5b4d3ec3d0 ]
msc313e_wdt_settimeout() unconditionally calls msc313e_wdt_start() which introduces two severe bugs:
1. If the watchdog is already active, calling start() again will increase the reference count of the clock again. However stop() is only called once, the reference count is unbalance.
2. If the watchdog is stopped, calling settimeout() will start the hardware timer accidentally.
Factor out the register-writing logic into a helper function. Only call it in settimeout() if the watchdog is running. Otherwise, simply update wdev->timeout.
--- drivers/watchdog/msc313e_wdt.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-)
drivers/watchdog/msc313e_wdt.c +16 -6
@@ -32,20 +32,26 @@ struct msc313e_wdt_priv {struct clk *clk; }; +static void msc313e_wdt_set_hw_timeout (struct msc313e_wdt_priv *priv, +unsigned int timeout) +{ +u32 t = timeout *clk_get_rate (priv->clk); + +writew (t &0xffff , priv->base +REG_WDT_MAX_PRD_L ); +writew ((t >>16 ) &0xffff , priv->base +REG_WDT_MAX_PRD_H ); +writew (1 , priv->base +REG_WDT_CLR ); +} +static int msc313e_wdt_start (struct watchdog_device *wdev) {struct msc313e_wdt_priv *priv =watchdog_get_drvdata (wdev); -u32 timeout;int err; err =clk_prepare_enable (priv->clk);if (err)return err; - timeout = wdev->timeout *clk_get_rate (priv->clk); -writew (timeout &0xffff , priv->base +REG_WDT_MAX_PRD_L ); -writew ((timeout >>16 ) &0xffff , priv->base +REG_WDT_MAX_PRD_H ); -writew (1 , priv->base +REG_WDT_CLR ); +msc313e_wdt_set_hw_timeout (priv, wdev->timeout);return 0 ; }
@@ -70,9 +76,13 @@ static int msc313e_wdt_stop(struct watchdog_device *wdev)static int msc313e_wdt_settimeout (struct watchdog_device *wdev,unsigned int new_time) { +struct msc313e_wdt_priv *priv =watchdog_get_drvdata (wdev); + wdev->timeout = new_time; -return msc313e_wdt_start (wdev); +if (watchdog_hw_running (wdev) ||watchdog_active (wdev)) +msc313e_wdt_set_hw_timeout (priv, wdev->timeout); +return 0 ; }static const struct watchdog_info msc313e_wdt_ident = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 894/1250 watchdog: msc313e: Enable clock before accessing hardware registers
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tzung-Bi Shih <[email protected]>
[ Upstream commit 3db2df24e7f11fb117718f6abe326628d91bc500 ]
msc313e_wdt_probe() reads from hardware registers without ensuring the required clock is enabled. Furthermore, if the bootloader leaves the watchdog running, msc313e_wdt_probe() sets WDOG_HW_RUNNING without increasing the clock's reference count.
While the clock is currently supplied as a fixed clock by the device tree (xtal_div2 in arch/arm/boot/dts/sigmastar/mstar-v7.dtsi) which masks the physical issue, this still violates the API usage.
Call clk_prepare_enable() before reading WDT registers. If the WDT is running, leave the clock enabled so the CCF reference counter is balanced.
--- drivers/watchdog/msc313e_wdt.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-)
drivers/watchdog/msc313e_wdt.c +21 -2
@@ -109,6 +109,7 @@ static int msc313e_wdt_probe(struct platform_device *pdev)struct device *dev = &pdev->dev;struct msc313e_wdt_priv *priv;unsigned long rate; +int ret; priv =devm_kzalloc (&pdev->dev,sizeof (*priv),GFP_KERNEL );if (!priv)
@@ -134,9 +135,21 @@ static int msc313e_wdt_probe(struct platform_device *pdev) priv->wdev.max_timeout =U32_MAX / rate; priv->wdev.timeout =MSC313E_WDT_DEFAULT_TIMEOUT ; + ret =clk_prepare_enable (priv->clk); +if (ret) +return ret; +/* If the period is non-zero the WDT is running */ -if (readw (priv->base +REG_WDT_MAX_PRD_L ) | (readw (priv->base +REG_WDT_MAX_PRD_H ) <<16 )) +if (readw (priv->base +REG_WDT_MAX_PRD_L ) | (readw (priv->base +REG_WDT_MAX_PRD_H ) <<16 )) {set_bit (WDOG_HW_RUNNING , &priv->wdev.status); +/* +* Keep the clock enabled. The watchdog core will skip the next +* start() and a future stop() will balance the CCF reference +* count. +*/ + }else { +clk_disable_unprepare (priv->clk); + }watchdog_set_drvdata (&priv->wdev, priv);platform_set_drvdata (pdev, priv);
@@ -145,7 +158,13 @@ static int msc313e_wdt_probe(struct platform_device *pdev)watchdog_stop_on_reboot (&priv->wdev);watchdog_stop_on_unregister (&priv->wdev); -return devm_watchdog_register_device (dev, &priv->wdev); + ret =devm_watchdog_register_device (dev, &priv->wdev); + +/* If the WDT is running and anything goes wrong, disable the clock. */ +if (ret &&test_bit (WDOG_HW_RUNNING , &priv->wdev.status)) +clk_disable_unprepare (priv->clk); + +return ret; }static int __maybe_unused msc313e_wdt_suspend (struct device *dev)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 895/1250 watchdog: msc313e: Fix spurious reset on suspend
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tzung-Bi Shih <[email protected]>
[ Upstream commit 4f6817c9eff4aa1078e16652d82e4b7ef4ffae3e ]
If the hardware watchdog was started by the bootloader and the device is suspended before userspace opens it, the ping worker (from watchdog core) is frozen and the active hardware timer continues running. This leads to a spurious system reset.
Check both watchdog_active() and watchdog_hw_running() when deciding whether to start or stop the watchdog during suspend and resume.
Additionally, call watchdog_stop_ping_on_suspend() to ensure the ping worker be correctly paused and restarted during suspend and resume.
--- drivers/watchdog/msc313e_wdt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/watchdog/msc313e_wdt.c +3 -2
@@ -157,6 +157,7 @@ static int msc313e_wdt_probe(struct platform_device *pdev)watchdog_init_timeout (&priv->wdev, timeout, dev);watchdog_stop_on_reboot (&priv->wdev);watchdog_stop_on_unregister (&priv->wdev); +watchdog_stop_ping_on_suspend (&priv->wdev); ret =devm_watchdog_register_device (dev, &priv->wdev);
@@ -171,7 +172,7 @@ static int __maybe_unused msc313e_wdt_suspend(struct device *dev) {struct msc313e_wdt_priv *priv =dev_get_drvdata (dev); -if (watchdog_active (&priv->wdev)) +if (watchdog_active (&priv->wdev) ||watchdog_hw_running (&priv->wdev))msc313e_wdt_stop (&priv->wdev);return 0 ;
@@ -181,7 +182,7 @@ static int __maybe_unused msc313e_wdt_resume(struct device *dev) {struct msc313e_wdt_priv *priv =dev_get_drvdata (dev); -if (watchdog_active (&priv->wdev)) +if (watchdog_active (&priv->wdev) ||watchdog_hw_running (&priv->wdev))msc313e_wdt_start (&priv->wdev);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 896/1250 watchdog: msc313e: Fix undefined behavior
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tzung-Bi Shih <[email protected]>
[ Upstream commit ab390021b2a3bb4cc875f28a6f76d13de90d7457 ]
readw() returns a u16. Left shifting a u16 by 16 bits yields undefined behavior.
Cast to u32 explicitly before the shift.
--- drivers/watchdog/msc313e_wdt.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
drivers/watchdog/msc313e_wdt.c +11 -1
@@ -32,6 +32,16 @@ struct msc313e_wdt_priv {struct clk *clk; }; +static u32 msc313e_wdt_get_hw_timeout (struct msc313e_wdt_priv *priv) +{ +u16 low, high; + + low =readw (priv->base +REG_WDT_MAX_PRD_L ); + high =readw (priv->base +REG_WDT_MAX_PRD_H ); + +return ((u32 )high <<16 ) | low; +} +static void msc313e_wdt_set_hw_timeout (struct msc313e_wdt_priv *priv,unsigned int timeout) {
@@ -140,7 +150,7 @@ static int msc313e_wdt_probe(struct platform_device *pdev)return ret;/* If the period is non-zero the WDT is running */ -if (readw (priv->base +REG_WDT_MAX_PRD_L ) | (readw (priv->base +REG_WDT_MAX_PRD_H ) <<16 )) { +if (msc313e_wdt_get_hw_timeout (priv)) {set_bit (WDOG_HW_RUNNING , &priv->wdev.status);/* * Keep the clock enabled. The watchdog core will skip the next
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 897/1250 watchdog: msc313e: Sync timeout value if WDT was running at boot
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tzung-Bi Shih <[email protected]>
[ Upstream commit 01504d14e47b34779911250dd308a03f6ef681c2 ]
If WDT was running at boot, the hardware timeout might be set to values other than the final software timeout.
To be consistent, set the hardware timeout to match the final software timeout (i.e., after watchdog_init_timeout()) if WDT was running.
--- drivers/watchdog/msc313e_wdt.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-)
drivers/watchdog/msc313e_wdt.c +9 -8
@@ -145,12 +145,21 @@ static int msc313e_wdt_probe(struct platform_device *pdev) priv->wdev.max_timeout =U32_MAX / rate; priv->wdev.timeout =MSC313E_WDT_DEFAULT_TIMEOUT ; +watchdog_set_drvdata (&priv->wdev, priv); +platform_set_drvdata (pdev, priv); + +watchdog_init_timeout (&priv->wdev, timeout, dev); +watchdog_stop_on_reboot (&priv->wdev); +watchdog_stop_on_unregister (&priv->wdev); +watchdog_stop_ping_on_suspend (&priv->wdev); + ret =clk_prepare_enable (priv->clk);if (ret)return ret;/* If the period is non-zero the WDT is running */ if (msc313e_wdt_get_hw_timeout (priv)) { +msc313e_wdt_set_hw_timeout (priv, priv->wdev.timeout);set_bit (WDOG_HW_RUNNING , &priv->wdev.status);/* * Keep the clock enabled. The watchdog core will skip the next
@@ -161,14 +170,6 @@ static int msc313e_wdt_probe(struct platform_device *pdev)clk_disable_unprepare (priv->clk); } -watchdog_set_drvdata (&priv->wdev, priv); -platform_set_drvdata (pdev, priv); - -watchdog_init_timeout (&priv->wdev, timeout, dev); -watchdog_stop_on_reboot (&priv->wdev); -watchdog_stop_on_unregister (&priv->wdev); -watchdog_stop_ping_on_suspend (&priv->wdev); - ret =devm_watchdog_register_device (dev, &priv->wdev);/* If the WDT is running and anything goes wrong, disable the clock. */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 898/1250 net: dsa: lantiq_gswip: fix GSWIP_MDIO_PHY_FCONTX_EN value
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jan Havran (Advantech Czech) <[email protected]>
[ Upstream commit 59fb389ad6bf50916189e56dafcd225ab977f874 ]
Per the GSW145 data sheet, the FCONTX (bits 8:7) and FCONRX (bits 6:5) flow-control fields of the PHY_ADDR_n register both encode 00 = AUTO, 01 = EN, 10 = reserved, 11 = DIS. GSWIP_MDIO_PHY_FCONTX_EN was 0x0100, i.e. field value 10 (the reserved encoding), instead of 0x0080 (01 = EN); FCONRX_EN is already 0x0020 (01). Enabling tx flow control therefore wrote the reserved value.
Set FCONTX_EN to 0x0080. The register is shared by all supported parts.
--- drivers/net/dsa/lantiq/lantiq_gswip.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/dsa/lantiq/lantiq_gswip.h +1 -1
@@ -41,7 +41,7 @@#define GSWIP_MDIO_PHY_FDUP_DIS 0x0600#define GSWIP_MDIO_PHY_FCONTX_MASK 0x0180#define GSWIP_MDIO_PHY_FCONTX_AUTO 0x0000 -#define GSWIP_MDIO_PHY_FCONTX_EN 0x0100 +#define GSWIP_MDIO_PHY_FCONTX_EN 0x0080#define GSWIP_MDIO_PHY_FCONTX_DIS 0x0180#define GSWIP_MDIO_PHY_FCONRX_MASK 0x0060#define GSWIP_MDIO_PHY_FCONRX_AUTO 0x0000
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 899/1250 net/micrel: Fix typos in micrel driver code comments
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yicong Hui <[email protected]>
[ Upstream commit c2b733da93bf607d6c6f925b4d40598e6bb516be ]
Fix various typos and misspellings in code comments in the drivers/net/ethernet/micrel directory
Stable-dep-of: 66ef5adb7544 ("net: ks8851: Fix receiver error in 100BASE-TX mode following software power-down")
--- drivers/net/ethernet/micrel/ks8842.c | 4 ++-- drivers/net/ethernet/micrel/ks8851_common.c | 2 +- drivers/net/ethernet/micrel/ks8851_spi.c | 4 ++-- drivers/net/ethernet/micrel/ksz884x.c | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-)
drivers/net/ethernet/micrel/ks8842.c +2 -2
@@ -242,7 +242,7 @@ static void ks8842_reset(struct ks8842_adapter *adapter)msleep (10 );iowrite16 (0 , adapter->hw_addr +REG_GRR ); }else { -/* The KS8842 goes haywire when doing softare reset +/* The KS8842 goes haywire when doing software reset * a work around in the timberdale IP is implemented to * do a hardware reset instead ks8842_write16(adapter, 3, 1, REG_GRR);
@@ -312,7 +312,7 @@ static void ks8842_reset_hw(struct ks8842_adapter *adapter)/* aggressive back off in half duplex */ ks8842_enable_bits (adapter,32 ,1 <<8 ,REG_SGCR1 ); -/* enable no excessive collison drop */ +/* enable no excessive collision drop */ ks8842_enable_bits (adapter,32 ,1 <<3 ,REG_SGCR2 );/* Enable port 1 force flow control / back pressure / transmit / recv */
drivers/net/ethernet/micrel/ks8851_common.c +1 -1
@@ -477,7 +477,7 @@ static int ks8851_net_open(struct net_device *dev)* ks8851_net_stop - close network device * @dev: The device being closed. * -* Called to close down a network device which has been active. Cancell any +* Called to close down a network device which has been active. Cancel any * work, shutdown the RX and TX process and then place the chip into a low * power state whilst it is not being used. */
drivers/net/ethernet/micrel/ks8851_spi.c +2 -2
@@ -39,7 +39,7 @@ static int msg_enable;* * The @lock ensures that the chip is protected when certain operations are * in progress. When the read or write packet transfer is in progress, most -* of the chip registers are not ccessible until the transfer is finished and +* of the chip registers are not accessible until the transfer is finished and * the DMA has been de-asserted. */ struct ks8851_net_spi {
@@ -296,7 +296,7 @@ static unsigned int calc_txlen(unsigned int len)/** * ks8851_tx_work - process tx packet(s) -* @work: The work strucutre what was scheduled. +* @work: The work structure what was scheduled. * * This is called when a number of packets have been scheduled for * transmission and need to be sent to the device.
drivers/net/ethernet/micrel/ksz884x.c +2 -2
@@ -1166,7 +1166,7 @@ struct ksz_port_info {* @tx_cfg: Cached transmit control settings. * @rx_cfg: Cached receive control settings. * @intr_mask: Current interrupt mask. -* @intr_set: Current interrup set. +* @intr_set: Current interrupt set. * @intr_blocked: Interrupt blocked. * @rx_desc_info: Receive descriptor information. * @tx_desc_info: Transmit descriptor information.
@@ -2096,7 +2096,7 @@ static void sw_dis_prio_rate(struct ksz_hw *hw, int port) }/** -* sw_init_prio_rate - initialize switch prioirty rate +* sw_init_prio_rate - initialize switch priority rate * @hw: The hardware instance. * * This routine initializes the priority rate function of the switch.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 900/1250 net: ks8851: Fix receiver error in 100BASE-TX mode following software power-down
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marek Vasut <[email protected]>
[ Upstream commit 66ef5adb75446627f8b6c26cd04f2adc86d4de56 ]
KSZ8851 errata sheet DS80000716D-page 4 Module 3 [1] states that, when issuing a software power-down (PMECR[1:0] = 10) followed by a power-on (PMECR[1:0] = 00), the receiver circuit can fail to start properly preventing communication. The Transmitter will still send data, but no data will be received.
The errata sheet also includes a workaround, which states that, it is recommended that the software power-down feature not be used.
Implement that workaround and drop the entry into software power-down mode. The ks8851_write_mac_addr() calls entry into normal power-on mode at the very beginning of the function, therefore dropping the second call to enter software power-down mode is sufficient here. The ks8851_net_stop() can only be called after ks8851_net_start() was already called, and ks8851_net_start() also makes the MAC enter normal power-on mode, therefore it is also fine to drop the call to enter software power-down mode from ks8851_net_stop().
This will lead to a slight increase in power consumption, but it also fixes a sporadic reliability problem on at least KSZ8851-16MLL, which is where the problem was reported and this fix was tested.
[1] https://ww1.microchip.com/downloads/en/DeviceDoc/80000716D.pdf
--- drivers/net/ethernet/micrel/ks8851_common.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-)
drivers/net/ethernet/micrel/ks8851_common.c +1 -7
@@ -143,9 +143,6 @@ static int ks8851_write_mac_addr(struct net_device *dev)ks8851_wrreg16 (ks,KS_MAR (i), val); } -if (!netif_running (dev)) -ks8851_set_powermode (ks,PMECR_PM_SOFTDOWN ); -ks8851_unlock (ks);return 0 ;
@@ -478,8 +475,7 @@ static int ks8851_net_open(struct net_device *dev)* @dev: The device being closed. * * Called to close down a network device which has been active. Cancel any -* work, shutdown the RX and TX process and then place the chip into a low -* power state whilst it is not being used. +* work and shutdown the RX and TX process. */ static int ks8851_net_stop (struct net_device *dev) {
@@ -506,8 +502,6 @@ static int ks8851_net_stop(struct net_device *dev)/* shutdown TX process */ ks8851_wrreg16 (ks,KS_TXCR ,0x0000 ); -/* set powermode to soft power down to save power */ -ks8851_set_powermode (ks,PMECR_PM_SOFTDOWN );ks8851_unlock (ks);/* ensure any queued tx buffers are dumped */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 901/1250 hwmon: (corsair-cpro) Create debugfs entries after hwmon registration
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <[email protected]>
[ Upstream commit 508baf1713f32f287bfb4f85d759403ec8ba35a3 ]
ccp_debugfs_init() registers debugfs files whose private data is the devm allocated ccp. It runs before hwmon_device_register_with_info(), so when that registration fails, ccp_probe() returns with the files still in place. The HID core then frees ccp, and ccp_remove() is not called for a failed probe, so nothing removes them later either. Reading one of the files dereferences the freed pointer.
Create the debugfs entries only after the hwmon device has been registered, so no failing path can leave them behind.
The two version queries stay where they are. They send USB commands without holding ccp->mutex, which is only safe as long as nothing else can call send_usb_cmd(); once the hwmon device is registered its callbacks can do so concurrently. Only the debugfs creation moves, and it is told which queries succeeded.
--- drivers/hwmon/corsair-cpro.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-)
drivers/hwmon/corsair-cpro.c +13 -7
@@ -566,21 +566,18 @@ static int bootloader_show(struct seq_file *seqf, void *unused) }DEFINE_SHOW_ATTRIBUTE (bootloader); -static void ccp_debugfs_init (struct ccp_device *ccp) +static void ccp_debugfs_init (struct ccp_device *ccp,bool fw_valid,bool bl_valid) {char name[32 ]; -int ret;scnprintf (name,sizeof (name),"corsaircpro-%s" ,dev_name (&ccp->hdev->dev)); ccp->debugfs =debugfs_create_dir (name,NULL ); - ret =get_fw_version (ccp); -if (!ret) +if (fw_valid)debugfs_create_file ("firmware_version" ,0444 , ccp->debugfs, ccp, &firmware_fops); - ret =get_bl_version (ccp); -if (!ret) +if (bl_valid)debugfs_create_file ("bootloader_version" ,0444 , ccp->debugfs, ccp, &bootloader_fops); }
@@ -588,6 +585,7 @@ static void ccp_debugfs_init(struct ccp_device *ccp)static int ccp_probe (struct hid_device *hdev,const struct hid_device_id *id) {struct ccp_device *ccp; +bool fw_valid, bl_valid;int ret; ccp =devm_kzalloc (&hdev->dev,sizeof (*ccp),GFP_KERNEL );
@@ -632,7 +630,13 @@ static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id)if (ret) goto out_hw_close; -ccp_debugfs_init (ccp); +/* +* Query the versions before registering the hwmon device: they send +* USB commands without holding ccp->mutex, which is only safe while +* nothing else can call send_usb_cmd(). +*/ + fw_valid = !get_fw_version (ccp); + bl_valid = !get_bl_version (ccp); ccp->hwmon_dev =hwmon_device_register_with_info (&hdev->dev,"corsaircpro" , ccp, &ccp_chip_info,NULL );
@@ -641,6 +645,8 @@ static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id) goto out_hw_close; } +ccp_debugfs_init (ccp, fw_valid, bl_valid); +return 0 ; out_hw_close:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 902/1250 hwmon: (gpio-fan) take fan_data->lock in gpio_fan_shutdown()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cong Nguyen <[email protected]>
[ Upstream commit bb2424c3502cc72292eedade46960c331d5f28fb ]
set_fan_speed() writes the control GPIOs one bit at a time. Every other caller locks around it; gpio_fan_shutdown() doesn't. If it races a locked caller, the GPIO writes can interleave and leave the fan at a speed neither caller asked for.
--- drivers/hwmon/gpio-fan.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/hwmon/gpio-fan.c +4 -1
@@ -604,8 +604,11 @@ static void gpio_fan_shutdown(struct platform_device *pdev) {struct gpio_fan_data *fan_data =platform_get_drvdata (pdev); -if (fan_data->gpios) +if (fan_data->gpios) { +mutex_lock (&fan_data->lock);set_fan_speed (fan_data,0 ); +mutex_unlock (&fan_data->lock); + } }static int gpio_fan_runtime_suspend (struct device *dev)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 903/1250 hwmon: (aspeed-pwm-tacho) Propagate reset deassert errors
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit 09a9e1746a87845d7d8e2b4e23bb613306effdff ]
aspeed_pwm_tacho_probe() installs its reset cleanup action and configures the
controller after an unchecked reset deassertion.
Stop probing when the reset controller rejects the transition, before the hwmon device becomes visible.
--- drivers/hwmon/aspeed-pwm-tacho.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/hwmon/aspeed-pwm-tacho.c +3 -1
@@ -933,7 +933,9 @@ static int aspeed_pwm_tacho_probe(struct platform_device *pdev) "missing or invalid reset controller device tree entry");return PTR_ERR (priv->rst); } -reset_control_deassert (priv->rst); + ret =reset_control_deassert (priv->rst); +if (ret) +return ret; ret =devm_add_action_or_reset (dev, aspeed_pwm_tacho_remove, priv);if (ret)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 904/1250 hwmon: (corsair-cpro) Remove debugfs entries when probe fails
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <[email protected]>
[ Upstream commit 4ee875c423c66c45d7ef7bbff403cd0e3971e0a2 ]
ccp_debugfs_init() registers debugfs files whose private data is the devm allocated ccp. If hwmon_device_register_with_info() fails right after it, ccp_probe() returns without removing them: the HID core then frees ccp, and ccp_remove() is not called for a failed probe, so the files stay behind. Reading one of them dereferences the freed pointer.
Remove the debugfs entries on that error path. debugfs_remove_recursive() waits for readers already inside the show callbacks, so ccp is no longer reachable through debugfs by the time probe returns.
--- drivers/hwmon/corsair-cpro.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/hwmon/corsair-cpro.c +3 -1
@@ -642,13 +642,15 @@ static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id) ccp, &ccp_chip_info, NULL);if (IS_ERR (ccp->hwmon_dev)) { ret =PTR_ERR (ccp->hwmon_dev); - goto out_hw_close; + goto out_debugfs_remove; }ccp_debugfs_init (ccp, fw_valid, bl_valid);return 0 ; +out_debugfs_remove: +debugfs_remove_recursive (ccp->debugfs); out_hw_close:hid_hw_close (hdev);hid_device_io_stop (hdev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 905/1250 hwmon: (nct6694) do not expose enable on DTIN temperature channels
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ali Ahmet Memis <[email protected]>
[ Upstream commit c88a6338ae485e4d6210cc74cdb7664d6476c925 ]
The driver registers 26 temperature channels, all advertising HWMON_T_ENABLE, and indexes the enable bitmap with the raw channel:
data->hwmon_en.tin_en[channel / 8] |= BIT(channel % 8);
tin_en is two bytes and only covers the 5 THR and 5 TDP channels (index 0-9). The 16 DTIN channels (index 10-25) are enabled by the firmware and were never meant to carry an enable bit. Because the control structure is packed, writing temp17_enable and above indexes past tin_en into the fin_en bytes that follow it, so it toggles fan enable state instead; nct6694_hwmon_init() then sends the whole structure back to the device, and reads report fan state as temperature state. It stays within the structure, so this is not a memory safety problem, but on a board that uses the fan channels it is not harmless.
Give the DTIN channels a temperature config without HWMON_T_ENABLE so the core never creates their enable attribute. The enable path is then reachable only for the first 10 channels, which stay within tin_en, and fin_en is left alone. The DTIN input and limit attributes are unchanged.
--- drivers/hwmon/nct6694-hwmon.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-)
drivers/hwmon/nct6694-hwmon.c +19 -16
@@ -159,6 +159,9 @@ static inline s8 temp_to_reg(long val)#define NCT6694_HWMON_TEMP_CONFIG (HWMON_T_INPUT | HWMON_T_ENABLE | \ HWMON_T_MAX | HWMON_T_MAX_HYST | \ HWMON_T_MAX_ALARM) +#define NCT6694_HWMON_DTIN_CONFIG (HWMON_T_INPUT | \ + HWMON_T_MAX | HWMON_T_MAX_HYST | \ + HWMON_T_MAX_ALARM)#define NCT6694_HWMON_FAN_CONFIG (HWMON_F_INPUT | HWMON_F_ENABLE | \ HWMON_F_MIN | HWMON_F_MIN_ALARM)#define NCT6694_HWMON_PWM_CONFIG (HWMON_PWM_INPUT | HWMON_PWM_ENABLE | \
@@ -193,22 +196,22 @@ static const struct hwmon_channel_info *nct6694_info[] = {NCT6694_HWMON_TEMP_CONFIG ,/* TDP2 */ NCT6694_HWMON_TEMP_CONFIG ,/* TDP3 */ NCT6694_HWMON_TEMP_CONFIG ,/* TDP4 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN0 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN1 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN2 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN3 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN4 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN5 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN6 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN7 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN8 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN9 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN10 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN11 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN12 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN13 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN14 */ - NCT6694_HWMON_TEMP_CONFIG), /* DTIN15 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN0 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN1 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN2 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN3 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN4 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN5 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN6 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN7 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN8 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN9 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN10 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN11 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN12 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN13 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN14 */ + NCT6694_HWMON_DTIN_CONFIG), /* DTIN15 */ HWMON_CHANNEL_INFO(fan, NCT6694_HWMON_FAN_CONFIG, /* FIN0 */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 906/1250 octeontx2-pf: reset HTB scheduler topology before freeing queues
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ratheesh Kannoth <[email protected]>
[ Upstream commit ef39fca8508597fa565cf2be72a884a712fb98af ]
HTB offload programs NIX_AF_TLxX_TOPOLOGY on QoS-allocated scheduler queues via otx2_qos_txschq_set_parent_topology(), but teardown freed those queues without clearing TOPOLOGY. The AF only restores PARENT and SCHEDULE on free, so PRIO_ANCHOR/RR_PRIO settings can survive in the shared scheduler pool and affect later allocations.
Add otx2_qos_reset_schq_topology() and otx2_qos_free_hw_schq() to zero TL4 through TL2 TOPOLOGY before each schq is returned to the AF during hierarchy teardown and cfg rollback. Skip the aggregation level (TL1):
it is a per-tx-link queue shared by the PF, default Tx hierarchy and VFs, and is not freed back to the AF by nix_txschq_free_one().
--- .../net/ethernet/marvell/octeontx2/nic/qos.c | 60 +++++++++++++++++-- 1 file changed, 55 insertions(+), 5 deletions(-)
drivers/net/ethernet/marvell/octeontx2/nic/qos.c +55 -5
@@ -235,13 +235,63 @@ static int otx2_qos_txschq_set_parent_topology(struct otx2_nic *pfvf,return rc; } +static int otx2_qos_reset_schq_topology (struct otx2_nic *pfvf,u16 lvl, +u16 schq) +{ +struct mbox *mbox = &pfvf->mbox; +struct nix_txschq_config *cfg; +int rc; + +if (lvl <NIX_TXSCH_LVL_TL4 || lvl >=NIX_TXSCH_LVL_TL1 ) +return 0 ; + +mutex_lock (&mbox->lock); + + cfg =otx2_mbox_alloc_msg_nix_txschq_cfg (mbox); +if (!cfg) { +mutex_unlock (&mbox->lock); +return -ENOMEM ; + } + + cfg->lvl = lvl; + cfg->num_regs =1 ; + +if (lvl ==NIX_TXSCH_LVL_TL4 ) + cfg->reg[0 ] =NIX_AF_TL4X_TOPOLOGY (schq); +else if (lvl ==NIX_TXSCH_LVL_TL3 ) + cfg->reg[0 ] =NIX_AF_TL3X_TOPOLOGY (schq); +else if (lvl ==NIX_TXSCH_LVL_TL2 ) + cfg->reg[0 ] =NIX_AF_TL2X_TOPOLOGY (schq); + + cfg->regval[0 ] =0 ; + + rc =otx2_sync_mbox_msg (mbox); + +mutex_unlock (&mbox->lock); + +return rc; +} + +static void otx2_qos_free_hw_schq (struct otx2_nic *pfvf,u16 lvl,u16 schq) +{ +int err; + + err =otx2_qos_reset_schq_topology (pfvf, lvl, schq); +if (err) +netdev_warn (pfvf->netdev, +"QoS: failed to reset topology for schq %u at level %u: %d\n" , + schq, lvl, err); + +otx2_txschq_free_one (pfvf, lvl, schq); +} +static void otx2_qos_free_hw_node_schq (struct otx2_nic *pfvf,struct otx2_qos_node *parent) {struct otx2_qos_node *node;list_for_each_entry_reverse (node, &parent->child_schq_list, list) -otx2_txschq_free_one (pfvf, node->level, node->schq); +otx2_qos_free_hw_schq (pfvf, node->level, node->schq); } static void otx2_qos_free_hw_node(struct otx2_nic *pfvf,
@@ -252,7 +302,7 @@ static void otx2_qos_free_hw_node(struct otx2_nic *pfvf,list_for_each_entry_safe (node, tmp, &parent->child_list, list) {otx2_qos_free_hw_node (pfvf, node);otx2_qos_free_hw_node_schq (pfvf, node); -otx2_txschq_free_one (pfvf, node->level, node->schq); +otx2_qos_free_hw_schq (pfvf, node->level, node->schq); } }
@@ -266,7 +316,7 @@ static void otx2_qos_free_hw_cfg(struct otx2_nic *pfvf,otx2_qos_free_hw_node_schq (pfvf, node);/* free node hw mappings */ -otx2_txschq_free_one (pfvf, node->level, node->schq); +otx2_qos_free_hw_schq (pfvf, node->level, node->schq);mutex_unlock (&pfvf->qos.qos_lock); }
@@ -913,7 +963,7 @@ static void otx2_qos_free_cfg(struct otx2_nic *pfvf, struct otx2_qos_cfg *cfg)for (lvl =0 ; lvl <NIX_TXSCH_LVL_CNT ; lvl++) {for (idx =0 ; idx < cfg->schq[lvl]; idx++) { schq = cfg->schq_list[lvl][idx]; -otx2_txschq_free_one (pfvf, lvl, schq); +otx2_qos_free_hw_schq (pfvf, lvl, schq); } }
@@ -921,7 +971,7 @@ static void otx2_qos_free_cfg(struct otx2_nic *pfvf, struct otx2_qos_cfg *cfg)for (idx =0 ; idx < cfg->schq_contig[lvl]; idx++) {if (cfg->schq_index_used[lvl][idx]) { schq = cfg->schq_contig_list[lvl][idx]; -otx2_txschq_free_one (pfvf, lvl, schq); +otx2_qos_free_hw_schq (pfvf, lvl, schq); } } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 907/1250 vxlan: initialize _md in vxlan_xmit_one()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit be83178bfc44588f6e3adb827ed874c683193466 ]
If a VXLAN device is configured with both VXLAN_F_COLLECT_METADATA and VXLAN_F_GBP, and a packet is transmitted through it using an external ip_tunnel_info that lacks the IP_TUNNEL_VXLAN_OPT_BIT flag, md is left pointing to the uninitialized _md stack variable:
if (test_bit(IP_TUNNEL_VXLAN_OPT_BIT, info->key.tun_flags)) {
if (info->options_len < sizeof(*md))
goto drop;
md = ip_tunnel_info_opts(info);
}Because IP_TUNNEL_VXLAN_OPT_BIT is not set, md is not updated and remains pointing to _md. Later, vxlan_build_skb() is called with md, which eventually calls vxlan_build_gbp_hdr():
if (vxflags & VXLAN_F_GBP)
vxlan_build_gbp_hdr(vxh, md);
Inside vxlan_build_gbp_hdr(), md->gbp is read:
if (!md->gbp)
return;
gbp = (struct vxlanhdr_gbp *)vxh;
...
if (md->gbp & VXLAN_GBP_DONT_LEARN)
gbp->dont_learn = 1;If the stack contains garbage, this causes:
1) VXLAN_HF_GBP flag to be spuriously set in the VXLAN header.
2) gbp->dont_learn and gbp->policy_applied to be set from stack bits.
3) gbp->policy_id to receive 16 bits of uninitialized kernel stack data, leaking it onto the wire.
Fix this by zero-initializing _md. If IP_TUNNEL_VXLAN_OPT_BIT is not present, md->gbp remains 0, and vxlan_build_gbp_hdr() returns early without modifying the VXLAN header.
--- drivers/net/vxlan/vxlan_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/vxlan/vxlan_core.c +1 -1
@@ -2369,7 +2369,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,struct ip_tunnel_key key;struct vxlan_dev *vxlan =netdev_priv (dev);const struct iphdr *old_iph; -struct vxlan_metadata _md; +struct vxlan_metadata _md = {};struct vxlan_metadata *md = &_md;unsigned int pkt_len = skb->len;__be16 src_port =0 , dst_port;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 908/1250 ppp_synctty: ensure a writeable skb header
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qingfang Deng <[email protected]>
[ Upstream commit 8aaeb56aff2a557a88f83ae866da2c91ad247e59 ]
ppp_sync_txmunge() checks headroom before prepending the address and control bytes, but does not ensure that the skb header is writable. A received skb can reach this function through PPP channel bridging without passing through ppp_start_xmit(), which calls skb_cow_head().
For example, a PPPoE frame may share its buffer with a clone queued to an AF_PACKET socket. If it is bridged to a synchronous tty channel, the address/control bytes can overwrite data still visible to that socket.
Use skb_cow_head() to ensure both sufficient headroom and a writable header.
--- drivers/net/ppp/ppp_synctty.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-)
drivers/net/ppp/ppp_synctty.c +3 -11
@@ -457,17 +457,9 @@ ppp_sync_txmunge(struct syncppp *ap, struct sk_buff *skb)/* prepend address/control fields if necessary */ if ((ap->flags &SC_COMP_AC ) ==0 || islcp) { -if (skb_headroom (skb) <2 ) { -struct sk_buff *npkt =dev_alloc_skb (skb->len +2 ); -if (npkt ==NULL ) { -kfree_skb (skb); -return NULL ; - } -skb_reserve (npkt,2 ); -skb_copy_from_linear_data (skb, -skb_put (npkt, skb->len), skb->len); -consume_skb (skb); - skb = npkt; +if (skb_cow_head (skb,2 )) { +kfree_skb (skb); +return NULL ; }skb_push (skb,2 ); skb->data[0 ] =PPP_ALLSTATIONS ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 909/1250 net: stmmac: initialize ptp_lock at probe time
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <[email protected]>
[ Upstream commit 0338c68e22abd2ee509ec2e32508a50896618c32 ]
priv->ptp_lock is only initialized in stmmac_ptp_register(), which runs during __stmmac_open(). However, the lock is also used while the interface is down and has never been opened: tc_taprio_configure() invokes the PTP gettime64() callback to compute the EST base time when offloading a TAPRIO schedule, and stmmac_get_time() takes priv->ptp_lock. Using an uninitialized rwlock is undefined behaviour. Move the rwlock_init() to __stmmac_dvr_probe(), together with the other private locks, so that ptp_lock is always valid regardless of the interface state.
--- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 1 + drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +1 -0
@@ -7647,6 +7647,7 @@ int stmmac_dvr_probe(struct device *device,stmmac_napi_add (ndev);mutex_init (&priv->lock); +rwlock_init (&priv->ptp_lock);stmmac_fpe_init (priv);
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c +0 -1
@@ -362,7 +362,6 @@ void stmmac_ptp_register(struct stmmac_priv *priv)if (priv->plat->crosststamp) priv->ptp_clock_ops.getcrosststamp = stmmac_getcrosststamp; -rwlock_init (&priv->ptp_lock);mutex_init (&priv->aux_ts_lock); priv->ptp_clock = ptp_clock_register(&priv->ptp_clock_ops,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 910/1250 devlink: Refactor resource functions to be generic
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Or Har-Toov <[email protected]>
[ Upstream commit 7be3163c49b24bf923d32f333096963159e03a14 ]
Currently the resource functions take devlink pointer as parameter and take the resource list from there.
Allow resource functions to work with other resource lists that will be added in next patches and not only with the devlink's resource list.
Stable-dep-of: 7f26a5e8040b ("net/mlx5e: Move representor vnic reporter to eswitch devlink port")
--- include/net/devlink.h | 2 +- net/devlink/resource.c | 114 ++++++++++++++++++++++++++--------------- 2 files changed, 73 insertions(+), 43 deletions(-)
include/net/devlink.h +1 -1
@@ -1828,7 +1828,7 @@ int devl_resource_register(struct devlink *devlink,u64 resource_size, u64 resource_id, u64 parent_resource_id, - const struct devlink_resource_size_params *size_params); + const struct devlink_resource_size_params *params);void devl_resources_unregister (struct devlink *devlink);void devlink_resources_unregister (struct devlink *devlink); int devl_resource_size_get(struct devlink *devlink,
net/devlink/resource.c +72 -42
192 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 911/1250 devlink: Add port-level resource registration infrastructure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Or Har-Toov <[email protected]>
[ Upstream commit 6f38acfed5edb398201d9ff127919745cbb331a1 ]
The current devlink resource infrastructure supports only device-level resources. Some hardware resources are associated with specific ports rather than the entire device, and today we have no way to show resource per-port.
Add support for registering resources at the port level.
Stable-dep-of: 7f26a5e8040b ("net/mlx5e: Move representor vnic reporter to eswitch devlink port")
--- include/net/devlink.h | 8 ++++++++ net/devlink/port.c | 2 ++ net/devlink/resource.c | 43 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+)
include/net/devlink.h +8 -0
@@ -129,6 +129,7 @@ struct devlink_rate {struct devlink_port {struct list_head list;struct list_head region_list; +struct list_head resource_list;struct devlink *devlink;const struct devlink_port_ops *ops;unsigned int index;
@@ -1834,6 +1835,13 @@ void devlink_resources_unregister(struct devlink *devlink);int devl_resource_size_get (struct devlink *devlink,u64 resource_id,u64 *p_resource_size); +int +devl_port_resource_register (struct devlink_port *devlink_port, +const char *resource_name, +u64 resource_size,u64 resource_id, +u64 parent_resource_id, +const struct devlink_resource_size_params *params); +void devl_port_resources_unregister (struct devlink_port *devlink_port);int devl_dpipe_table_resource_set (struct devlink *devlink,const char *table_name,u64 resource_id,u64 resource_units);
net/devlink/port.c +2 -0
@@ -1024,6 +1024,7 @@ void devlink_port_init(struct devlink *devlink,return ; devlink_port->devlink = devlink;INIT_LIST_HEAD (&devlink_port->region_list); +INIT_LIST_HEAD (&devlink_port->resource_list); devlink_port->initialized = true; }EXPORT_SYMBOL_GPL (devlink_port_init);
@@ -1041,6 +1042,7 @@ EXPORT_SYMBOL_GPL(devlink_port_init);void devlink_port_fini (struct devlink_port *devlink_port) {WARN_ON (!list_empty (&devlink_port->region_list)); +WARN_ON (!list_empty (&devlink_port->resource_list)); }EXPORT_SYMBOL_GPL (devlink_port_fini);
net/devlink/resource.c +43 -0
46 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 912/1250 net/mlx5: Register SF resource on PF port representor
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Or Har-Toov <[email protected]>
[ Upstream commit 4be8326d817e6d47f8446938408bb2001b799340 ]
The device-level "resource show" displays max_local_SFs and max_external_SFs without indicating which port each resource belongs to. Users cannot determine the controller number and pfnum associated with each SF pool.
Register max_SFs resource on the host PF representor port to expose per-port SF limits. Users can correlate the port resource with the controller number and pfnum shown in 'devlink port show'.
Future patches will introduce an ECPF that manages multiple PFs, where each PF has its own SF pool.
Example usage:
$ devlink resource show pci/0000:03:00.0/196608
pci/0000:03:00.0/196608:
name max_SFs size 20 unit entry $ devlink port show pci/0000:03:00.0/196608
pci/0000:03:00.0/196608: type eth netdev pf0hpf flavour pcipf
controller 1 pfnum 0 external true splittable false
function:
hw_addr b8:3f:d2:e1:8f:dc roce enable max_io_eqs 120We can create up to 20 SFs over devlink port pci/0000:03:00.0/196608, with pfnum 0 and controller 1.
Stable-dep-of: 7f26a5e8040b ("net/mlx5e: Move representor vnic reporter to eswitch devlink port")
--- .../net/ethernet/mellanox/mlx5/core/devlink.h | 4 ++ .../mellanox/mlx5/core/esw/devlink_port.c | 37 +++++++++++++++++++ 2 files changed, 41 insertions(+)
drivers/net/ethernet/mellanox/mlx5/core/devlink.h +4 -0
@@ -14,6 +14,10 @@ enum mlx5_devlink_resource_id { MLX5_ID_RES_MAX = __MLX5_ID_RES_MAX - 1, }; +enum mlx5_devlink_port_resource_id { +MLX5_DL_PORT_RES_MAX_SFS =1 , +}; +enum mlx5_devlink_param_id {MLX5_DEVLINK_PARAM_ID_BASE =DEVLINK_PARAM_GENERIC_ID_MAX ,MLX5_DEVLINK_PARAM_ID_FLOW_STEERING_MODE ,
drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c +37 -0
@@ -3,6 +3,7 @@#include <linux/mlx5/driver.h> #include "eswitch.h" +#include "devlink.h" static void mlx5_esw_get_port_parent_id (struct mlx5_core_dev *dev,struct netdev_phys_item_id *ppid)
@@ -160,6 +161,32 @@ static const struct devlink_port_ops mlx5_esw_dl_sf_port_ops = { .port_fn_max_io_eqs_set = mlx5_devlink_port_fn_max_io_eqs_set, }; +static int mlx5_esw_devlink_port_res_register (struct mlx5_eswitch *esw, +struct devlink_port *dl_port) +{ +struct devlink_resource_size_params size_params; +struct mlx5_core_dev *dev = esw->dev; +u16 max_sfs, sf_base_id; +int err; + + err =mlx5_esw_sf_max_hpf_functions (dev, &max_sfs, &sf_base_id); +if (err) +return err; + +devlink_resource_size_params_init (&size_params, max_sfs, max_sfs,1 , +DEVLINK_RESOURCE_UNIT_ENTRY ); + +return devl_port_resource_register (dl_port,"max_SFs" , max_sfs, +MLX5_DL_PORT_RES_MAX_SFS , +DEVLINK_RESOURCE_ID_PARENT_TOP , + &size_params); +} + +static void mlx5_esw_devlink_port_res_unregister (struct devlink_port *dl_port) +{ +devl_port_resources_unregister (dl_port); +} +int mlx5_esw_offloads_devlink_port_register (struct mlx5_eswitch *esw,struct mlx5_vport *vport) {struct mlx5_core_dev *dev = esw->dev;
@@ -191,6 +218,15 @@ int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, struct mlxif (err) goto rate_err; +if (vport_num ==MLX5_VPORT_PF ) { + err =mlx5_esw_devlink_port_res_register (esw, + &dl_port->dl_port); +if (err) +mlx5_core_dbg (dev, +"Failed to register port resources: %d\n" , + err); + } +return 0 ; rate_err:
@@ -205,6 +241,7 @@ void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_vport *vport)if (!vport->dl_port)return ; dl_port = vport->dl_port; +mlx5_esw_devlink_port_res_unregister (&dl_port->dl_port);mlx5_esw_qos_vport_update_parent (vport,NULL ,NULL );devl_rate_leaf_destroy (&dl_port->dl_port);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 913/1250 net/mlx5e: Move representor vnic reporter to eswitch devlink port
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Carolina Jubran <[email protected]>
[ Upstream commit 7f26a5e8040b4957ef4dbdfcde6cc7ba2db53937 ]
The representor vnic devlink health reporter is created and destroyed along the representor netdev (un)load path, which is not serialized by the devlink instance lock. Destroying the reporter from there triggers a devl_assert_locked() splat on driver unbind:
WARNING: net/devlink/core.c:259 at devl_assert_locked+0x54/0x70, CPU#2: bash/3758 Modules linked in: mlx5_vdpa vringh vdpa mlx5_ib mlx5_fwctl mlx5_core ... CPU: 2 UID: 0 PID: 3758 Comm: bash Tainted: G W 6.19.0+ #1 PREEMPT Tainted: [W]=WARN Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), ... RIP: 0010:devl_assert_locked+0x54/0x70 Call Trace: <TASK> devl_health_reporter_destroy+0x3a/0x1b0 mlx5e_vport_rep_unload+0x12d/0x2b0 [mlx5_core] mlx5_eswitch_unregister_vport_reps+0x1b8/0x220 [mlx5_core] ? __esw_offloads_unload_rep+0x190/0x190 [mlx5_core] ? kernfs_remove_by_name_ns+0xc3/0xf0 device_release_driver_internal+0x3b2/0x560 unbind_store+0xce/0xf0
Move the reporter's lifecycle to the eswitch devlink port (un)register paths, which are already serialized by the devlink instance lock, and store the handle on mlx5_devlink_port. Use the port's mlx5_vport as the reporter priv since the diagnose callback only needs a device handle and a vport number, and mlx5_vport carries both and is initialized before any representor driver probes.
--- .../net/ethernet/mellanox/mlx5/core/en_rep.c | 52 +------------------ .../net/ethernet/mellanox/mlx5/core/en_rep.h | 1 - .../mellanox/mlx5/core/esw/devlink_port.c | 37 +++++++++++++ .../net/ethernet/mellanox/mlx5/core/eswitch.h | 1 + 4 files changed, 39 insertions(+), 52 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +1 -51
@@ -57,7 +57,6 @@#include "lib/vxlan.h" #define CREATE_TRACE_POINTS #include "diag/en_rep_tracepoint.h" -#include "diag/reporter_vnic.h" #include "en_accel/ipsec.h" #include "en/tc/int_port.h" #include "en/ptp.h"
@@ -1431,51 +1430,6 @@ static unsigned int mlx5e_ul_rep_stats_grps_num(struct mlx5e_priv *priv)return ARRAY_SIZE (mlx5e_ul_rep_stats_grps); } -static int -mlx5e_rep_vnic_reporter_diagnose (struct devlink_health_reporter *reporter, -struct devlink_fmsg *fmsg, -struct netlink_ext_ack *extack) -{ -struct mlx5e_rep_priv *rpriv =devlink_health_reporter_priv (reporter); -struct mlx5_eswitch_rep *rep = rpriv->rep; - -mlx5_reporter_vnic_diagnose_counters (rep->esw->dev, fmsg, rep->vport, - true); -return 0 ; -} - -static const struct devlink_health_reporter_ops mlx5_rep_vnic_reporter_ops = { - .name ="vnic" , - .diagnose = mlx5e_rep_vnic_reporter_diagnose, -}; - -static void mlx5e_rep_vnic_reporter_create (struct mlx5e_priv *priv, -struct devlink_port *dl_port) -{ -struct mlx5e_rep_priv *rpriv = priv->ppriv; -struct devlink_health_reporter *reporter; - - reporter =devl_port_health_reporter_create (dl_port, - &mlx5_rep_vnic_reporter_ops, - rpriv); -if (IS_ERR (reporter)) { -mlx5_core_err (priv->mdev, -"Failed to create representor vnic reporter, err = %pe\n" , - reporter); -return ; - } - - rpriv->rep_vnic_reporter = reporter; -} - -static void mlx5e_rep_vnic_reporter_destroy (struct mlx5e_priv *priv) -{ -struct mlx5e_rep_priv *rpriv = priv->ppriv; - -if (!IS_ERR_OR_NULL (rpriv->rep_vnic_reporter)) -devl_health_reporter_destroy (rpriv->rep_vnic_reporter); -} -static const struct mlx5e_profile mlx5e_rep_profile = { .init = mlx5e_init_rep, .cleanup = mlx5e_cleanup_rep,
@@ -1599,10 +1553,8 @@ mlx5e_vport_vf_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep) dl_port =mlx5_esw_offloads_devlink_port (dev->priv.eswitch, rpriv->rep->vport); -if (!IS_ERR (dl_port)) { +if (!IS_ERR (dl_port))SET_NETDEV_DEVLINK_PORT (netdev, dl_port); -mlx5e_rep_vnic_reporter_create (priv, dl_port); - } err =register_netdev (netdev);if (err) {
@@ -1615,7 +1567,6 @@ mlx5e_vport_vf_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)return 0 ; err_detach_netdev: -mlx5e_rep_vnic_reporter_destroy (priv);mlx5e_detach_netdev (netdev_priv (netdev)); err_cleanup_profile: priv->profile->cleanup (priv);
@@ -1673,7 +1624,6 @@ mlx5e_vport_rep_unload(struct mlx5_eswitch_rep *rep) }unregister_netdev (netdev); -mlx5e_rep_vnic_reporter_destroy (priv);mlx5e_detach_netdev (priv); priv->profile->cleanup (priv);mlx5e_destroy_netdev (netdev);
drivers/net/ethernet/mellanox/mlx5/core/en_rep.h +0 -1
@@ -118,7 +118,6 @@ struct mlx5e_rep_priv {struct rtnl_link_stats64 prev_vf_vport_stats;struct mlx5_flow_handle *send_to_vport_meta_rule;struct rhashtable tc_ht; -struct devlink_health_reporter *rep_vnic_reporter; }; static inline
drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c +37 -0
@@ -4,6 +4,26 @@#include <linux/mlx5/driver.h> #include "eswitch.h" #include "devlink.h" +#include "diag/reporter_vnic.h" + +static int +mlx5_esw_rep_vnic_reporter_diagnose (struct devlink_health_reporter *reporter, +struct devlink_fmsg *fmsg, +struct netlink_ext_ack *extack) +{ +struct mlx5_vport *vport =devlink_health_reporter_priv (reporter); + +mlx5_reporter_vnic_diagnose_counters (vport->dev, fmsg, vport->vport, + true); + +return 0 ; +} + +static const +struct devlink_health_reporter_ops mlx5_esw_rep_vnic_reporter_ops = { + .name ="vnic" , + .diagnose = mlx5_esw_rep_vnic_reporter_diagnose, +};static void mlx5_esw_get_port_parent_id (struct mlx5_core_dev *dev,struct netdev_phys_item_id *ppid)
@@ -189,6 +209,7 @@ static void mlx5_esw_devlink_port_res_unregister(struct devlink_port *dl_port)int mlx5_esw_offloads_devlink_port_register (struct mlx5_eswitch *esw,struct mlx5_vport *vport) { +struct devlink_health_reporter *reporter;struct mlx5_core_dev *dev = esw->dev;const struct devlink_port_ops *ops;struct mlx5_devlink_port *dl_port;
@@ -227,6 +248,16 @@ int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, struct mlx err); } + reporter =devl_port_health_reporter_create ( + &dl_port->dl_port, &mlx5_esw_rep_vnic_reporter_ops, + vport); +if (IS_ERR (reporter)) +mlx5_core_err (dev, +"Failed to create vnic health reporter for vport %d: %pe\n" , + vport_num, reporter); +else + dl_port->vnic_reporter = reporter; +return 0 ; rate_err:
@@ -241,6 +272,12 @@ void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_vport *vport)if (!vport->dl_port)return ; dl_port = vport->dl_port; + +if (dl_port->vnic_reporter) { +devl_health_reporter_destroy (dl_port->vnic_reporter); + dl_port->vnic_reporter =NULL ; + } +mlx5_esw_devlink_port_res_unregister (&dl_port->dl_port);mlx5_esw_qos_vport_update_parent (vport,NULL ,NULL );
drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +1 -0
@@ -179,6 +179,7 @@ struct mlx5_vport;struct mlx5_devlink_port {struct devlink_port dl_port;struct mlx5_vport *vport; +struct devlink_health_reporter *vnic_reporter; }; static inline void mlx5_devlink_port_init(struct mlx5_devlink_port *dl_port,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 914/1250 selftests/powerpc/tm: Fix tcheck() reading uninitialised CR value
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thibault Ferrante <[email protected]>
[ Upstream commit ed28b16eab705071d28edaace47189c2eb3aa108 ]
tcheck() is used to check the current transaction state (active, suspended, doomed) via the "tcheck" instruction, which writes its result into CR field 0. The inline asm declared a GPR output operand for this result but never actually moved the CR into it.
Every caller (tcheck_doomed(), tcheck_active(), tcheck_suspended(), tcheck_transactional()) has effectively been testing bits of an unrelated, arbitrary register value since this helper was introduced.
The "& 4" mask discards the TDOOMED and TS_lsb (suspended) bits before they ever reach the callers, so tcheck_doomed() and tcheck_suspended() can never return true, and tcheck_transactional() degrades to being equivalent to tcheck_active().
Fix tcheck() to actually move CR into the output register with mfcr, and widen the mask from "& 4" to "& 0xf" so the full CR0 nibble (TDOOMED | TS_msb | TS_lsb | reserved) is preserved for the callers.
This bug has been present since tcheck() was introduced.
--- tools/testing/selftests/powerpc/tm/tm.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
tools/testing/selftests/powerpc/tm/tm.h +6 -2
@@ -105,8 +105,12 @@ static inline bool failure_is_nesting(void)static inline int tcheck (void ) {long cr; - asmvolatile ("tcheck 0" :"=r" (cr) : :"cr0" ); -return (cr >>28 ) &4 ; + asmvolatile ("tcheck 0;" +"mfcr %0;" + :"=r" (cr) + : + :"cr0" ); +return (cr >>28 ) &0xf ; }static inline bool tcheck_doomed (void )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 915/1250 perf/core: Allow list_del during perf_event_overflow()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Richter <[email protected]>
[ Upstream commit 59e63416f5153e7d58652c616fbdcb7d5e01fff7 ]
A PMU might use perf_sched_cb_inc() and perf_sched_cb_dec() interface to get the PMU call back function pmu::sched_task invoked at schedule in and schedule out. This is achieved by walking along the list anchored by sched_cb_list.
The following scenario might lead to a list corruption.
perf_pmu_sched_task()
for_each_list_entry(..., &sched_cb_list)
+--> __perf_pmu_sched_task()
+--> event->pmu->sched_task())
+--> PMU_push_sample()
+--> perf_event_overflow()
+--> __perf_event_overflow()
+--> pmu->stop()
+--> perf_sched_cb_dec()
remove entry from sched_cb_list
while list node in use.This happens when ioctl(fd, PERF_EVENT_IOC_REFRESH, xxx) has been invoked and perf_event::event_limit hits zero.
Prevent the list corruption and convert for_each_list_entry() to for_each_list_entry_safe().
--- kernel/events/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
kernel/events/core.c +2 -2
@@ -3816,13 +3816,13 @@ static void perf_pmu_sched_task(struct task_struct *prev, bool sched_in) {struct perf_cpu_context *cpuctx =this_cpu_ptr (&perf_cpu_context); -struct perf_cpu_pmu_context *cpc; +struct perf_cpu_pmu_context *cpc, *cpc2;/* cpuctx->task_ctx will be handled in perf_event_context_sched_in/out */ if (prev == next || cpuctx->task_ctx)return ; -list_for_each_entry (cpc,this_cpu_ptr (&sched_cb_list), sched_cb_entry) +list_for_each_entry_safe (cpc, cpc2,this_cpu_ptr (&sched_cb_list), sched_cb_entry)__perf_pmu_sched_task (cpc, sched_in ? next : prev, sched_in); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 916/1250 perf/x86/intel/ds: Factor out PEBS group processing code to functions
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dapeng Mi <[email protected]>
[ Upstream commit 167cde7dc9b36b7a88f3c29d836fabce13023327 ]
Adaptive PEBS and arch-PEBS share lots of same code to process these PEBS groups, like basic, GPR and meminfo groups. Extract these shared code to generic functions to avoid duplicated code.
Stable-dep-of: 88aa1223bfff ("perf/x86/intel: Correct pt_regs->flags update for PEBS path")
--- arch/x86/events/intel/ds.c | 170 +++++++++++++++++++++++-------------- 1 file changed, 104 insertions(+), 66 deletions(-)
arch/x86/events/intel/ds.c +104 -66
@@ -2060,6 +2060,90 @@ static inline void __setup_pebs_counter_group(struct cpu_hw_events *cpuc,#define PEBS_LATENCY_MASK 0xffff +static inline void __setup_perf_sample_data (struct perf_event *event, +struct pt_regs *iregs, +struct perf_sample_data *data) +{ +perf_sample_data_init (data,0 , event->hw.last_period); + +/* +* We must however always use iregs for the unwinder to stay sane; the +* record BP,SP,IP can point into thin air when the record is from a +* previous PMI context or an (I)RET happened between the record and +* PMI. +*/ +perf_sample_save_callchain (data, event, iregs); +} + +static inline void __setup_pebs_basic_group (struct perf_event *event, +struct pt_regs *regs, +struct perf_sample_data *data, +u64 sample_type,u64 ip, +u64 tsc,u16 retire) +{ +/* The ip in basic is EventingIP */ +set_linear_ip (regs, ip); + regs->flags =PERF_EFLAGS_EXACT ; +setup_pebs_time (event, data, tsc); + +if (sample_type &PERF_SAMPLE_WEIGHT_STRUCT ) + data->weight.var3_w = retire; +} + +static inline void __setup_pebs_gpr_group (struct perf_event *event, +struct pt_regs *regs, +struct pebs_gprs *gprs, +u64 sample_type) +{ +if (event->attr.precise_ip <2 ) { +set_linear_ip (regs, gprs->ip); + regs->flags &= ~PERF_EFLAGS_EXACT ; + } + +if (sample_type & (PERF_SAMPLE_REGS_INTR |PERF_SAMPLE_REGS_USER )) +adaptive_pebs_save_regs (regs, gprs); +} + +static inline void __setup_pebs_meminfo_group (struct perf_event *event, +struct perf_sample_data *data, +u64 sample_type,u64 latency, +u16 instr_latency,u64 address, +u64 aux,u64 tsx_tuning,u64 ax) +{ +if (sample_type &PERF_SAMPLE_WEIGHT_TYPE ) { +u64 tsx_latency =intel_get_tsx_weight (tsx_tuning); + + data->weight.var2_w = instr_latency; + +/* +* Although meminfo::latency is defined as a u64, +* only the lower 32 bits include the valid data +* in practice on Ice Lake and earlier platforms. +*/ +if (sample_type &PERF_SAMPLE_WEIGHT ) + data->weight.full = latency ?: tsx_latency; +else + data->weight.var1_dw = (u32 )latency ?: tsx_latency; + + data->sample_flags |=PERF_SAMPLE_WEIGHT_TYPE ; + } + +if (sample_type &PERF_SAMPLE_DATA_SRC ) { + data->data_src.val =get_data_src (event, aux); + data->sample_flags |=PERF_SAMPLE_DATA_SRC ; + } + +if (sample_type &PERF_SAMPLE_ADDR_TYPE ) { + data->addr = address; + data->sample_flags |=PERF_SAMPLE_ADDR ; + } + +if (sample_type &PERF_SAMPLE_TRANSACTION ) { + data->txn =intel_get_tsx_transaction (tsx_tuning, ax); + data->sample_flags |=PERF_SAMPLE_TRANSACTION ; + } +} +/* * With adaptive PEBS the layout depends on what fields are configured. */
@@ -2069,12 +2153,14 @@ static void setup_pebs_adaptive_sample_data(struct perf_event *event, struct pt_regs *regs) {struct cpu_hw_events *cpuc =this_cpu_ptr (&cpu_hw_events); +u64 sample_type = event->attr.sample_type;struct pebs_basic *basic = __pebs;void *next_record = basic +1 ; -u64 sample_type, format_group;struct pebs_meminfo *meminfo =NULL ;struct pebs_gprs *gprs =NULL ;struct x86_perf_regs *perf_regs; +u64 format_group; +u16 retire;if (basic ==NULL )return ;
@@ -2082,31 +2168,17 @@ static void setup_pebs_adaptive_sample_data(struct perf_event *event, perf_regs = container_of(regs, struct x86_perf_regs, regs); perf_regs->xmm_regs =NULL ; - sample_type = event->attr.sample_type; format_group = basic->format_group; -perf_sample_data_init (data,0 , event->hw.last_period); -setup_pebs_time (event, data, basic->tsc); - -/* -* We must however always use iregs for the unwinder to stay sane; the -* record BP,SP,IP can point into thin air when the record is from a -* previous PMI context or an (I)RET happened between the record and -* PMI. -*/ -perf_sample_save_callchain (data, event, iregs); +__setup_perf_sample_data (event, iregs, data); *regs = *iregs; -/* The ip in basic is EventingIP */ -set_linear_ip (regs, basic->ip); - regs->flags =PERF_EFLAGS_EXACT ; -if (sample_type &PERF_SAMPLE_WEIGHT_STRUCT ) { -if (x86_pmu.flags &PMU_FL_RETIRE_LATENCY ) - data->weight.var3_w = basic->retire_latency; -else - data->weight.var3_w =0 ; - } +/* basic group */ + retire = x86_pmu.flags &PMU_FL_RETIRE_LATENCY ? + basic->retire_latency :0 ; +__setup_pebs_basic_group (event, regs, data, sample_type, + basic->ip, basic->tsc, retire);/* * The record for MEMINFO is in front of GP
@@ -2122,54 +2194,20 @@ static void setup_pebs_adaptive_sample_data(struct perf_event *event, gprs = next_record; next_record = gprs +1 ; -if (event->attr.precise_ip <2 ) { -set_linear_ip (regs, gprs->ip); - regs->flags &= ~PERF_EFLAGS_EXACT ; - } - -if (sample_type & (PERF_SAMPLE_REGS_INTR |PERF_SAMPLE_REGS_USER )) -adaptive_pebs_save_regs (regs, gprs); +__setup_pebs_gpr_group (event, regs, gprs, sample_type); }if (format_group &PEBS_DATACFG_MEMINFO ) { -if (sample_type &PERF_SAMPLE_WEIGHT_TYPE ) { -u64 latency = x86_pmu.flags &PMU_FL_INSTR_LATENCY ? - meminfo->cache_latency : meminfo->mem_latency; - -if (x86_pmu.flags &PMU_FL_INSTR_LATENCY ) - data->weight.var2_w = meminfo->instr_latency; - -/* -* Although meminfo::latency is defined as a u64, -* only the lower 32 bits include the valid data -* in practice on Ice Lake and earlier platforms. -*/ -if (sample_type &PERF_SAMPLE_WEIGHT ) { - data->weight.full = latency ?: -intel_get_tsx_weight (meminfo->tsx_tuning); - }else { - data->weight.var1_dw = (u32 )latency ?: -intel_get_tsx_weight (meminfo->tsx_tuning); - } - - data->sample_flags |=PERF_SAMPLE_WEIGHT_TYPE ; - } - -if (sample_type &PERF_SAMPLE_DATA_SRC ) { - data->data_src.val =get_data_src (event, meminfo->aux); - data->sample_flags |=PERF_SAMPLE_DATA_SRC ; - } - -if (sample_type &PERF_SAMPLE_ADDR_TYPE ) { - data->addr = meminfo->address; - data->sample_flags |=PERF_SAMPLE_ADDR ; - } - -if (sample_type &PERF_SAMPLE_TRANSACTION ) { - data->txn =intel_get_tsx_transaction (meminfo->tsx_tuning, - gprs ? gprs->ax :0 ); - data->sample_flags |=PERF_SAMPLE_TRANSACTION ; - } +u64 latency = x86_pmu.flags &PMU_FL_INSTR_LATENCY ? + meminfo->cache_latency : meminfo->mem_latency; +u64 instr_latency = x86_pmu.flags &PMU_FL_INSTR_LATENCY ? + meminfo->instr_latency :0 ; +u64 ax = gprs ? gprs->ax :0 ; + +__setup_pebs_meminfo_group (event, data, sample_type, latency, + instr_latency, meminfo->address, + meminfo->aux, meminfo->tsx_tuning, + ax); }if (format_group &PEBS_DATACFG_XMMS ) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 917/1250 perf/x86/intel: Correct pt_regs->flags update for PEBS path
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dapeng Mi <[email protected]>
[ Upstream commit 88aa1223bfffb1a0a98c639e9e1f71058f0d9178 ]
pt_regs->flags holds the saved CPU FLAGS register. In the PEBS path, it was incorrectly set to PERF_EFLAGS_EXACT instead of being populated from the PEBS flags snapshot.
Update pt_regs->flags from PEBS GPR flags if GPRs group is present.
--- arch/x86/events/intel/ds.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
arch/x86/events/intel/ds.c +9 -1
@@ -2083,7 +2083,7 @@ static inline void __setup_pebs_basic_group(struct perf_event *event, {/* The ip in basic is EventingIP */ set_linear_ip (regs, ip); - regs->flags =PERF_EFLAGS_EXACT ; + regs->flags |=PERF_EFLAGS_EXACT ;setup_pebs_time (event, data, tsc);if (sample_type &PERF_SAMPLE_WEIGHT_STRUCT )
@@ -2095,9 +2095,17 @@ static inline void __setup_pebs_gpr_group(struct perf_event *event, struct pebs_gprs *gprs, u64 sample_type) { +/* +* Update flags with PEBS data. PERF_EFLAGS_EXACT must be set +* in previous basic group handling. +*/ + regs->flags = gprs->flags |PERF_EFLAGS_EXACT ; +if (event->attr.precise_ip <2 ) {set_linear_ip (regs, gprs->ip); regs->flags &= ~PERF_EFLAGS_EXACT ; + }else if (regs->flags &X86_VM_MASK ) { + regs->flags ^= (PERF_EFLAGS_VM |X86_VM_MASK ); }if (sample_type & (PERF_SAMPLE_REGS_INTR |PERF_SAMPLE_REGS_USER ))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 918/1250 perf/x86/intel: Prevent drain_pebs() reentry
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dapeng Mi <[email protected]>
[ Upstream commit a56c03a397e2cd0c4cf8da96dcd6214f7d0e7d8c ]
The PEBS buffer is shared by all events on a CPU, so drain_pebs() must not be reentered. If so, one instance may observe stale buffer state and potentially access out-of-bound memory.
Most invocations happen in NMI context, which naturally prevents reentry. However, drain_pebs() is also reachable from process context via intel_pmu_drain_pebs_buffer().
In those paths, the PMU is often already disabled, but not guaranteed. For example, __intel_pmu_pebs_disable() only disables the target counter, so other active counters can still raise a PMI and interrupt an in-flight drain_pebs(). Here is an example,
__perf_addr_filters_adjust()
perf_event_stop()
__perf_event_stop()
x86_pmu_stop() (event->pmu->stop)
intel_pmu_disable_event()
intel_pmu_pebs_disable()
__intel_pmu_pebs_disable()
intel_pmu_drain_large_pebs()
intel_pmu_drain_pebs_buffer()Introduce __intel_pmu_quiesce() and __intel_pmu_resume() helpers and use them in intel_pmu_drain_large_pebs() to disable the full PMU around the intel_pmu_drain_pebs_buffer() call, preventing reentry.
Also add a warning in intel_pmu_drain_pebs_buffer() when the full PMU is not disabled.
--- arch/x86/events/intel/core.c | 33 ++++++++++++++++++++++++--------- arch/x86/events/intel/ds.c | 8 +++++++- arch/x86/events/perf_event.h | 3 +++ 3 files changed, 34 insertions(+), 10 deletions(-)
arch/x86/events/intel/core.c +24 -9
@@ -2621,6 +2621,27 @@ static void intel_pmu_del_event(struct perf_event *event)this_cpu_ptr (&cpu_hw_events)->n_late_setup--; } +int __intel_pmu_quiesce (void ) +{ +struct cpu_hw_events *cpuc =this_cpu_ptr (&cpu_hw_events); +int pmu_enabled = cpuc->enabled; + + cpuc->enabled =0 ; +if (pmu_enabled) +intel_pmu_disable_all (); + +return pmu_enabled; +} + +void __intel_pmu_resume (int pmu_enabled) +{ +struct cpu_hw_events *cpuc =this_cpu_ptr (&cpu_hw_events); + + cpuc->enabled = pmu_enabled; +if (pmu_enabled) +intel_pmu_enable_all (0 ); +} +static int icl_set_topdown_event_period (struct perf_event *event) {struct hw_perf_event *hwc = &event->hw;
@@ -2812,16 +2833,13 @@ static void intel_pmu_read_event(struct perf_event *event)if (event->hw.flags & (PERF_X86_EVENT_AUTO_RELOAD |PERF_X86_EVENT_TOPDOWN ) ||is_pebs_counter_event_group (event)) {struct cpu_hw_events *cpuc =this_cpu_ptr (&cpu_hw_events); -bool pmu_enabled = cpuc->enabled; +int pmu_enabled;/* Only need to call update_topdown_event() once for group read. */ if (is_metric_event (event) && (cpuc->txn_flags &PERF_PMU_TXN_READ ))return ; - cpuc->enabled =0 ; -if (pmu_enabled) -intel_pmu_disable_all (); - + pmu_enabled =__intel_pmu_quiesce ();/* * If the PEBS counters snapshotting is enabled, * the topdown event is available in PEBS records.
@@ -2830,10 +2848,7 @@ static void intel_pmu_read_event(struct perf_event *event)static_call (intel_pmu_update_topdown_event)(event,NULL ); elseintel_pmu_drain_pebs_buffer (); - - cpuc->enabled = pmu_enabled; -if (pmu_enabled) -intel_pmu_enable_all (0 ); +__intel_pmu_resume (pmu_enabled);return ; }
arch/x86/events/intel/ds.c +7 -1
@@ -961,8 +961,11 @@ int intel_pmu_drain_bts_buffer(void)void intel_pmu_drain_pebs_buffer (void ) { +struct cpu_hw_events *cpuc =this_cpu_ptr (&cpu_hw_events);struct perf_sample_data data; +WARN_ON_ONCE (cpuc->enabled); +static_call (x86_pmu_drain_pebs)(NULL , &data); }
@@ -1528,8 +1531,11 @@ static void intel_pmu_pebs_via_pt_enable(struct perf_event *event)static inline void intel_pmu_drain_large_pebs (struct cpu_hw_events *cpuc) {if (cpuc->n_pebs == cpuc->n_large_pebs && - cpuc->n_pebs != cpuc->n_pebs_via_pt) + cpuc->n_pebs != cpuc->n_pebs_via_pt) { +int enabled =__intel_pmu_quiesce ();intel_pmu_drain_pebs_buffer (); +__intel_pmu_resume (enabled); + } }void intel_pmu_pebs_enable (struct perf_event *event)
arch/x86/events/perf_event.h +3 -0
@@ -1612,6 +1612,9 @@ static __always_inline void __intel_pmu_lbr_disable(void)wrmsrq (MSR_IA32_DEBUGCTLMSR , debugctl); } +extern int __intel_pmu_quiesce (void ); +extern void __intel_pmu_resume (int pmu_enabled); +int intel_pmu_save_and_restart (struct perf_event *event); struct event_constraint *
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 919/1250 sched/eevdf: Fix augmented max_slice
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vincent Guittot <[email protected]>
[ Upstream commit 9a8bc9bb4c3fb3218b4f151f98a722fbeb5b5c34 ]
Similarly to se->min_slice, init se->max_slice with se->slice before enqueueing the entity so the augmented callback computes it correctly at parent level.
--- kernel/sched/fair.c | 2 ++ 1 file changed, 2 insertions(+)
kernel/sched/fair.c +2 -0
@@ -921,6 +921,8 @@ static void __enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)sum_w_vruntime_add (cfs_rq, se); se->min_vruntime = se->vruntime; se->min_slice = se->slice; + se->max_slice = se->slice; +rb_add_augmented_cached (&se->run_node, &cfs_rq->tasks_timeline, __entity_less, &min_vruntime_cb); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 920/1250 sched/eevdf: Fix rb augmented with multi fields
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vincent Guittot <[email protected]>
[ Upstream commit 51b0e68cfa0ac69e3c3ea9d6753af7e15dfaab22 ]
The eevdf rb tree maintains 3 augmented fields but only one is currently copied when balancing the tree.
Add a more generic define that can be used when there are several augmented fields. In this case, we provide a function that takes care of copying all fields.
--- include/linux/rbtree_augmented.h | 35 +++++++++++++++++++++++++------- kernel/sched/fair.c | 12 +++++++++-- 2 files changed, 38 insertions(+), 9 deletions(-)
include/linux/rbtree_augmented.h +28 -7
@@ -87,18 +87,18 @@ rb_add_augmented_cached(struct rb_node *node, struct rb_root_cached *tree, }/* -* Template for declaring augmented rbtree callbacks (generic case) +* Template for declaring augmented rbtree callbacks (generic multi fields) * * RBSTATIC: 'static' or empty * RBNAME: name of the rb_augment_callbacks structure * RBSTRUCT: struct type of the tree nodes * RBFIELD: name of struct rb_node field within RBSTRUCT -* RBAUGMENTED: name of field within RBSTRUCT holding data for subtree -* RBCOMPUTE: name of function that recomputes the RBAUGMENTED data +* RBCOPY: name of function that copies the RBAUGMENTED datas +* RBCOMPUTE: name of function that recomputes the RBAUGMENTED datas */ -#define RB_DECLARE_CALLBACKS (RBSTATIC ,RBNAME , \ -RBSTRUCT ,RBFIELD ,RBAUGMENTED ,RBCOMPUTE ) \ +#define RB_DECLARE_CALLBACKS_MULTI (RBSTATIC ,RBNAME , \ +RBSTRUCT ,RBFIELD ,RBCOPY ,RBCOMPUTE ) \ static inline void \ RBNAME ## _propagate(struct rb_node *rb, struct rb_node *stop) \ { \
@@ -114,14 +114,14 @@ RBNAME ## _copy(struct rb_node *rb_old, struct rb_node *rb_new) \ { \RBSTRUCT *old =rb_entry (rb_old,RBSTRUCT ,RBFIELD ); \RBSTRUCT *new =rb_entry (rb_new,RBSTRUCT ,RBFIELD ); \ - new->RBAUGMENTED = old->RBAUGMENTED; \ +RBCOPY (new, old); \ } \static void \ RBNAME ## _rotate(struct rb_node *rb_old, struct rb_node *rb_new) \ { \RBSTRUCT *old =rb_entry (rb_old,RBSTRUCT ,RBFIELD ); \RBSTRUCT *new =rb_entry (rb_new,RBSTRUCT ,RBFIELD ); \ - new->RBAUGMENTED = old->RBAUGMENTED; \ +RBCOPY (new, old); \RBCOMPUTE (old, false); \ } \ RBSTATIC const struct rb_augment_callbacks RBNAME = { \
@@ -130,6 +130,27 @@ RBSTATIC const struct rb_augment_callbacks RBNAME = { \ .rotate = RBNAME ## _rotate \ }; +/* +* Template for declaring augmented rbtree callbacks (generic single field) +* +* RBSTATIC: 'static' or empty +* RBNAME: name of the rb_augment_callbacks structure +* RBSTRUCT: struct type of the tree nodes +* RBFIELD: name of struct rb_node field within RBSTRUCT +* RBAUGMENTED: name of field within RBSTRUCT holding data for subtree +* RBCOMPUTE: name of function that recomputes the RBAUGMENTED data +*/ + +#define RB_DECLARE_CALLBACKS (RBSTATIC ,RBNAME , \ +RBSTRUCT ,RBFIELD ,RBAUGMENTED ,RBCOMPUTE ) \ +static inline void \ +RBNAME ## _copy_single(RBSTRUCT *new, RBSTRUCT *old) \ +{ \ + new->RBAUGMENTED = old->RBAUGMENTED; \ +} \ +RB_DECLARE_CALLBACKS_MULTI(RBSTATIC, RBNAME, \ + RBSTRUCT, RBFIELD, RBNAME ## _copy_single, RBCOMPUTE) +/* * Template for declaring augmented rbtree callbacks, * computing RBAUGMENTED scalar as max(RBCOMPUTE(node)) for all subtree nodes.
kernel/sched/fair.c +10 -2
@@ -883,6 +883,13 @@ static inline void __max_slice_update(struct sched_entity *se, struct rb_node *n } } +static inline void min_vruntime_copy (struct sched_entity *new,struct sched_entity *old) +{ + new->min_vruntime = old->min_vruntime; + new->min_slice = old->min_slice; + new->max_slice = old->max_slice; +} +/* * se->min_vruntime = min(se->vruntime, {left,right}->min_vruntime) */
@@ -910,8 +917,9 @@ static inline bool min_vruntime_update(struct sched_entity *se, bool exit) se->max_slice == old_max_slice; } -RB_DECLARE_CALLBACKS(static, min_vruntime_cb, struct sched_entity, - run_node, min_vruntime, min_vruntime_update); + +RB_DECLARE_CALLBACKS_MULTI(static, min_vruntime_cb, struct sched_entity, + run_node, min_vruntime_copy, min_vruntime_update);/* * Enqueue an entity into the rb-tree:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 921/1250 sched: Account cgroup CPU time to the execution context
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hui Su <[email protected]>
[ Upstream commit c23810313bdf6b02f39a1f2a1464c4b18bd39e31 ]
Proxy execution separates the scheduling context from the execution context. Commit aa4f74dfd42b ("sched: Fix runtime accounting w/ split exec & sched contexts") made per-task and thread-group runtime accounting follow the task that actually executes, while cgroup CPU usage is charged to the donor.
When the donor and execution task belong to different cgroups, this makes a task's execution time count against a different cgroup from the one the task belongs to.
Cgroup CPU usage should follow the execution context, matching the per-task, thread-group, and cgroup user/system accounting. Keep scheduling state associated with the donor, but charge cgroup CPU usage to rq->curr.
A reproducer with the donor and execution task in separate cgroups showed the execution task accumulating runtime while cgroup CPU usage was charged to the donor's cgroup. With this change, the execution task's cgroup accumulates the CPU usage instead. The same behavior was verified with an RT donor and with legacy cpuacct accounting.
--- kernel/sched/fair.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
kernel/sched/fair.c +1 -3
@@ -1250,7 +1250,6 @@ static s64 update_se(struct rq *rq, struct sched_entity *se) se->exec_start = now;if (entity_is_task (se)) { -struct task_struct *donor =task_of (se);struct task_struct *running = rq->curr;/* * If se is a task, we account the time against the running
@@ -1262,8 +1261,7 @@ static s64 update_se(struct rq *rq, struct sched_entity *se)trace_sched_stat_runtime (running, delta_exec);account_group_exec_runtime (running, delta_exec); -/* cgroup time is always accounted against the donor */ -cgroup_account_cputime (donor, delta_exec); +cgroup_account_cputime (running, delta_exec); }else {/* If not task, account the time against donor se */ se->sum_exec_runtime += delta_exec;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 922/1250 sched/core: Call wq_worker_tick() for the execution context
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hui Su <[email protected]>
[ Upstream commit f5741d2b34519d387edf6e9798fc7030c20a35f3 ]
wq_worker_tick() accounts CPU time and detects CPU-intensive work for the kworker that is actually running. With proxy execution, rq->donor is the scheduling context while rq->curr is the execution context.
Calling the hook with rq->donor can skip workqueue accounting when a kworker is executing on behalf of a donor task. It can also account a blocked kworker when the donor is a worker but rq->curr is the task actually executing. The former can delay WORKER_CPU_INTENSIVE handling and pool concurrency management, which can delay pending kernel work and userspace operations depending on it.
Use rq->curr for the workqueue tick hook while retaining rq->donor for scheduler accounting.
--- kernel/sched/core.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
kernel/sched/core.c +5 -4
@@ -5598,8 +5598,8 @@ void sched_tick(void) {int cpu =smp_processor_id ();struct rq *rq =cpu_rq (cpu); -/* accounting goes to the donor task */ -struct task_struct *donor; +/* scheduler accounting goes to the donor task */ +struct task_struct *curr, *donor;struct rq_flags rf;unsigned long hw_pressure;u64 resched_latency;
@@ -5610,6 +5610,7 @@ void sched_tick(void)sched_clock_tick ();rq_lock (rq, &rf); + curr = rq->curr; donor = rq->donor;psi_account_irqtime (rq, donor,NULL );
@@ -5636,8 +5637,8 @@ void sched_tick(void)perf_event_task_tick (); -if (donor->flags &PF_WQ_WORKER ) -wq_worker_tick (donor); +if (curr->flags &PF_WQ_WORKER ) +wq_worker_tick (curr);if (!scx_switched_all ()) { rq->idle_balance =idle_cpu (cpu);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 923/1250 net/sched: cls_route: free emptied bucket on filter move
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Victor Nogueira <[email protected]>
[ Upstream commit 1853f30cf5c84971f99788a76207c6f745380896 ]
route4_change can move an existing filter to a different top-level
bucket: route4_set_parms recomputes the handle from TCA_ROUTE4_TO/ FROM/IIF, and the handle-mismatch check is gated on the 'new' flag, so for an existing filter the new handle may differ from the old one and land in a different bucket. When this happens, the filter is unlinked from the old bucket, but the bucket itself is never freed once it goes empty. The stale empty bucket remains in head->table[], causing route4_delete to report *last=false even after the last live filter is gone. That pins the empty tcf_proto and causes a leak.
Fix this by refcounting the filters linked to a bucket and freeing the bucket when the count drops to zero. The existing scan in route4_delete goes away with it.
The count is updated at all sites that link or unlink a filter during add, change and delete, and the bucket is dropped from head->table[] as soon as it reaches zero.
Conditions to recreate the bug:
CONFIG_NET_CLS_ROUTE4=y, CONFIG_NET_SCH_INGRESS=y, CONFIG_NET_CLS_ACT=y.
tc qdisc replace dev lo clsact
tc filter add dev lo ingress protocol ip pref 100 route from 1 to 1 tc filter change dev lo ingress protocol ip pref 100 handle 0x10001 \
route from 1 to 2
tc filter del dev lo ingress protocol ip pref 100 handle 0x10002 \
route from 1 to 2
tc filter show dev lo ingress | grep -c 'pref 100 route chain 0 '
--- net/sched/cls_route.c | 45 +++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 23 deletions(-)
net/sched/cls_route.c +22 -23
@@ -11,6 +11,7 @@#include <linux/kernel.h> #include <linux/string.h> #include <linux/errno.h> +#include <linux/refcount.h> #include <linux/skbuff.h> #include <net/dst.h> #include <net/route.h>
@@ -41,6 +42,7 @@ struct route4_head {struct route4_bucket {/* 16 FROM buckets + 16 IIF buckets + 1 wildcard bucket */ struct route4_filter __rcu *ht[16 +16 +1 ]; +refcount_t filters_ref;struct rcu_head rcu; };
@@ -336,7 +338,7 @@ static int route4_delete(struct tcf_proto *tp, void *arg, bool *last,struct route4_filter *nf;struct route4_bucket *b;unsigned int h =0 ; -int i, h1; +int h1;if (!head || !f)return -EINVAL ;
@@ -362,23 +364,14 @@ static int route4_delete(struct tcf_proto *tp, void *arg, bool *last,tcf_exts_get_net (&f->exts);tcf_queue_work (&f->rwork, route4_delete_filter_work); -/* Strip RTNL protected tree */ -for (i =0 ; i <=32 ; i++) { -struct route4_filter *rt; - - rt =rtnl_dereference (b->ht[i]); -if (rt) - goto out; +if (refcount_dec_and_test (&b->filters_ref)) { +RCU_INIT_POINTER (head->table[to_hash (h)],NULL ); +kfree_rcu (b, rcu); } - -/* OK, session has no flows */ -RCU_INIT_POINTER (head->table[to_hash (h)],NULL ); -kfree_rcu (b, rcu);break ; } } -out: *last = true;for (h1 =0 ; h1 <=256 ; h1++) {if (rcu_access_pointer (head->table[h1])) {
@@ -459,6 +452,7 @@ static int route4_set_parms(struct net *net, struct tcf_proto *tp,if (b ==NULL )return -ENOBUFS ; +refcount_set (&b->filters_ref,1 );rcu_assign_pointer (head->table[h1], b); }else {unsigned int h2 =from_hash (nhandle >>16 );
@@ -468,6 +462,8 @@ static int route4_set_parms(struct net *net, struct tcf_proto *tp, fp = rtnl_dereference(fp->next))if (fp->handle == f->handle)return -EEXIST ; + +refcount_inc (&b->filters_ref); }if (tb[TCA_ROUTE4_TO ])
@@ -500,7 +496,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb,struct route4_filter *fold, *f1, *pfp, *f =NULL ;struct route4_bucket *b;struct nlattr *tb[TCA_ROUTE4_MAX +1 ]; -unsigned int h, th; +unsigned int h;int err;bool new = true;
@@ -560,17 +556,20 @@ static int route4_change(struct net *net, struct sk_buff *in_skb,rcu_assign_pointer (*fp, f);if (fold) { - th =to_hash (fold->handle); + b = fold->bkt; h =from_hash (fold->handle >>16 ); - b =rtnl_dereference (head->table[th]); -if (b) { - fp = &b->ht[h]; -for (pfp =rtnl_dereference (*fp); pfp; - fp = &pfp->next, pfp =rtnl_dereference (*fp)) { -if (pfp == fold) { -rcu_assign_pointer (*fp, fold->next); -break ; + fp = &b->ht[h]; +for (pfp =rtnl_dereference (*fp); pfp; + fp = &pfp->next, pfp =rtnl_dereference (*fp)) { +if (pfp == fold) { +rcu_assign_pointer (*fp, fold->next); +if (refcount_dec_and_test (&b->filters_ref)) { +unsigned int th =to_hash (fold->handle); + +RCU_INIT_POINTER (head->table[th],NULL ); +kfree_rcu (b, rcu); } +break ; } } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 924/1250 net/sched: cls_route: Reject handle aliasing
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Victor Nogueira <[email protected]>
[ Upstream commit b74a8455a2f271f54695b6a8ec1f113824a46c0e ]
route4_set_parms() rejects a duplicate by scanning the destination chain for f->handle, but f->handle is the handle the filter has before the update, not the one it is about to be linked under. The comparison and the insertion therefore use different handles, which causes breakage.
When a change moves the filter to a chain that already holds nhandle, the scan looks for the old handle instead, misses the collision and links a second filter with the same handle:
tc filter add dev lo ingress protocol ip pref 100 \
route from 1 to 1 classid 1:1 action ok
tc filter add dev lo ingress protocol ip pref 100 \
route from 2 to 2 classid 1:2 action drop
tc filter change dev lo ingress protocol ip pref 100 handle 0x10001 \
route from 2 to 2 classid 1:1 action ok
tc filter show dev lo ingress
... fh 0x00020002 flowid 1:2 to 2 from 2
... fh 0x00020002 flowid 1:1 to 2 from 2
The newcomer is appended after the incumbent, and both end up with the same f->id. route4_get() returns the first match, so the second filter can no longer be addressed by handle, and route4_classify() stops at the first filter whose f->id matches. The second filter is dumped but is effectively dead.
Fix this by comparing against nhandle.
--- net/sched/cls_route.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
net/sched/cls_route.c +5 -1
@@ -460,8 +460,12 @@ static int route4_set_parms(struct net *net, struct tcf_proto *tp,for (fp =rtnl_dereference (b->ht[h2]); fp; fp =rtnl_dereference (fp->next)) -if (fp->handle == f->handle) +if (fp->handle == nhandle) { +NL_SET_ERR_MSG_FMT (extack, +"Handle %x is already in use" , + nhandle);return -EEXIST ; + }refcount_inc (&b->filters_ref); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 925/1250 net/sched: cls_route: Fix in-place replace
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Victor Nogueira <[email protected]>
[ Upstream commit 41e85e54e5649a1617698438b0ce64c6f9d83d69 ]
Building on the previous patch, route4_set_parms rejects a duplicate by scanning the destination chain for nhandle, but the scan doesn't exclude the older version it is replacing, so an in-place replace will match the older version's handle and fail.
Fix this by passing the older filter as a parameter to route4_set_parms (replacing "new") and skipping it in the scan.
Excluding the older version is not enough on its own. nhandle is built out of TCA_ROUTE4_TO, TCA_ROUTE4_FROM and TCA_ROUTE4_IIF alone, while the 0x7F00 bits, which only tell apart filters sharing one key, are folded in on the create path. Letting the replace through would therefore rename the filter it replaces: replacing handle 0x10101 stored it back as 0x10001, and a sibling at 0x10201 could then no longer be replaced at all, since its own nhandle collided with the renamed filter.
tc filter add ... handle 0x10101 route from 1 to 1 classid 1:1 tc filter add ... handle 0x10201 route from 1 to 1 classid 1:2 tc filter replace ... handle 0x10101 route from 1 to 1 classid 1:9 ... fh 0x00010001 flowid 1:9 to 1 from 1 ... fh 0x00010201 flowid 1:2 to 1 from 1 tc filter replace ... handle 0x10201 route from 1 to 1 classid 1:8 Error: Handle 10001 is already in use.
So carry those bits over when the key the request builds is the key the older filter already has. An in-place replace then keeps the handle userspace named the filter by, while a request that does change the key still renames it, as it did before.
--- net/sched/cls_route.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-)
net/sched/cls_route.c +13 -14
@@ -393,8 +393,9 @@ static const struct nla_policy route4_policy[TCA_ROUTE4_MAX + 1] = {static int route4_set_parms (struct net *net,struct tcf_proto *tp,unsigned long base,struct route4_filter *f,u32 handle,struct route4_head *head, -struct nlattr **tb,struct nlattr *est,int new, -u32 flags,struct netlink_ext_ack *extack) +struct nlattr **tb,struct nlattr *est, +struct route4_filter *fold,u32 flags, +struct netlink_ext_ack *extack) {u32 id =0 , to =0 , nhandle =0x8000 ;struct route4_filter *fp;
@@ -407,7 +408,7 @@ static int route4_set_parms(struct net *net, struct tcf_proto *tp,return err;if (tb[TCA_ROUTE4_TO ]) { -if (new && handle &0x8000 ) { +if (!fold && handle &0x8000 ) {NL_SET_ERR_MSG (extack,"Invalid handle" );return -EINVAL ; }
@@ -430,14 +431,14 @@ static int route4_set_parms(struct net *net, struct tcf_proto *tp, }else nhandle |=0xFFFF <<16 ; -if (handle && new) { +if (handle && (!fold || nhandle == (handle & ~0x7F00 ))) nhandle |= handle &0x7F00 ; -if (nhandle != handle) { -NL_SET_ERR_MSG_FMT (extack, -"Handle mismatch constructed: %x (expected: %x)" , - handle, nhandle); -return -EINVAL ; - } + +if (handle && !fold && nhandle != handle) { +NL_SET_ERR_MSG_FMT (extack, +"Handle mismatch constructed: %x (expected: %x)" , + handle, nhandle); +return -EINVAL ; }if (!nhandle) {
@@ -460,7 +461,7 @@ static int route4_set_parms(struct net *net, struct tcf_proto *tp,for (fp =rtnl_dereference (b->ht[h2]); fp; fp =rtnl_dereference (fp->next)) -if (fp->handle == nhandle) { +if (fp != fold && fp->handle == nhandle) {NL_SET_ERR_MSG_FMT (extack,"Handle %x is already in use" , nhandle);
@@ -502,7 +503,6 @@ static int route4_change(struct net *net, struct sk_buff *in_skb,struct nlattr *tb[TCA_ROUTE4_MAX +1 ];unsigned int h;int err; -bool new = true;if (!handle) {NL_SET_ERR_MSG (extack,"Creating with handle of 0 is invalid" );
@@ -539,11 +539,10 @@ static int route4_change(struct net *net, struct sk_buff *in_skb, f->tp = fold->tp; f->bkt = fold->bkt; - new = false; } err =route4_set_parms (net, tp, base, f, handle, head, tb, - tca[TCA_RATE ], new, flags, extack); + tca[TCA_RATE ], fold, flags, extack);if (err <0 ) goto errout;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 926/1250 net/sched: cls_api: Dont replay RTM_GETCHAIN in tc_ctl_chain().
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <[email protected]>
[ Upstream commit dff39930ad5e53d202bfdfb14687d1d2fd753b4d ]
If a netlink socket sends RTM_GETCHAIN requests repeatedly without recv()ing the responses, tc_ctl_chain() hogs CPU and triggers Hung Task splat. [0]
As caught in the stack trace, netlink_attachskb() could confuse tc_ctl_chain() by returning -EAGAIN when the userspace netlink socket's receive buffer is full.
The replay: label exists since commit 32a4f5ecd738 ("net: sched:
introduce chain object to uapi") but was not used initially.
Since commit 9f407f1768d3 ("net: sched: introduce chain templates"), the label is needed for RTM_NEWCHAIN because tcf_proto_lookup_ops() may release RTNL to call request_module().
However, the replay logic is unnecessary for RTM_GETCHAIN.
Let's apply the replay logic only for RTM_NEWCHAIN.
[0]:
INFO: task repro:1018 is blocked on a mutex likely owned by task repro:1022. task:repro state:R running task stack:14096 pid:1022 tgid:1014 ppid:961 task_flags:0x400040 flags:0x00080000 Call Trace: <TASK> ? clockevents_program_event (kernel/time/clockevents.c:372) ? pskb_expand_head (net/core/skbuff.c:615) ? skb_release_data (net/core/skbuff.c:1122) ? netlink_attachskb (./include/linux/skbuff.h:1323 ./include/linux/skbuff.h:1332 net/netlink/af_netlink.c:1232) ? __netlink_lookup (./include/linux/rcupdate.h:882 ./include/linux/rhashtable.h:711 net/netlink/af_netlink.c:499) ? tc_chain_notify (net/sched/cls_api.c:3045) ? tc_chain_notify (./include/linux/skbuff.h:1384 net/sched/cls_api.c:3041) ? netlink_unicast (net/netlink/af_netlink.c:1335) ? rtnl_unicast (./include/net/netlink.h:1198 net/core/rtnetlink.c:985) ? tc_ctl_chain (net/sched/cls_api.c:3242) ? rtnetlink_rcv_msg (net/core/rtnetlink.c:7146) ? netlink_unicast (net/netlink/af_netlink.c:1354) ? __pfx_rtnetlink_rcv_msg (net/core/rtnetlink.c:7177) ? netlink_rcv_skb (net/netlink/af_netlink.c:2556) ? netlink_unicast (net/netlink/af_netlink.c:1319) ? netlink_sendmsg (net/netlink/af_netlink.c:1900) ? __sock_sendmsg (net/socket.c:800) ? __sys_sendto (net/socket.c:2281) ? __x64_sys_sendto (net/socket.c:2288 net/socket.c:2284 net/socket.c:2284) ? do_syscall_64 (arch/x86/entry/syscall_64.c:61 arch/x86/entry/syscall_64.c:84) ? entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121) </TASK>
--- net/sched/cls_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/sched/cls_api.c +1 -1
@@ -3254,7 +3254,7 @@ static int tc_ctl_chain(struct sk_buff *skb, struct nlmsghdr *n,tcf_chain_put (chain); errout_block:tcf_block_release (q, block, true); -if (err == -EAGAIN ) +if (err == -EAGAIN && n->nlmsg_type ==RTM_NEWCHAIN )/* Replay the request. */ goto replay;return err;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 927/1250 net: sun4i-emac: fix missing of_node_put() for phy_node
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Li Youhong <[email protected]>
[ Upstream commit af406abfecad2f48d8f1fc646d3994f0982bac62 ]
of_parse_phandle() returns a node pointer with an elevated refcount. Add the missing of_node_put() on the probe error path after register_netdev() fails and in emac_remove().
--- drivers/net/ethernet/allwinner/sun4i-emac.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/ethernet/allwinner/sun4i-emac.c +2 -0
@@ -1067,6 +1067,7 @@ static int emac_probe(struct platform_device *pdev)return 0 ; out_release_sram: +of_node_put (db->phy_node);sunxi_sram_release (&pdev->dev); out_clk_disable_unprepare:clk_disable_unprepare (db->clk);
@@ -1094,6 +1095,7 @@ static void emac_remove(struct platform_device *pdev) }unregister_netdev (ndev); +of_node_put (db->phy_node);sunxi_sram_release (&pdev->dev);clk_disable_unprepare (db->clk);irq_dispose_mapping (ndev->irq);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 928/1250 net: hinic: fix mailbox segment buffer overflow
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aamir Ahmed <[email protected]>
[ Upstream commit 5d4d985957434867bbe85e4fa5e638f3e48ad522 ]
check_mbox_seq_id_and_seg_len() validates that seq_id does not exceed SEQ_ID_MAX_VAL (42) and seg_len does not exceed MBOX_SEG_LEN (48). However, this allows the last segment (seq_id=42) to carry a full 48-byte payload, writing to offset 42*48=2016 for 48 bytes (ending at byte 2064). The receive buffer is only MBOX_MAX_BUF_SZ (2048) bytes, resulting in a 16-byte heap buffer overflow.
The hinic3 driver already handles this correctly by defining MBOX_LAST_SEG_MAX_LEN and rejecting the last segment when it exceeds the remaining buffer space. Apply the same fix to the hinic driver.
--- drivers/net/ethernet/huawei/hinic/hinic_hw_mbox.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/net/ethernet/huawei/hinic/hinic_hw_mbox.c +3 -1
@@ -128,6 +128,7 @@ enum hinic_mbox_tx_status {#define SEQ_ID_START_VAL 0#define SEQ_ID_MAX_VAL 42 +#define MBOX_LAST_SEG_MAX_LEN (MBOX_MAX_BUF_SZ - SEQ_ID_MAX_VAL * MBOX_SEG_LEN)#define NO_DMA_ATTRIBUTE_VAL 0
@@ -372,7 +373,8 @@ recv_pf_from_vf_mbox_handler(struct hinic_mbox_func_to_func *func_to_func,static bool check_mbox_seq_id_and_seg_len (struct hinic_recv_mbox *recv_mbox,u8 seq_id,u8 seg_len) { -if (seq_id >SEQ_ID_MAX_VAL || seg_len >MBOX_SEG_LEN ) +if (seq_id >SEQ_ID_MAX_VAL || seg_len >MBOX_SEG_LEN || + (seq_id ==SEQ_ID_MAX_VAL && seg_len >MBOX_LAST_SEG_MAX_LEN ))return false;if (seq_id ==0 ) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 929/1250 net: dsa: mt7530: add EN7528 support
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ahmed Naseef <[email protected]>
[ Upstream commit cf23fcc9437e5c383d9f282197d580a5a3fd6e6e ]
The EcoNet EN7528 SoC integrates an MT7530 switch (the chip revision register reads 0x7530), memory-mapped in the SoC register space and reached through the same MMIO glue used for the built-in switches of the MediaTek MT7988 and Airoha EN7581/AN7583 SoCs. Its reset sequence and its PHY indirect access registers are the same as on those switches, so add an ID_EN7528 variant bound with the "econet,en7528-switch" compatible, reusing mt7988_setup() and the indirect PHY accessors.
The switch core, however, is an MT7530 and not an MT7531 derivative: the CPU port to trap frames to is set through the MT7530-style CPU_EN / CPU_PORT fields of the MFC register rather than the MT7531 CFC register, so add it to the MT7530 handling in mt753x_conduit_state_change(). For the same reason the MT7530 mirror and force-mode register layouts already apply to it as the default of the MT753X_*() macros.
The four user ports (1-4) are connected to integrated Gigabit PHYs at MDIO addresses 9-12 of the switch internal MDIO bus. The CPU port (port
6) is connected to the SoC Ethernet MAC at a fixed 1000 Mbps full duplex link, so the port capabilities cannot be shared with the MT7988 and EN7581 switches, whose CPU ports run at 10 Gbps.
The LAN GPHYs advertise EEE by default, but negotiating EEE with some link partners results in an unstable link with dropped frames. Leave the LPI capabilities empty for the EN7528 so that phylink disables EEE on these PHYs and refuses to enable it from userspace.
Stable-dep-of: 3c18e3c9a54e ("net: dsa: mt7530: populate lpi_interfaces to fix EEE support")
--- drivers/net/dsa/mt7530-mmio.c | 1 + drivers/net/dsa/mt7530.c | 58 ++++++++++++++++++++++++++++++----- drivers/net/dsa/mt7530.h | 1 + 3 files changed, 52 insertions(+), 8 deletions(-)
drivers/net/dsa/mt7530-mmio.c +1 -0
@@ -13,6 +13,7 @@static const struct of_device_id mt7988_of_match[] = { { .compatible ="airoha,an7583-switch" , .data = &mt753x_table[ID_AN7583 ], }, { .compatible ="airoha,en7581-switch" , .data = &mt753x_table[ID_EN7581 ], }, + { .compatible ="econet,en7528-switch" , .data = &mt753x_table[ID_EN7528 ], }, { .compatible ="mediatek,mt7988-switch" , .data = &mt753x_table[ID_MT7988 ], }, {/* sentinel */ }, };
drivers/net/dsa/mt7530.c +50 -8
86 lines not on this page · raw message
drivers/net/dsa/mt7530.h +1 -0
@@ -21,6 +21,7 @@ enum mt753x_id {ID_MT7988 =3 ,ID_EN7581 =4 ,ID_AN7583 =5 , + ID_EN7528 = 6, };#define NUM_TRGMII_CTRL 5
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 930/1250 net: dsa: mt7530: populate lpi_interfaces to fix EEE support
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aleksei Sviridkin <[email protected]>
[ Upstream commit 3c18e3c9a54e1239b72849502ca4737604bfbb46 ]
phylink_create() decides once and for all that a MAC supports managed EEE, and it requires the tx_lpi ops plus non-empty lpi_capabilities and lpi_interfaces. mt753x_phylink_get_caps() leaves lpi_interfaces empty.
So ever since the conversion to phylink managed EEE, ethtool has answered "Not supported" on every mt753x port, and phy_disable_eee() has locked userspace out of turning EEE on. That undoes what commit 06dfcd4098cf ("net: dsa: mt7530: fix enabling EEE on MT7531 switch on all boards") arranged: EEE off by default, but reachable with ethtool.
Leave the speeds above 1 Gbps out of both bitmaps. PMCR folds SPEED_2500 and SPEED_10000 onto PMCR_FORCE_SPEED_1000, so PMCR_FORCE_EEE1G would govern LPI on such a link, and that is unvalidated rather than known unsupported: MediaTek's SDK driver sets the EEE force bits for 100 Mbps and 1 Gbps only, and the unit of the wakeup timers is undocumented with the port clock at 2.5 times the rate.
LPI stays off until userspace enables it, but the EEE advertisement of a PHY that advertises it out of reset comes back, since phylink stops force-clearing it.
--- drivers/net/dsa/mt7530.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
drivers/net/dsa/mt7530.c +12 -4
@@ -3045,23 +3045,31 @@ static void mt753x_phylink_get_caps(struct dsa_switch *ds, int port, config->mac_capabilities =MAC_ASYM_PAUSE |MAC_SYM_PAUSE ; + priv->info->mac_port_get_caps (ds, port, config); +/* The EN7528 GPHYs report EEE capability, but negotiating EEE with * common link partners (e.g. Realtek GbE NICs) results in an unstable * link with dropped frames. Leave the LPI capabilities empty so that * phylink disables EEE on these PHYs and refuses to enable it from * userspace. */ -if (priv->id !=ID_EN7528 ) { +if (priv->id !=ID_EN7528 && + config->mac_capabilities & (MAC_100FD |MAC_1000FD )) {u32 eeecr =mt7530_read (priv,MT753X_PMEEECR_P (port)); - config->lpi_capabilities =MAC_100FD |MAC_1000FD |MAC_2500FD ; +/* LPI above 1 Gbps is not supported */ + config->lpi_capabilities = config->mac_capabilities & + (MAC_100FD |MAC_1000FD ); +phy_interface_copy (config->lpi_interfaces, + config->supported_interfaces); +__clear_bit (PHY_INTERFACE_MODE_2500BASEX , + config->lpi_interfaces); +/* tx_lpi_timer should be in microseconds. The time units for * LPI threshold are unspecified. */ config->lpi_timer_default =FIELD_GET (LPI_THRESH_MASK , eeecr); } - - priv->info->mac_port_get_caps (ds, port, config); } static int mt753x_pcs_validate(struct phylink_pcs *pcs,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 931/1250 net: ethernet: mtk_eth_soc: avoid writing to ESW registers on MT7628
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joris Vaisvila <[email protected]>
[ Upstream commit 9a04d3b2f0708a9e5e1f731bafb69b040bb934a0 ]
The MT7628 has a fixed-link PHY and does not expose MAC control registers. Writes to these registers only corrupt the ESW VLAN configuration.
This patch explicitly registers no-op phylink_mac_ops for MT7628, as after removing the invalid register accesses, the existing phylink_mac_ops effectively become no-ops.
This code was introduced by commit 296c9120752b ("net: ethernet: mediatek: Add MT7628/88 SoC support")
Stable-dep-of: d876c9cb2d16 ("net: ethernet: mtk_eth_soc: populate lpi_interfaces to fix EEE support")
--- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 34 ++++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-)
drivers/net/ethernet/mediatek/mtk_eth_soc.c +30 -4
@@ -562,9 +562,7 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode,int val, ge_mode, err =0 ;u32 i; -/* MT76x8 has no hardware settings between for the MAC */ -if (!MTK_HAS_CAPS (eth->soc->caps,MTK_SOC_MT7628 ) && - mac->interface != state->interface) { +if (mac->interface != state->interface) {/* Setup soc pin functions */ switch (state->interface) {case PHY_INTERFACE_MODE_TRGMII :
@@ -956,6 +954,30 @@ static const struct phylink_mac_ops mtk_phylink_ops = { .mac_enable_tx_lpi = mtk_mac_enable_tx_lpi, }; +static void rt5350_mac_config (struct phylink_config *config,unsigned int mode, +const struct phylink_link_state *state) +{ +} + +static void rt5350_mac_link_down (struct phylink_config *config,unsigned int mode, +phy_interface_t interface) +{ +} + +static void rt5350_mac_link_up (struct phylink_config *config, +struct phy_device *phy, +unsigned int mode,phy_interface_t interface, +int speed,int duplex,bool tx_pause,bool rx_pause) +{ +} + +/* MT76x8 (rt5350-eth) does not expose any MAC control registers */ +static const struct phylink_mac_ops rt5350_phylink_ops = { + .mac_config = rt5350_mac_config, + .mac_link_down = rt5350_mac_link_down, + .mac_link_up = rt5350_mac_link_up, +}; +static void mtk_mdio_config (struct mtk_eth *eth) {u32 val;
@@ -4798,6 +4820,7 @@ static const struct net_device_ops mtk_netdev_ops = {static int mtk_add_mac (struct mtk_eth *eth,struct device_node *np) { +const struct phylink_mac_ops *mac_ops = &mtk_phylink_ops;const __be32 *_id =of_get_property (np,"reg" ,NULL );phy_interface_t phy_mode;struct phylink *phylink;
@@ -4932,9 +4955,12 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) mac->phylink_config.supported_interfaces); } +if (MTK_HAS_CAPS (eth->soc->caps,MTK_SOC_MT7628 )) + mac_ops = &rt5350_phylink_ops; + phylink =phylink_create (&mac->phylink_config,of_fwnode_handle (mac->of_node), - phy_mode, &mtk_phylink_ops); + phy_mode, mac_ops);if (IS_ERR (phylink)) { err =PTR_ERR (phylink); goto free_netdev;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 932/1250 net: ethernet: mtk_eth_soc: fix supported_interface set after phylink_create
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Marangi <[email protected]>
[ Upstream commit e4b4d8410c7ccea25f4b332a077c6b9f5d263228 ]
Everything configured in phylink_config it's assumed to be set before calling phylink_create() to permit correct parsing of all the different modes and capabilities.
Commit 51cf06ddafc9 ("net: ethernet: mtk_eth_soc: add support for MT7988 internal 2.5G PHY") while introducing support for 2.5G phy for MT7988, probably due to an auto-rebase, placed the configuration of the INTERNAL interface mode for the supported_interfaces for phylink_config right after phylink_create() introducing a possible problem with supported interfaces parsing.
While this doesn't currently create any problem/bug, move setting this bit before phylink_create() to prevent any possible regression in future code change in phylink core.
Stable-dep-of: d876c9cb2d16 ("net: ethernet: mtk_eth_soc: populate lpi_interfaces to fix EEE support")
--- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/net/ethernet/mediatek/mtk_eth_soc.c +5 -5
@@ -4958,6 +4958,11 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)if (MTK_HAS_CAPS (eth->soc->caps,MTK_SOC_MT7628 )) mac_ops = &rt5350_phylink_ops; +if (MTK_HAS_CAPS (mac->hw->soc->caps,MTK_2P5GPHY ) && + id ==MTK_GMAC2_ID ) +__set_bit (PHY_INTERFACE_MODE_INTERNAL , + mac->phylink_config.supported_interfaces); + phylink =phylink_create (&mac->phylink_config,of_fwnode_handle (mac->of_node), phy_mode, mac_ops);
@@ -4968,11 +4973,6 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) mac->phylink = phylink; -if (MTK_HAS_CAPS (mac->hw->soc->caps,MTK_2P5GPHY ) && - id ==MTK_GMAC2_ID ) -__set_bit (PHY_INTERFACE_MODE_INTERNAL , - mac->phylink_config.supported_interfaces); -SET_NETDEV_DEV (eth->netdev[id], eth->dev); eth->netdev[id]->watchdog_timeo =5 *HZ ; eth->netdev[id]->netdev_ops = &mtk_netdev_ops;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 933/1250 net: ethernet: mtk_eth_soc: populate lpi_interfaces to fix EEE support
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aleksei Sviridkin <[email protected]>
[ Upstream commit d876c9cb2d16ed259449fe9da08c37a5cb81d724 ]
phylink_create() decides once and for all that a MAC supports managed EEE, and it requires the tx_lpi ops plus non-empty lpi_capabilities and lpi_interfaces. mtk_add_mac() leaves lpi_interfaces empty.
So ever since EEE support was added, ethtool has answered "Not supported" on every MAC that uses mtk_phylink_ops, and phy_disable_eee() has locked userspace out of turning EEE on. MT7628 is unaffected, as rt5350_phylink_ops has no tx_lpi methods.
Leave 2.5 Gbps out of both bitmaps, and the xGMII modes that mtk_mac_enable_tx_lpi() already refuses. MAC_MCR folds SPEED_2500 onto MAC_MCR_SPEED_1000, so MAC_MCR_EEE1G would govern LPI on such a link, and that is unvalidated rather than known unsupported: MediaTek's SDK driver sets the EEE force bits for 100 Mbps and 1 Gbps only, and the unit of the wakeup timers is undocumented with the port clock at 2.5 times the rate.
mtk_mac_enable_tx_lpi() programs wake-up times taken from MT7531's reset values, and the SoC's own field has no reset value to fall back on. Only MT7981 has been seen to exit LPI cleanly with them, so the LPI interfaces sit behind a new MTK_GMAC_EEE capability that only MT7981 sets; every other SoC keeps the current behaviour until it has been confirmed.
LPI stays off until userspace enables it, but the EEE advertisement of a PHY that advertises it out of reset comes back, since phylink stops force-clearing it.
--- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 18 +++++++++++++++--- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 4 +++- 2 files changed, 18 insertions(+), 4 deletions(-)
drivers/net/ethernet/mediatek/mtk_eth_soc.c +15 -3
@@ -4825,7 +4825,7 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)phy_interface_t phy_mode;struct phylink *phylink;struct mtk_mac *mac; -int id, err; +int id, err, i;int txqs =1 ;u32 val;
@@ -4904,8 +4904,8 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) mac->phylink_config.type =PHYLINK_NETDEV ; mac->phylink_config.mac_capabilities =MAC_ASYM_PAUSE |MAC_SYM_PAUSE |MAC_10 |MAC_100 |MAC_1000 |MAC_2500FD ; - mac->phylink_config.lpi_capabilities =MAC_100FD |MAC_1000FD | -MAC_2500FD ; +/* LPI above 1 Gbps is not supported */ + mac->phylink_config.lpi_capabilities =MAC_100FD |MAC_1000FD ; mac->phylink_config.lpi_timer_default =1000 ;/* MT7623 gmac0 is now missing its speed-specific PLL configuration
@@ -4963,6 +4963,18 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)__set_bit (PHY_INTERFACE_MODE_INTERNAL , mac->phylink_config.supported_interfaces); +/* LPI wake-up timing is only verified on MTK_GMAC_EEE SoCs */ +if (MTK_HAS_CAPS (eth->soc->caps,MTK_GMAC_EEE )) { +phy_interface_copy (mac->phylink_config.lpi_interfaces, + mac->phylink_config.supported_interfaces); +__clear_bit (PHY_INTERFACE_MODE_2500BASEX , + mac->phylink_config.lpi_interfaces); +for (i =0 ; i <PHY_INTERFACE_MODE_MAX ; i++) +if (mtk_interface_mode_is_xgmii (eth, i)) +__clear_bit (i, + mac->phylink_config.lpi_interfaces); + } + phylink =phylink_create (&mac->phylink_config,of_fwnode_handle (mac->of_node), phy_mode, mac_ops);
drivers/net/ethernet/mediatek/mtk_eth_soc.h +3 -1
@@ -994,6 +994,7 @@ enum mkt_eth_capabilities {MTK_U3_COPHY_V2_BIT ,MTK_SRAM_BIT ,MTK_36BIT_DMA_BIT , +MTK_GMAC_EEE_BIT ,/* MUX BITS*/ MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT,
@@ -1034,6 +1035,7 @@ enum mkt_eth_capabilities {#define MTK_U3_COPHY_V2 BIT_ULL(MTK_U3_COPHY_V2_BIT)#define MTK_SRAM BIT_ULL(MTK_SRAM_BIT)#define MTK_36BIT_DMA BIT_ULL(MTK_36BIT_DMA_BIT) +#define MTK_GMAC_EEE BIT_ULL(MTK_GMAC_EEE_BIT)#define MTK_ETH_MUX_GDM1_TO_GMAC1_ESW \ BIT_ULL(MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT)
@@ -1117,7 +1119,7 @@ enum mkt_eth_capabilities {#define MT7981_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | MTK_GMAC2_GEPHY | \ MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \ MTK_MUX_U3_GMAC2_TO_QPHY | MTK_U3_COPHY_V2 | \ - MTK_RSTCTRL_PPE1 | MTK_SRAM) + MTK_RSTCTRL_PPE1 | MTK_SRAM | MTK_GMAC_EEE)#define MT7986_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | \ MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 934/1250 net: phy: mediatek-ge: disable EEE on the MT7530 PHY
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vladislav Karmanov <[email protected]>
[ Upstream commit ccbe7540e4aad0d1c3acc249697350b93ccb8025 ]
The MT7530 internal GE PHY advertises EEE by hardware default, but its EEE support is defective: with EEE advertised, some link partners fail to establish a stable link. On a 2-pair (4-wire) cable where both ends advertise gigabit, 1000BASE-T training cannot succeed, and instead of falling back to 100 Mbps the port loops, so no link or DHCP lease is ever obtained. MediaTek confirms the hardware is the root cause (Landen Chao, 2021): "EEE of the 10-year-old MT7530 internal gephy has many IOT problems, so it is recommended to disable its EEE."
mtk_gephy_config_init() used to clear the EEE advertisement early, but commit af3b4b0e59de ("net: phy: mediatek-ge: do not disable EEE advertisement") removed that on the rationale that the DSA subdriver already performs an early disable. That holds for MT7531, whose mt7531_setup() clears MDIO_AN_EEE_ADV on each switch PHY, but not for the MT7530 PHY: neither the MT7621 integrated switch nor the dedicated MT7530 IC ever had such a loop, so removing it left those boards without any working early EEE disable and the link flapping came back.
Since the broken hardware is the PHY, fix it in the PHY driver so it covers all users of this PHY, integrated in a switch or standalone:
- clear MDIO_AN_EEE_ADV in probe(), as early as possible, before
anything can negotiate EEE with the link partner;
- clear it again in config_init() and call phy_disable_eee() there. config_init() is what phy_init_hw() replays after a PHY reset, when the register is back at its EEE-advertising hardware default, and it runs after of_set_phy_eee_broken() in phy_probe(), so the eee_disabled_modes mask survives and neither phylib nor userspace can re-enable EEE. dp83867 disables broken EEE from config_init() the same way.
Auto-negotiation then falls back to a stable 100 Mbps link instead of looping at gigabit. Tested on ASUS RT-AX53U (MT7621): with a 2-pair cable on the WAN port, a single clean 100 Mbps link comes up and a DHCP lease is obtained, where the unpatched driver loops.
--- drivers/net/phy/mediatek/mtk-ge.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
drivers/net/phy/mediatek/mtk-ge.c +29 -0
@@ -62,10 +62,38 @@ static void mtk_gephy_config_init(struct phy_device *phydev) FIELD_PREP(MTK_MCC_NEARECHO_OFFSET_MASK, 0x3)); } +static int mt7530_phy_probe (struct phy_device *phydev) +{ +/* The MT7530 internal GE PHY has broken EEE: with EEE advertised, +* some link partners fail to establish a stable link (on a 2-pair +* cable, 1000BASE-T training fails and the port loops instead of +* falling back). MediaTek recommends disabling EEE on this PHY. +* Clear the advertisement as early as possible, before anything +* can negotiate EEE with the link partner. +*/ +return phy_write_mmd (phydev,MDIO_MMD_AN ,MDIO_AN_EEE_ADV ,0 ); +} +static int mt7530_phy_config_init (struct phy_device *phydev) { +int ret; +mtk_gephy_config_init (phydev); +/* The probe() clear alone is not durable: phy_init_hw() replays only +* ->config_init after a PHY reset, with the register back at its +* EEE-advertising hardware default, and phy_probe() zeroes +* eee_disabled_modes (of_set_phy_eee_broken()) after ->probe already +* ran. Clear the advertisement again and mark EEE disabled, so that +* neither phylib nor userspace can re-enable it; dp83867 disables +* broken EEE from config_init() the same way. +*/ + ret =phy_write_mmd (phydev,MDIO_MMD_AN ,MDIO_AN_EEE_ADV ,0 ); +if (ret) +return ret; + +phy_disable_eee (phydev); +/* Increase post_update_timer */ phy_write_paged (phydev,MTK_PHY_PAGE_EXTENDED_3 ,MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG11 ,0x4b );
@@ -100,6 +128,7 @@ static struct phy_driver mtk_gephy_driver[] = { { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530), .name = "MediaTek MT7530 PHY", + .probe = mt7530_phy_probe, .config_init = mt7530_phy_config_init,/* Interrupts are handled by the switch, not the PHY * itself.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 935/1250 net: net_failover: Fix the deadlock in net_failover_slave_name_change()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Faicker Mo <[email protected]>
[ Upstream commit 985a663bf00799c1daf1c5789efa6406958780c8 ]
This is a sibling fix of commitb84c5632c7b3 ("net: net_failover: Fix the deadlock in slave register"). There is netdev_lock_ops() in the upper callers, so using netif_open() instead of dev_open().
Call Trace: __schedule+0x2bb/0x650 schedule+0x27/0xb0 schedule_preempt_disabled+0x15/0x30 __mutex_lock.constprop.0+0x550/0xaf0 __mutex_lock_slowpath+0x13/0x20 mutex_lock+0x3b/0x50 dev_open+0x3b/0xe0 net_failover_slave_name_change+0x22/0x40 failover_event+0xd4/0x1e0 notifier_call_chain+0x62/0xf0 raw_notifier_call_chain+0x16/0x30 call_netdevice_notifiers_info+0x50/0x80 netif_change_name+0x200/0x330 do_setlink.isra.0+0xb12/0xdf0 ? security_capable+0x9a/0x1e0 ? ns_capable+0x31/0x60 rtnl_setlink+0x302/0x670 ? netlink_recvmsg+0x296/0x340 ? security_capable+0x9a/0x1e0 ? __pfx_rtnl_setlink+0x10/0x10 rtnetlink_rcv_msg+0x384/0x460 ? __pfx_rtnetlink_rcv_msg+0x10/0x10 netlink_rcv_skb+0x61/0x120 rtnetlink_rcv+0x15/0x30 netlink_unicast+0x28f/0x3c0 netlink_sendmsg+0x216/0x450 __sys_sendto+0x222/0x230 __x64_sys_sendto+0x24/0x40 x64_sys_call+0x1d5d/0x2390 do_syscall_64+0x105/0x5a0 ? do_syscall_64+0x140/0x5a0 ? exc_page_fault+0x94/0x1e0 entry_SYSCALL_64_after_hwframe+0x76/0x7e
--- drivers/net/net_failover.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/net_failover.c +1 -1
@@ -675,7 +675,7 @@ static int net_failover_slave_name_change(struct net_device *slave_dev,/* We need to bring up the slave after the rename by udev in case * open failed with EBUSY when it was registered. */ -dev_open (slave_dev,NULL ); +netif_open (slave_dev,NULL );return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 936/1250 octeontx2-af: fix PF/CGX debugfs PCI bus lookup
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ratheesh Kannoth <[email protected]>
[ Upstream commit 4f4b743c2d2bbc336cb164d9d3d2ed6956ad8437 ]
rvu_dbg_rvu_pf_cgx_map_display() locates each RVU PF PCI device via pci_get_domain_bus_and_slot() when printing the PF-to-CGX map. It assumed PF0 always sits on PCI bus 1 and derived other PF bus numbers as pf + 1, but the AF device can be enumerated on a different bus.
Use rvu->pdev->bus->number as the base bus instead, so each PF lookup uses pf + start on systems where RVU functions are on contiguous buses but do not start at bus 1.
--- .../net/ethernet/marvell/octeontx2/af/rvu_debugfs.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c +8 -2
@@ -825,19 +825,25 @@ static int rvu_dbg_rvu_pf_cgx_map_display(struct seq_file *filp, void *unused)int pf, domain, blkid;u8 cgx_id, lmac_id;u16 pcifunc; +u8 start; - domain =2 ; + domain =pci_domain_nr (rvu->pdev->bus); mac_ops =get_mac_ops (rvu_first_cgx_pdata (rvu));/* There can be no CGX devices at all */ if (!mac_ops)return 0 ;seq_printf (filp,"PCI dev\t\tRVU PF Func\tNIX block\t%s\tLMAC\tCHAN\n" , mac_ops->name); + +/* All the PF devices are on contiguous PCI bus numbers, but the PF0(AF) +* may not start from 1 always. Hence get domain and bus from PCI device. +*/ + start = rvu->pdev->bus->number;for (pf =0 ; pf < rvu->hw->total_pfs; pf++) {if (!is_pf_cgxmapped (rvu, pf))continue ; - pdev =pci_get_domain_bus_and_slot (domain, pf +1 ,0 ); + pdev =pci_get_domain_bus_and_slot (domain, pf + start,0 );if (!pdev)continue ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 937/1250 net: phy: dp83867: handle the active-high LED polarity mode
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Donggeun Yoo <[email protected]>
[ Upstream commit 36a45facedd5c8e73bfb2403f8b0dbff05124c9c ]
Commit a274465cc3be ("net: phy: support 'active-high' property for PHY LEDs") added PHY_LED_ACTIVE_HIGH and made of_phy_led() set the matching bit in the modes mask when a LED node carries the 'active-high' property. dp83867 was not part of that series.
dp83867_led_polarity_set() only recognizes PHY_LED_ACTIVE_LOW, so PHY_LED_ACTIVE_HIGH falls through to the default case and returns -EINVAL. of_phy_led() propagates the error, of_phy_leds() drops the LEDs registered so far and passes it on, and phy_probe() fails. A device tree marking a DP83867 LED as 'active-high', which leds/common.yaml allows and ethernet-phy.yaml references for led@N nodes, thus stops the PHY from probing.
Active high is what the function programs when no polarity mode is requested at all, so the initial value of polarity already satisfies the request and only the case label is missing.
The same series updated mxl-gpy in commit eb89c79c1b8f ("net: phy:
mxl-gpy: correctly describe LED polarity") and aquantia in commit 9d55e68b19f2 ("net: phy: aquantia: correctly describe LED polarity override").
--- drivers/net/phy/dp83867.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/phy/dp83867.c +3 -0
@@ -1108,6 +1108,9 @@ static int dp83867_led_polarity_set(struct phy_device *phydev, int index,case PHY_LED_ACTIVE_LOW : polarity =0 ;break ; +case PHY_LED_ACTIVE_HIGH : + polarity =DP83867_LED_POLARITY (index); +break ;default :return -EINVAL ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 938/1250 net: mana: restore the XDP program pointer when pre-allocation fails
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Long Li <[email protected]>
[ Upstream commit 4c46beb807efcc93f5899ebe1f5958248eb296c6 ]
mana_xdp_set() publishes the new program into apc->bpf_prog before it allocates anything, because mana_pre_alloc_rxbufs() sizes the buffers from it via mana_get_rxbuf_cfg(). When that allocation fails the function returns the error directly, skipping the err_dealloc_rxbuffs label which is the only place that restores the previous pointer.
The attach is reported as failed, so the BPF core drops the reference it held for the caller and the program can be freed, while apc->bpf_prog still points at it. The next consumer of mana_xdp_get() - typically mana_chn_setxdp() from mana_alloc_queues() on the following ifup, or after a TX timeout reset - then calls bpf_prog_add() on freed memory.
This is reachable from an ordinary "ip link set dev ethX xdp obj ..." whenever the per-queue RX buffer pre-allocation cannot be satisfied.
Restore the previous program on that error path.
--- drivers/net/ethernet/microsoft/mana/mana_bpf.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ethernet/microsoft/mana/mana_bpf.c +1 -0
@@ -208,6 +208,7 @@ static int mana_xdp_set(struct net_device *ndev, struct bpf_prog *prog,if (err) {NL_SET_ERR_MSG_MOD (extack,"XDP: Insufficient memory for tx/rx re-config" ); + apc->bpf_prog = old_prog;return err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 939/1250 net/rds: fix tcp stream corruption with large pages
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Greg Marsden <[email protected]>
[ Upstream commit 2ac09b5353fe6858411fdc8c6efa60d832e20f13 ]
rds_message_map_pages() assigns PAGE_SIZE bytes to every scatterlist entry, even when total_len ends in a partial page. The RDS congestion map is defined as 8192 bytes, so on systems with PAGE_SIZE greater than 8192 the scatterlist maps bytes beyond the end of the congestion map. RDS-TCP transmits the SG contents according to those lengths, so the extra bytes become part of the TCP RDS stream and are interpreted as subsequent RDS message headers, corrupting the stream.
Limit the final scatterlist mapping to the number of bytes remaining. This has no effect on systems with a 4K page size and allows RDS-TCP to be used on systems with 16K and larger page sizes.
The RDS selftest, which previously hung on 16K pages, now passes.
--- net/rds/message.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
net/rds/message.c +3 -1
@@ -365,7 +365,9 @@ struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned infor (i =0 ; i < rm->data.op_nents; ++i) {sg_set_page (&rm->data.op_sg[i],virt_to_page ((void *)page_addrs[i]), -PAGE_SIZE ,0 ); + i == rm->data.op_nents -1 + ? total_len - (i *PAGE_SIZE ) + :PAGE_SIZE ,0 ); }return rm;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 940/1250 net: stmmac: fix TSO support when some channels have TBS available
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Russell King (Oracle) <[email protected]>
[ Upstream commit e32820264c2949a3e75bc5083e49c885e3bbaf62 ]
According to the STM32MP25xx manual, which is dwmac v5.3, TBS (time based scheduling) is not permitted for channels which have hardware TSO enabled. Intel's commit 5e6038b88a57 ("net: stmmac: fix TSO and TBS feature enabling during driver open") concurs with this, but it is incomplete.
This commit avoids enabling TSO support on the channels which have TBS available, which, as far as the hardware is concerned, means we do not set the TSE bit in the DMA channel's transmit control register.
However, the net device's features apply to all queues(channels), which means these channels may still be handed TSO skbs to transmit, and the driver will pass them to stmmac_tso_xmit(). This will generate the descriptors for TSO, even though the channel has the TSE bit clear.
Fix this by checking whether the queue(channel) has TBS available, and if it does, fall back to software GSO support.
Stable-dep-of: 5e38d732ec67 ("net: stmmac: fix TX descriptor availability check for TSO traffic")
--- .../net/ethernet/stmicro/stmmac/stmmac_main.c | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-)
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +28 -4
@@ -3390,6 +3390,17 @@ static void stmmac_safety_feat_configuration(struct stmmac_priv *priv) } } +/* STM32MP25xx (dwmac v5.3) states "Do not enable time-based scheduling for +* channels on which the TSO feature is enabled." If we have a skb for a +* channel which has TBS enabled, fall back to software GSO. +*/ +static bool stmmac_tso_channel_permitted (struct stmmac_priv *priv, +unsigned int chan) +{ +/* TSO and TBS cannot co-exist */ +return !(priv->dma_conf.tx_queue[chan].tbs &STMMAC_TBS_AVAIL ); +} +/** * stmmac_hw_setup - setup mac in a usable state. * @dev : pointer to the device structure.
@@ -3502,10 +3513,7 @@ static int stmmac_hw_setup(struct net_device *dev)/* Enable TSO */ if (priv->tso) {for (chan =0 ; chan < tx_cnt; chan++) { -struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan]; - -/* TSO and TBS cannot co-exist */ -if (tx_q->tbs &STMMAC_TBS_AVAIL ) +if (!stmmac_tso_channel_permitted (priv, chan))continue ;stmmac_enable_tso (priv, priv->ioaddr,1 , chan);
@@ -4728,6 +4736,21 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)return NETDEV_TX_OK ; } +static netdev_features_t stmmac_features_check (struct sk_buff *skb, +struct net_device *dev, +netdev_features_t features) +{ +u16 queue; + +if (skb_is_gso (skb)) { + queue =skb_get_queue_mapping (skb); +if (!stmmac_tso_channel_permitted (netdev_priv (dev), queue)) + features &= ~NETIF_F_GSO_MASK ; + } + +return vlan_features_check (skb, features); +} +static void stmmac_rx_vlan (struct net_device *dev,struct sk_buff *skb) {struct vlan_ethhdr *veth =skb_vlan_eth_hdr (skb);
@@ -7097,6 +7120,7 @@ static void stmmac_get_stats64(struct net_device *dev, struct rtnl_link_stats64static const struct net_device_ops stmmac_netdev_ops = { .ndo_open = stmmac_open, .ndo_start_xmit = stmmac_xmit, + .ndo_features_check = stmmac_features_check, .ndo_stop = stmmac_release, .ndo_change_mtu = stmmac_change_mtu, .ndo_fix_features = stmmac_fix_features,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 941/1250 net: stmmac: add stmmac_tso_header_size()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Russell King (Oracle) <[email protected]>
[ Upstream commit f799b5dab9c98a4b52a93d1c357916e0f0b7e663 ]
We will need to compute the size of the protocol headers in two places, so move this into a separate function.
Stable-dep-of: 5e38d732ec67 ("net: stmmac: fix TX descriptor availability check for TSO traffic")
--- .../net/ethernet/stmicro/stmmac/stmmac_main.c | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-)
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +15 -5
@@ -4164,6 +4164,18 @@ static void stmmac_flush_tx_descriptors(struct stmmac_priv *priv, int queue)stmmac_set_tx_tail_ptr (priv, priv->ioaddr, tx_q->tx_tail_addr, queue); } +static size_t stmmac_tso_header_size (struct sk_buff *skb) +{ +size_t size; + +if (skb_shinfo (skb)->gso_type &SKB_GSO_UDP_L4 ) + size =skb_transport_offset (skb) +sizeof (struct udphdr ); +else + size =skb_tcp_all_headers (skb); + +return size; +} +/** * stmmac_tso_xmit - Tx entry point of the driver for oversized frames (TSO) * @skb : the socket buffer
@@ -4235,13 +4247,11 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) first_tx = tx_q->cur_tx;/* Compute header lengths */ -if (skb_shinfo (skb)->gso_type &SKB_GSO_UDP_L4 ) { - proto_hdr_len =skb_transport_offset (skb) +sizeof (struct udphdr ); + proto_hdr_len =stmmac_tso_header_size (skb); +if (skb_shinfo (skb)->gso_type &SKB_GSO_UDP_L4 ) hdr =sizeof (struct udphdr ); - }else { - proto_hdr_len =skb_tcp_all_headers (skb); +else hdr =tcp_hdrlen (skb); - }/* Desc availability based on threshold should be enough safe */ if (unlikely(stmmac_tx_avail(priv, queue) <
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 942/1250 net: stmmac: add TSO check for header length
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Russell King (Oracle) <[email protected]>
[ Upstream commit 6732e474f880468435a79d05811c8c814c5d71f8 ]
According to the STM32MP151 documentation which covers dwmac v4.2, the hardware TSO feature can handle header lengths up to a maximum of 1023 bytes.
Add a .ndo_features_check() method implementation to check the header length meets these requirements, otherwise fall back to software GSO.
Stable-dep-of: 5e38d732ec67 ("net: stmmac: fix TX descriptor availability check for TSO traffic")
--- .../net/ethernet/stmicro/stmmac/stmmac_main.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-)
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +16 -1
@@ -4176,6 +4176,20 @@ static size_t stmmac_tso_header_size(struct sk_buff *skb)return size; } +/* STM32MP151 (dwmac v4.2) and STM32MP25xx (dwmac v5.3) states for TDES2 normal +* (read format) descriptor that the maximum header length supported for the +* TSO feature is 1023 bytes. +* +* While IPv4 is limited to MAC+VLAN+IPv4+ext+TCP+ext = 138 bytes, the IPv6 +* extension headers aren't similarly limited. +*/ +static bool stmmac_tso_valid_packet (struct sk_buff *skb) +{ +size_t header_len =stmmac_tso_header_size (skb); + +return header_len <=1023 ; +} +/** * stmmac_tso_xmit - Tx entry point of the driver for oversized frames (TSO) * @skb : the socket buffer
@@ -4754,7 +4768,8 @@ static netdev_features_t stmmac_features_check(struct sk_buff *skb,if (skb_is_gso (skb)) { queue =skb_get_queue_mapping (skb); -if (!stmmac_tso_channel_permitted (netdev_priv (dev), queue)) +if (!stmmac_tso_channel_permitted (netdev_priv (dev), queue) || + !stmmac_tso_valid_packet (skb)) features &= ~NETIF_F_GSO_MASK ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 943/1250 net: stmmac: fix TX descriptor availability check for TSO traffic
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <[email protected]>
[ Upstream commit 5e38d732ec67a5b1f9a56e6c73add480c4b6030a ]
stmmac_tso_xmit() estimates the number of free TX descriptors required by a TSO skb as:
(skb->len - proto_hdr_len) / TSO_MAX_BUFF_SIZE + 1
which assumes the payload is split into TSO_MAX_BUFF_SIZE chunks. This underestimates the descriptors actually consumed by stmmac_tso_allocator(), since each fragment is mapped individually and so it needs at least one descriptor regardless of its size. Moreover, one descriptor is used for the L2/L3/L4 headers and, when the MSS changes, one more is consumed for the MSS context descriptor.
For a highly fragmented TSO skb the check can therefore pass even when the ring has too few free slots. stmmac_tso_allocator() then writes past the available descriptors, overwriting descriptors still owned by the DMA engine, corrupting the TX ring.
Add stmmac_tso_get_num_desc() to compute the exact number of descriptors needed for the header, the linear payload and each fragment, plus the MSS context descriptor when required, and use it in the availability check.
--- .../net/ethernet/stmicro/stmmac/stmmac_main.c | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-)
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +25 -6
@@ -4190,6 +4190,26 @@ static bool stmmac_tso_valid_packet(struct sk_buff *skb)return header_len <=1023 ; } +static int stmmac_tso_get_num_desc (struct stmmac_tx_queue *tx_q, +struct sk_buff *skb,u32 pay_len) +{ +int i, ndesc =1 ; + +/* head payload */ + ndesc +=DIV_ROUND_UP (pay_len,TSO_MAX_BUFF_SIZE ); +/* frag payload */ +for (i =0 ; i <skb_shinfo (skb)->nr_frags; i++) { +const skb_frag_t *frag = &skb_shinfo (skb)->frags[i]; + + ndesc +=DIV_ROUND_UP (skb_frag_size (frag), +TSO_MAX_BUFF_SIZE ); + } +/* MSS update requires a new descriptor */ + ndesc += !!(skb_shinfo (skb)->gso_size != tx_q->mss); + +return ndesc; +} +/** * stmmac_tso_xmit - Tx entry point of the driver for oversized frames (TSO) * @skb : the socket buffer
@@ -4233,9 +4253,9 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)struct stmmac_priv *priv =netdev_priv (dev);unsigned int first_entry, tx_packets;struct stmmac_txq_stats *txq_stats; +int i, first_tx, nfrags, ndesc;struct stmmac_tx_queue *tx_q;u32 pay_len, mss, queue; -int i, first_tx, nfrags;u8 proto_hdr_len, hdr;dma_addr_t des;bool set_ic;
@@ -4262,14 +4282,15 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)/* Compute header lengths */ proto_hdr_len =stmmac_tso_header_size (skb); + pay_len =skb_headlen (skb) - proto_hdr_len;/* no frags */ +if (skb_shinfo (skb)->gso_type &SKB_GSO_UDP_L4 ) hdr =sizeof (struct udphdr );else hdr =tcp_hdrlen (skb); -/* Desc availability based on threshold should be enough safe */ -if (unlikely (stmmac_tx_avail (priv, queue) < - (((skb->len - proto_hdr_len) /TSO_MAX_BUFF_SIZE +1 )))) { + ndesc =stmmac_tso_get_num_desc (tx_q, skb, pay_len); +if (unlikely (stmmac_tx_avail (priv, queue) < ndesc)) {if (!netif_tx_queue_stopped (netdev_get_tx_queue (dev, queue))) {netif_tx_stop_queue (netdev_get_tx_queue (priv->dev, queue));
@@ -4281,8 +4302,6 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)return NETDEV_TX_BUSY ; } - pay_len =skb_headlen (skb) - proto_hdr_len;/* no frags */ - mss =skb_shinfo (skb)->gso_size;/* set new MSS value if needed */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 944/1250 net: hsr: enable promiscuous mode on interlink port with fwd offload
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: MD Danish Anwar <[email protected]>
[ Upstream commit a2dc179481d18f6df7274522571b64dd50f31e81 ]
hsr_portdev_setup() skips promiscuous mode on non-master ports when hsr->fwd_offloaded is set. fwd_offloaded is derived only from the ring slaves' NETIF_F_HW_HSR_FWD bit, so this also skips it for the interlink port, which never gets forwarding offload. Without promiscuous mode, the interlink NIC drops unicast frames addressed to hsr_dev's MAC (e.g. SAN traffic to the RedBox), breaking RedBox whenever the ring is HW-offloaded.
--- net/hsr/hsr_slave.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
net/hsr/hsr_slave.c +7 -4
@@ -149,9 +149,12 @@ static int hsr_portdev_setup(struct hsr_priv *hsr, struct net_device *dev,int res;/* Don't use promiscuous mode for offload since L2 frame forward -* happens at the offloaded hardware. +* happens at the offloaded hardware. The interlink port never +* gets forwarding offload (RedBox forwarding to/from it is done +* by this driver), so it still needs promiscuous mode to receive +* frames addressed to hsr_dev's MAC rather than its own. */ -if (!port->hsr->fwd_offloaded) { +if (!port->hsr->fwd_offloaded || port->type ==HSR_PT_INTERLINK ) { res =dev_set_promiscuity (dev,1 );if (res)return res;
@@ -176,7 +179,7 @@ static int hsr_portdev_setup(struct hsr_priv *hsr, struct net_device *dev, fail_rx_handler:netdev_upper_dev_unlink (dev, hsr_dev); fail_upper_dev_link: -if (!port->hsr->fwd_offloaded) +if (!port->hsr->fwd_offloaded || port->type ==HSR_PT_INTERLINK )dev_set_promiscuity (dev,-1 );return res;
@@ -240,7 +243,7 @@ void hsr_del_port(struct hsr_port *port)netdev_update_features (master->dev);dev_set_mtu (master->dev,hsr_get_max_mtu (hsr));netdev_rx_handler_unregister (port->dev); -if (!port->hsr->fwd_offloaded) +if (!port->hsr->fwd_offloaded || port->type ==HSR_PT_INTERLINK )dev_set_promiscuity (port->dev,-1 );if (port->type ==HSR_PT_SLAVE_A || port->type ==HSR_PT_SLAVE_B )vlan_vids_del_by_dev (port->dev, master->dev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 945/1250 openvswitch: fix wrong flag value in get_ipv6_ext_hdrs()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eelco Chaudron <[email protected]>
[ Upstream commit e184a4a6f423550a25adce867036cdb1ff471745 ]
The ESP and AH cases in get_ipv6_ext_hdrs() used IPPROTO_FRAGMENT instead of OFPIEH12_FRAG when checking for out-of-order extension headers, causing the fragment header to not be recognised as a valid predecessor.
The original code used IPPROTO_FRAGMENT (44) as a bitmask constant where OFPIEH12_FRAG (1 << 4 = 16) was intended. IPPROTO_FRAGMENT encodes bits 2, 3 and 5 (OFPIEH12_AUTH | OFPIEH12_DEST | OFPIEH12_ROUTER), but not bit 4 (OFPIEH12_FRAG). This caused incorrect OFPIEH12_UNSEQ verdicts in both the ESP and AH arms: the ESP arm failed to whitelist OFPIEH12_FRAG, while the AH arm accidentally whitelisted OFPIEH12_AUTH.
With the fix, a packet with two AH headers now also gets OFPIEH12_UNSEQ in addition to OFPIEH12_UNREP, matching the ESP arm which already sets UNSEQ on a repeat, which is the intended behavior.
--- net/openvswitch/flow.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/openvswitch/flow.c +2 -2
@@ -288,7 +288,7 @@ static void get_ipv6_ext_hdrs(struct sk_buff *skb, struct ipv6hdr *nh,if (*ext_hdrs &OFPIEH12_ESP ) *ext_hdrs |=OFPIEH12_UNREP ;if ((*ext_hdrs & ~(OFPIEH12_HOP |OFPIEH12_DEST | -OFPIEH12_ROUTER |IPPROTO_FRAGMENT | +OFPIEH12_ROUTER |OFPIEH12_FRAG |OFPIEH12_AUTH |OFPIEH12_UNREP )) || dest_options_header_count >=2 ) { *ext_hdrs |=OFPIEH12_UNSEQ ;
@@ -301,7 +301,7 @@ static void get_ipv6_ext_hdrs(struct sk_buff *skb, struct ipv6hdr *nh, *ext_hdrs |=OFPIEH12_UNREP ;if ((*ext_hdrs & ~(OFPIEH12_HOP |OFPIEH12_DEST |OFPIEH12_ROUTER | -IPPROTO_FRAGMENT |OFPIEH12_UNREP )) || +OFPIEH12_FRAG |OFPIEH12_UNREP )) || dest_options_header_count >=2 ) { *ext_hdrs |=OFPIEH12_UNSEQ ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 946/1250 sunvdc: unmap LDC cookies when the descriptor send fails
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stian Halseth <[email protected]>
[ Upstream commit 0c6da21fa35e03fc74f09895433ccd6d4a9c3530 ]
__send_request() maps the request's pages into the LDC channel's map table (ldc_map_sg()), fills in the descriptor and marks it VIO_DESC_READY before ringing the doorbell via __vdc_tx_trigger(). When the trigger fails, the error path only prints a message: the descriptor stays READY and the cookies are never unmapped. The mapping is normally released in vdc_end_one() when the peer completes the descriptor - but a descriptor whose doorbell was never sent will never complete, and since dr->prod is not advanced on failure, the reset path (vdc_requeue_inflight(), which walks [cons, prod)) never visits it either. The map table entries are leaked permanently.
Since commit a11f6ca9aef9 ("sunvdc: Do not spin in an infinite loop when vio_ldc_send() returns EAGAIN") trigger failures occur in practice under load, so every resulting I/O error also leaks one request's worth of entries from the fixed-size (8192 entries per channel) map table. Because the allocator hands out contiguous ranges, fragmentation makes large multi-segment requests fail first as the table drains, until ldc_map_sg() fails permanently and the disk is dead until reboot.
It also makes any retry-based recovery unusable: requeuing the request on -EAGAIN remaps the pages on every attempt, overwriting desc->cookies and orphaning the previous mapping, so the table drains at the retry rate. This is the memory exhaustion observed when the requeue approach was first tested in October 2025.
Roll back on failure: unmap the cookies, mark the descriptor FREE again and clear the request entry. If the trigger failed with -ENOTCONN, __vdc_tx_trigger() has already reset the port, which tears down and reallocates both the dring and the LDC channel including its map table - nothing to roll back, and the stale descriptor must not be touched.
--- drivers/block/sunvdc.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
drivers/block/sunvdc.c +17 -0
@@ -525,6 +525,23 @@ static int __send_request(struct request *req) err =__vdc_tx_trigger (port);if (err <0 ) { printk(KERN_ERR PFX "vdc_tx_trigger() failure, err=%d\n", err); +/* +* If the port was reset (-ENOTCONN), the dring and the +* LDC channel including all of its mappings are already +* torn down and reallocated - there is nothing to undo +* and @desc must not be touched. +* +* For any other failure the descriptor was never handed +* to the peer: unmap the cookies and free the descriptor +* again, so that a later retry of the request does not +* leak LDC map table entries. +*/ +if (err != -ENOTCONN ) { +ldc_unmap (port->vio.lp, desc->cookies, + desc->ncookies); + desc->hdr.state =VIO_DESC_FREE ; + rqe->req =NULL ; + } }else { port->req_id++; dr->prod =vio_dring_next (dr, dr->prod);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 947/1250 erofs: add missing buf->off in erofs_bread()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Binglei Wang <[email protected]>
[ Upstream commit 135d84c66f85426299db01a09d93a79a87af18ba ]
erofs_bread() locates the target folio with
index = (buf->off + offset) >> PAGE_SHIFT;
but computes the in-folio offset without taking buf->off into account:
return buf->base + (offset & ~PAGE_MASK);
If buf->off is not page-aligned, the returned pointer misses the in-page component of buf->off, so callers end up fetching data from a wrong offset.
buf->off is set to sbi->dif0.fsoff in erofs_init_metabuf(), and fsoff can be specified via the "fsoffset=" mount option, which only requires block-size alignment. Therefore, on an image with a sub-page block size (e.g. 512 bytes), a non-page-aligned fsoff (e.g. 512) triggers the issue, since 512 is a multiple of the block size but not of PAGE_SIZE.
It can be reproduced by mounting an image that is placed at a non-page-aligned offset:
mkfs.erofs -b512 -zlz4hc sub.erofs src/
# prepend 512 bytes of padding to the image mount -t erofs -o loop,fsoffset=512 padded.erofs /mnt
which fails with
erofs (device loop0): cannot find valid erofs superblock
because the on-disk superblock (at offset 1024 within the image, i.e. 1536 within the padded file) is read from a wrong in-folio offset. With this fixed, the very same image mounts successfully and its file contents match those read from the unpadded image.
Fix it by including buf->off in the in-folio offset calculation, so that it is consistent with the folio index calculation.
--- fs/erofs/data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/erofs/data.c +1 -1
@@ -46,7 +46,7 @@ void *erofs_bread(struct erofs_buf *buf, erofs_off_t offset, bool need_kmap)return NULL ;if (!buf->base) buf->base =kmap_local_page (buf->page); -return buf->base + (offset & ~PAGE_MASK ); +return buf->base + ((buf->off + offset) & ~PAGE_MASK ); } int erofs_init_metabuf(struct erofs_buf *buf, struct super_block *sb,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 948/1250 scripts/mksysmap: drop the MODULE_INFO() symbols from kallsyms
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Stoakes (ARM) <[email protected]>
[ Upstream commit 281b61d408d4c39544583e393c6707af0ef5ee50 ]
Commit 3e86e4d74c04 ("kbuild: keep .modinfo section in vmlinux.unstripped") keeps .modinfo symbols out of System.map and kallsyms, which assumes unique IDs have a format like '__UNIQUE_ID_modinfo123'.
However, commit afb026b6d35c ("compiler: Tweak __UNIQUE_ID() naming"), sent in the same cycle, changes this to '__UNIQUE_ID_modinfo_123'.
As a result this regexp has never matched and every kernel since v6.18 has carried one kallsyms entries for every MODULE_INFO() declaration in the kernel whether the modules are compiled or not.
That's 5,810 entries for an x86 defconfig build and 15,200 for arm64.
On x86 defconfig that is 113 KiB of kallsyms tables and 32 KiB of bzImage, and every lookup walks past them.
Fix the pattern.
--- scripts/mksysmap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
scripts/mksysmap +1 -1
@@ -83,7 +83,7 @@ / _SDA2_BASE_$/d # MODULE_INFO() -/ __UNIQUE_ID_modinfo[0-9]*$/d +/ __UNIQUE_ID_modinfo_[0-9]*$/d # --------------------------------------------------------------------------- # Ignored patterns
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 949/1250 scripts/mksysmap: fix escape of $ in the __pi_ pattern
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Stoakes (ARM) <[email protected]>
[ Upstream commit 59351365ac271b5e0eb180f211c531476a36221f ]
Commit b18b047002b7 ("kbuild: change scripts/mksysmap into sed script") converted scripts/mksysmap from a shell script to a sed script.
However an error was made - escaping of '$' required \\ escaping in shell but only \ in a sed script.
This was mostly corrected in commit 7a6c355b55c0 ("scripts/mksysmap: Fix escape chars '$'"), but this fix missed arm64 PIE namespace local symbols like __pi_$x and __pi_$d which appear in System.map and /proc/kallsyms:
$ grep __pi_\\$ /proc/kallsyms | sort -u 0000000000000000 d __pi_$d 0000000000000000 t __pi_$x
Fix the escaping properly.
--- scripts/mksysmap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
scripts/mksysmap +1 -1
@@ -35,7 +35,7 @@ / __efistub_/d # arm64 local symbols in PIE namespace -/ __pi_\\$/d +/ __pi_\$/d / __pi_\.L/d # arm64 local symbols in non-VHE KVM namespace
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 950/1250 scsi: target: iscsi: Fix hang for aborted WRITE_PENDING commands
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maurizio Lombardi <[email protected]>
[ Upstream commit d5869dae5080e976d4b03cc33eb7ceb527f242bf ]
When a LUN_RESET aborts a WRITE command that is in the TRANSPORT_WRITE_PENDING state, the target core sets CMD_T_ABORTED and waits for the frontend to finish processing.
If the initiator subsequently sends the remaining dataout PDUs, __iscsit_check_dataout_hdr() catches the payload, stops the dataout timer if the sequence is final and finally dumps the data. However, the iSCSI target doesn't trigger the completion process for these aborted commands. Because of this, the abort path hangs indefinitely in target_put_cmd_and_wait(), leading to a deadlocked target worker thread.
Fix this by explicitly calling target_complete_cmd() when the final dataout PDU is received for an aborted WRITE command. target_complete_cmd() detects the CMD_T_ABORTED flag and cleanly routes the command into target_abort_work, allowing the abort completion to successfully unblock.
--- drivers/target/iscsi/iscsi_target.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/target/iscsi/iscsi_target.c +3 -1
@@ -1519,8 +1519,10 @@ __iscsit_check_dataout_hdr(struct iscsit_conn *conn, void *buf,*/ if (se_cmd->transport_state &CMD_T_ABORTED ) {if (hdr->flags &ISCSI_FLAG_CMD_FINAL && - --cmd->outstanding_r2ts <1 ) + --cmd->outstanding_r2ts <1 ) {iscsit_stop_dataout_timer (cmd); +target_complete_cmd (se_cmd,SAM_STAT_TASK_ABORTED ); + }return iscsit_dump_data_payload (conn, payload_length,1 ); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 951/1250 ksmbd: prevent out-of-bounds reads in share config responses
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit f25e93768fcc5d8287e50b1ec52a42e4c276df34 ]
Validate IPC share configuration payload sizes before consuming variable-length fields. Bound veto list parsing and account for the separator byte when deriving the path length.
--- fs/smb/server/mgmt/share_config.c | 38 +++++++++++++++++++++++-------- fs/smb/server/transport_ipc.c | 21 +++++++++++------ 2 files changed, 42 insertions(+), 17 deletions(-)
fs/smb/server/mgmt/share_config.c +28 -10
@@ -88,9 +88,9 @@ static struct ksmbd_share_config *__share_lookup(const char *name)static int parse_veto_list (struct ksmbd_share_config *share,char *veto_list, -int veto_list_sz) +size_t veto_list_sz) { -int sz =0 ; +size_t sz;if (!veto_list_sz)return 0 ;
@@ -98,7 +98,7 @@ static int parse_veto_list(struct ksmbd_share_config *share,while (veto_list_sz >0 ) {struct ksmbd_veto_pattern *p; - sz =strlen (veto_list); + sz =strnlen (veto_list, veto_list_sz);if (!sz)break ;
@@ -106,7 +106,7 @@ static int parse_veto_list(struct ksmbd_share_config *share,if (!p)return -ENOMEM ; - p->pattern =kstrdup (veto_list,KSMBD_DEFAULT_GFP ); + p->pattern =kstrndup (veto_list, sz,KSMBD_DEFAULT_GFP );if (!p->pattern) {kfree (p);return -ENOMEM ;
@@ -114,6 +114,9 @@ static int parse_veto_list(struct ksmbd_share_config *share,list_add (&p->list, &share->veto_list); +if (sz == veto_list_sz) +break ; + veto_list += sz +1 ; veto_list_sz -= (sz +1 ); }
@@ -165,13 +168,27 @@ static struct ksmbd_share_config *share_config_request(struct ksmbd_work *work, }if (!test_share_config_flag (share,KSMBD_SHARE_FLAG_PIPE )) { -int path_len =PATH_MAX ; +size_t path_len; -if (resp->payload_sz) +if (resp->payload_sz <= resp->veto_list_sz) { + ret = -EINVAL ; + }else { path_len = resp->payload_sz - resp->veto_list_sz; - - share->path =kstrndup (ksmbd_share_config_path (resp), path_len, -KSMBD_DEFAULT_GFP ); +if (resp->veto_list_sz) + path_len--; + +if (!path_len) { + ret = -EINVAL ; + }else { + share->path =kstrndup ( +ksmbd_share_config_path (resp), + path_len,KSMBD_DEFAULT_GFP ); +if (!share->path) + ret = -ENOMEM ; +else + ret =0 ; + } + }if (share->path) { share->path_sz =strlen (share->path); while (share->path_sz > 1 &&
@@ -184,7 +201,8 @@ static struct ksmbd_share_config *share_config_request(struct ksmbd_work *work, share->force_directory_mode = resp->force_directory_mode; share->force_uid = resp->force_uid; share->force_gid = resp->force_gid; - ret =parse_veto_list (share, +if (!ret) + ret =parse_veto_list (share,KSMBD_SHARE_CONFIG_VETO_LIST (resp), resp->veto_list_sz);if (!ret && share->path) {
fs/smb/server/transport_ipc.c +14 -7
@@ -524,14 +524,21 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry)if (entry->msg_sz <sizeof (struct ksmbd_share_config_response ))return -EINVAL ; -if (resp->payload_sz) { -if (resp->payload_sz < resp->veto_list_sz) -return -EINVAL ; +if (strnlen (resp->share_name,sizeof (resp->share_name)) == +sizeof (resp->share_name)) +return -EINVAL ; -if (check_add_overflow (sizeof (struct ksmbd_share_config_response ), - resp->payload_sz, &msg_sz)) -return -EINVAL ; - } +if (resp->veto_list_sz > resp->payload_sz) +return -EINVAL ; + +if (resp->flags !=KSMBD_SHARE_FLAG_INVALID && + !(resp->flags &KSMBD_SHARE_FLAG_PIPE ) && + resp->payload_sz <= resp->veto_list_sz) +return -EINVAL ; + +if (check_add_overflow (sizeof (struct ksmbd_share_config_response ), + resp->payload_sz, &msg_sz)) +return -EINVAL ;break ; }case KSMBD_EVENT_LOGIN_REQUEST_EXT :
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 952/1250 configfs: pin the symlink targets dirent instead of chasing ->ci_dentry
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vasileios Almpanis <[email protected]>
commit a7c1290eef60711c10289c056ad32ed1f2b47b12 upstream.
create_link() reads the target's configfs_dirent from item->ci_dentry->d_fsdata, relying on the item reference taken by get_target(). That reference pins the item, not its dentry: the dentry is pinned by DCACHE_PERSISTENT, which configfs_remove_dir() releases via simple_rmdir() while the item is still alive. A symlink racing with rmdir of its target can therefore find ->ci_dentry freed and its dirent released, triggering WARN_ON(!atomic_read(&sd->s_count)) in configfs_get().
Take the dirent in get_target() as well, under ->d_lock and atomically with the item reference, and pass it down to create_link(). A hashed dentry has not been killed yet, so its ->d_fsdata reference keeps the dirent alive there.
--- fs/configfs/symlink.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-)
fs/configfs/symlink.c +20 -4
@@ -76,9 +76,9 @@ static int configfs_get_target_path(strustatic int create_link (struct config_item *parent_item,struct config_item *item, +struct configfs_dirent *target_sd,struct dentry *dentry) { -struct configfs_dirent *target_sd = item->ci_dentry->d_fsdata;char *body;int ret;
@@ -115,6 +115,7 @@ static int create_link(struct config_itestatic int get_target (const char *symname,struct config_item **target, +struct configfs_dirent **target_sd,struct super_block *sb) { struct path path __free(path_put) = {};
@@ -125,7 +126,20 @@ static int get_target(const char *symnamreturn ret;if (path.dentry->d_sb != sb)return -EPERM ; - *target =configfs_get_config_item (path.dentry); +/* +* A hashed dentry guarantees that neither the item nor the dirent +* have been released yet, as removals unhash before dropping. +* Grab both references here. An item reference alone would not keep +* ->ci_dentry alive. +*/ +spin_lock (&path.dentry->d_lock); +if (!d_unhashed (path.dentry)) { +struct configfs_dirent *sd = path.dentry->d_fsdata; + + *target =config_item_get (sd->s_element); + *target_sd =configfs_get (sd); + } +spin_unlock (&path.dentry->d_lock);if (!*target)return -ENOENT ;return 0 ;
@@ -139,6 +153,7 @@ int configfs_symlink(struct mnt_idmap *istruct configfs_dirent *sd;struct config_item *parent_item;struct config_item *target_item =NULL ; +struct configfs_dirent *target_sd =NULL ;const struct config_item_type *type; sd = dentry->d_parent->d_fsdata;
@@ -182,7 +197,7 @@ int configfs_symlink(struct mnt_idmap *i* AV, a thoroughly annoyed bastard. */ inode_unlock (dir); - ret =get_target (symname, &target_item, dentry->d_sb); + ret =get_target (symname, &target_item, &target_sd, dentry->d_sb);inode_lock (dir);if (ret) goto out_put;
@@ -196,13 +211,14 @@ int configfs_symlink(struct mnt_idmap *i ret = type->ct_item_ops->allow_link (parent_item, target_item);if (!ret) {mutex_lock (&configfs_symlink_mutex); - ret =create_link (parent_item, target_item, dentry); + ret =create_link (parent_item, target_item, target_sd, dentry);mutex_unlock (&configfs_symlink_mutex);if (ret && type->ct_item_ops->drop_link) type->ct_item_ops->drop_link (parent_item, target_item); } +configfs_put (target_sd);config_item_put (target_item); out_put:
Greg Kroah-Hartman
maintainerPATCH 953/1250 powerpc/ps3: Fix repository.c build failure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thorsten Blum <[email protected]>
commit 5ba79d37403d86082ab4083b0f51ec3008a942cb upstream.
GCC fails to build ps3_defconfig with the following errors:
arch/powerpc/platforms/ps3/repository.c: In function ‘make_first_field.constprop’:
arch/powerpc/platforms/ps3/repository.c:78:9: error: ‘strnlen’ specified bound 8 exceeds source size 3 [-Werror=stringop-overread]
78 | memcpy((char *)&n, text, strnlen(text, sizeof(n)));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
arch/powerpc/platforms/ps3/repository.c: In function ‘make_first_field.constprop’:
arch/powerpc/platforms/ps3/repository.c:78:9: error: ‘strnlen’ specified bound 8 exceeds source size 4 [-Werror=stringop-overread]
78 | memcpy((char *)&n, text, strnlen(text, sizeof(n)));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~The current use of strnlen(text, sizeof(n)) triggers -Wstringop-overread when text is a short string literal that is smaller than sizeof(n), such as "bi" or "bus". Use strlen(text) instead and clamp the copy length to sizeof(n) before memcpy().
Drop the redundant char * cast while at it.
--- arch/powerpc/platforms/ps3/repository.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
arch/powerpc/platforms/ps3/repository.c +4 -1
@@ -6,6 +6,8 @@* Copyright 2006 Sony Corp. */ +#include <linux/minmax.h> +#include <asm/lv1call.h> #include "platform.h"
@@ -74,8 +76,9 @@ static void _dump_node(unsigned int lparstatic u64 make_first_field (const char *text,u64 index) {u64 n =0 ; +size_t len =min (strlen (text),sizeof (n)); -memcpy ((char *)&n, text,strnlen (text,sizeof (n))); +memcpy (&n, text, len);return PS3_VENDOR_ID_NONE + (n >>32 ) + index; }
Greg Kroah-Hartman
maintainerPATCH 954/1250 powerpc/eeh: Fix recursive locking on devices without EEH sensitive driver
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shivaprasad G Bhat <[email protected]>
commit c5e68706527968282e49de205cc2b935823cb88a upstream.
The commit 1010b4c012b0 ("powerpc/eeh: Make EEH driver device hotplug safe") refactored the EEH code such that the pci_rescan_remove_lock is held at the beginning of eeh_handle_normal_event() and the eeh_reset_device() is called with that lock being held. Looks like the commit missed to remove the existing lock/unlock inside eeh_rmv_device() which is no longer necessary. This is causing the eehd to hang on the lock which it actually holds when that code path is taken.
[<0>] 0xc00000011c78f870
[<0>] __switch_to+0xfc/0x1a0 [<0>] pci_lock_rescan_remove+0x30/0x44 [<0>] eeh_rmv_device+0x290/0x2e0 [<0>] eeh_pe_dev_traverse+0x80/0x130 [<0>] eeh_reset_device+0xcc/0x23c [<0>] eeh_handle_normal_event+0x830/0xa80 [<0>] eeh_event_handler+0xf8/0x190 [<0>] kthread+0x194/0x1b0 [<0>] start_kernel_thread+0x14/0x18
The issue is seen for cases where the errors are detected on the PHB directly AND|OR for devices where the driver error_detected() returns PCI_ERS_RESULT_NEED_RESET, and driver being not EEH sensitive(i.e no error handlers like slot_reset(), resume() etc defined).
--- arch/powerpc/kernel/eeh_driver.c | 2 -- 1 file changed, 2 deletions(-)
arch/powerpc/kernel/eeh_driver.c +0 -2
@@ -533,9 +533,7 @@ static void eeh_rmv_device(struct eeh_deif (rmv_data)list_add (&edev->rmv_entry, &rmv_data->removed_vf_list); }else { -pci_lock_rescan_remove ();pci_stop_and_remove_bus_device (dev); -pci_unlock_rescan_remove (); } }
Greg Kroah-Hartman
maintainerPATCH 955/1250 powerpc: pci-ioda: Fix the stale irq chip reference
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shivaprasad G Bhat <[email protected]>
commit d96171d911e3b89ca2957c04264019cf2f96287b upstream.
The commit f0ac60e6e311 ("powerpc/powernv/pci: Switch to use msi_create_parent_irq_domain()") removed the legacy MSI irq chip pnv_pci_msi_irq_chip but left behind the static definition of it and its reference in is_pnv_opal_msi().
The KVM IRQ bypass for vfio devices is broken because the comparision in is_pnv_opal_msi() fails on the comparision with stale unused variable showing the below errors in dmesg.
kvmppc_set_passthru_irq_hv: Could not assign IRQ map for (X,Y) kvmppc_set_passthru_irq (irq X, gsi Y) fails: -2
vfio-pci A:B:C.D irq bypass producer (eventfd Z) registration fails: -2
The patch removes the stale variable definition and fixes the is_pnv_opal_msi() by comparing against the chip name prefix.
--- arch/powerpc/platforms/powernv/pci-ioda.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
arch/powerpc/platforms/powernv/pci-ioda.c +2 -4
@@ -1634,15 +1634,13 @@ int64_t pnv_opal_pci_msi_eoi(struct irq_return opal_pci_msi_eoi (phb->opal_id, d->parent_data->hwirq); } -static struct irq_chip pnv_pci_msi_irq_chip; -/* * Returns true iff chip is something that we could call * pnv_opal_pci_msi_eoi for. */ bool is_pnv_opal_msi (struct irq_chip *chip) { -return chip == &pnv_pci_msi_irq_chip; +return chip && chip->name &&str_has_prefix (chip->name,"PNV-" ); }EXPORT_SYMBOL_GPL (is_pnv_opal_msi);
@@ -1739,7 +1737,7 @@ static const struct msi_parent_ops pnv_m .chip_flags = MSI_CHIP_FLAG_SET_EOI, .bus_select_token = DOMAIN_BUS_NEXUS, .bus_select_mask = MATCH_PCI_MSI, - .prefix = "PNV-", + .prefix = "PNV-", /* Note: is_pnv_opal_msi() uses this */ .init_dev_msi_info = pnv_init_dev_msi_info, };
Greg Kroah-Hartman
maintainerPATCH 956/1250 x86/amd_node: Avoid divide by zero on virtualized systems
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jason Andryuk <[email protected]>
commit 72bd92bd8190d7869ecb462649ca40f297822a33 upstream.
On a virtualized system, the number of nodes does not have a relationship to the number of roots. A Xen PVH dom0 can calculate roots_per_node as 0, which crashes with a divide by zero in:
if (count++ % roots_per_node)
because the underlying topology code on Xen ends up making num_nodes 2 and num_roots 1 and the integer division result is 0.
The issue is seen with Xen, but it could affect other systems.
Set roots_per_node to 1 in this case. Print a firmware bug when this is performed for non-virtualized systems.
[ bp: Massage commit message. ]
--- arch/x86/kernel/amd_node.c | 5 +++++ 1 file changed, 5 insertions(+)
arch/x86/kernel/amd_node.c +5 -0
@@ -287,6 +287,11 @@ static int __init amd_smn_init(void)return -ENOMEM ; roots_per_node = num_roots / num_nodes; +if (!roots_per_node) { +if (!cpu_feature_enabled (X86_FEATURE_HYPERVISOR )) +pr_warn (FW_BUG "Error detecting roots per node.\n" ); + roots_per_node =1 ; + } count =0 ; node =0 ;
Signature · 1 line
2.55.0
Greg Kroah-Hartman
maintainerPATCH 957/1250 x86/amd_node: Fix potential NULL pointer dereference
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jason Andryuk <[email protected]>
commit aefdbd574a362dcf7569bada6d72f64a006b9fb9 upstream.
amd_smn_read/write() are exported functions around __amd_smn_rw(), so they are always available even if amd_smn_init() fails. In that case, 'amd_roots' is NULL and __amd_smn_rw() will access uninitialized memory.
Then, commit:
83518453074d ("x86/amd_node: Add SMN offsets to exclusive region access")
added the 'smn_exclusive' flag, which indicated the calls to pci_request_config_region_exclusive() succeeded, to prevent concurrent userspace access.
Commit:
0a4b61d9c2e4 ("x86/amd_node: Fix AMD root device caching")
re-ordered initialization so pci_request_config_region_exclusive() is called earlier and a failure exits amd_smn_init() before allocating 'amd_roots'. The setting of 'smn_exclusive' moved to the end of amd_smn_init(), after 'amd_roots' is allocated. It became redundant and can be removed.
Replace 'smn_exclusive' with directly checking 'amd_roots', to fix a potential NULL pointer dereference and to simplify the logic.
[ bp: Reorg commit message, touchup comment. ]
[ mingo: Rebase & further touchups. ]
--- arch/x86/kernel/amd_node.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-)
arch/x86/kernel/amd_node.c +8 -6
@@ -38,7 +38,6 @@ static struct pci_dev **amd_roots;/* Protect the PCI config register pairs used for SMN. */ static DEFINE_MUTEX (smn_mutex); -static bool smn_exclusive;#define SMN_INDEX_OFFSET 0x60#define SMN_DATA_OFFSET 0x64
@@ -91,11 +90,16 @@ static int __amd_smn_rw(u8 i_off, u8 d_oif (node >=amd_num_nodes ())return err; - root = amd_roots[node]; -if (!root) +/* +* Uninitialized amd_roots indicates pci_request_config_region_exclusive() +* didn't run or failed and thus the kernel cannot rely on having +* exclusive access to SMN registers so prevent that. +*/ +if (!amd_roots)return err; -if (!smn_exclusive) + root = amd_roots[node]; +if (!root)return err;guard (mutex)(&smn_mutex);
@@ -313,8 +317,6 @@ static int __init amd_smn_init(void)debugfs_create_file ("value" ,0600 , debugfs_dir,NULL , &smn_value_fops); } - smn_exclusive = true; -return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 958/1250 crypto: x86/aria - add missing vzeroupper in AVX2 code
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 ac53977611428db3bc0b4ac0225e19c3e08ae50b upstream.
Since the AVX2 optimized ARIA code uses YMM registers, execute vzeroupper before returning from it. This is needed to avoid degrading the performance of any later SSE code that may happen to be executed.
--- arch/x86/crypto/aria-aesni-avx2-asm_64.S | 6 ++++++ 1 file changed, 6 insertions(+)
arch/x86/crypto/aria-aesni-avx2-asm_64.S +6 -0
@@ -982,6 +982,7 @@ SYM_TYPED_FUNC_START(aria_aesni_avx2_enc %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14, %ymm15, %rax); + vzeroupper; FRAME_END RET; SYM_FUNC_END(aria_aesni_avx2_encrypt_32way)
@@ -1007,6 +1008,7 @@ SYM_TYPED_FUNC_START(aria_aesni_avx2_dec %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14, %ymm15, %rax); + vzeroupper; FRAME_END RET; SYM_FUNC_END(aria_aesni_avx2_decrypt_32way)
@@ -1209,6 +1211,7 @@ SYM_TYPED_FUNC_START(aria_aesni_avx2_ctr %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14, %ymm15, %r10); + vzeroupper; FRAME_END RET; SYM_FUNC_END(aria_aesni_avx2_ctr_crypt_32way)
@@ -1359,6 +1362,7 @@ SYM_TYPED_FUNC_START(aria_aesni_avx2_gfn %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14, %ymm15, %rax); + vzeroupper; FRAME_END RET; SYM_FUNC_END(aria_aesni_avx2_gfni_encrypt_32way)
@@ -1384,6 +1388,7 @@ SYM_TYPED_FUNC_START(aria_aesni_avx2_gfn %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14, %ymm15, %rax); + vzeroupper; FRAME_END RET; SYM_FUNC_END(aria_aesni_avx2_gfni_decrypt_32way)
@@ -1428,6 +1433,7 @@ SYM_TYPED_FUNC_START(aria_aesni_avx2_gfn %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14, %ymm15, %r10); + vzeroupper; FRAME_END RET; SYM_FUNC_END(aria_aesni_avx2_gfni_ctr_crypt_32way)
Greg Kroah-Hartman
maintainerPATCH 959/1250 crypto: x86/aria - add missing vzeroupper in AVX-512 code
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 60892a384aa1e65d0e703e1c513417bdf0c80777 upstream.
Since the AVX-512 optimized ARIA code uses ZMM registers, execute vzeroupper before returning from it. This is needed to avoid degrading the performance of any later SSE code that may happen to be executed.
--- arch/x86/crypto/aria-gfni-avx512-asm_64.S | 3 +++ 1 file changed, 3 insertions(+)
arch/x86/crypto/aria-gfni-avx512-asm_64.S +3 -0
@@ -800,6 +800,7 @@ SYM_TYPED_FUNC_START(aria_gfni_avx512_en %zmm9, %zmm8, %zmm11, %zmm10, %zmm12, %zmm13, %zmm14, %zmm15, %rax); + vzeroupper; FRAME_END RET; SYM_FUNC_END(aria_gfni_avx512_encrypt_64way)
@@ -825,6 +826,7 @@ SYM_TYPED_FUNC_START(aria_gfni_avx512_de %zmm9, %zmm8, %zmm11, %zmm10, %zmm12, %zmm13, %zmm14, %zmm15, %rax); + vzeroupper; FRAME_END RET; SYM_FUNC_END(aria_gfni_avx512_decrypt_64way)
@@ -966,6 +968,7 @@ SYM_TYPED_FUNC_START(aria_gfni_avx512_ct %zmm9, %zmm8, %zmm11, %zmm10, %zmm12, %zmm13, %zmm14, %zmm15, %r10); + vzeroupper; FRAME_END RET; SYM_FUNC_END(aria_gfni_avx512_ctr_crypt_64way)
Greg Kroah-Hartman
maintainerPATCH 960/1250 x86/amd_node: Fix PCI device reference counting in amd_smn_init()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yazen Ghannam <[email protected]>
commit 27600805e62f800bacf990354632eae4e487d34c upstream.
The local "root" pointer is a temporary variable used during the device search. Therefore, refcount related to the search iterators should be cleaned up after the search is complete.
Use the __free() cleanup macro to ensure the refcount is decremented when the temporary pointer goes out of scope.
Additionally, increment the refcount when caching a root pointer. This ensures the in-use refcount is separate from the temporary search refcounting.
Finally, drop the redundant "root = NULL" before the second search loop. The pci_get_class() iterator always decrements the refcount of its "from" argument, so the first loop can only fall through with "root" already NULL.
--- arch/x86/kernel/amd_node.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
arch/x86/kernel/amd_node.c +2 -4
@@ -251,7 +251,7 @@ __setup("amd_smn_debugfs_enable", amd_smn_enable_dfs);static int __init amd_smn_init (void ) {u16 count, num_roots, roots_per_node, node, num_nodes; -struct pci_dev *root; + struct pci_dev *root __free(pci_dev_put) = NULL;if (!cpu_feature_enabled (X86_FEATURE_ZEN ))return 0 ;
@@ -262,7 +262,6 @@ static int __init amd_smn_init(void)return 0 ; num_roots =0 ; - root =NULL ;while ((root =get_next_root (root))) {pci_dbg (root,"Reserving PCI config space\n" );
@@ -299,14 +298,13 @@ static int __init amd_smn_init(void) count =0 ; node =0 ; - root =NULL ;while (node < num_nodes && (root =get_next_root (root))) {/* Use one root for each node and skip the rest. */ if (count++ % roots_per_node)continue ;pci_dbg (root,"is root for AMD node %u\n" , node); - amd_roots[node++] = root; + amd_roots[node++] =pci_dev_get (root); }if (enable_dfs) {
Signature · 1 line
2.55.0
Greg Kroah-Hartman
maintainerPATCH 961/1250 x86/mm: Fix user-space data loss with MADV_FREE and THP
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vernon Yang <[email protected]>
commit f7491d7c81db0e7c304a7bd757a76d2fbeaff80e upstream.
Some of users of Polars (a data analytics library) have lost production data from this bug. They seem to have just the right combination of huge pages, MADV_FREE and heavy reclaim pressure.
pmd_modify() masks the old value with (_HPAGE_CHG_MASK & ~_PAGE_DIRTY), silently discarding the hardware dirty bit. The subsequent pmd_mksaveddirty() call is supposed to transfer _PAGE_DIRTY into _PAGE_SAVED_DIRTY when write-protecting, but the dirty bit was already stripped from the value, so there is nothing left to transfer.
Contrast with pte_modify(), which keeps _PAGE_DIRTY_BITS in its mask, and pud_modify(), which keeps _HPAGE_CHG_MASK untouched: pmd_modify() is the odd one out. Any pmd_modify() on a writable, dirty PMD loses the dirty state.
One visible consequence is data loss with MADV_FREE on PMD-mapped THP:
memset(buf, 0x5A, size); // PMD-mapped THP, PMD dirty
madvise(buf, size, MADV_FREE); // PMD cleaned but left writable,
// folio marked lazyfree
memset(buf, 0x5A, size); // hardware sets _PAGE_DIRTY again
mprotect(buf, size, PROT_READ); // pmd_modify() drops the dirty bit
mprotect(buf, size, PROT_READ|PROT_WRITE);
// ... memory pressure ...Reclaim (e.g. under memcg pressure) then finds the lazyfree folio with no dirty bit set anywhere and frees it in __discard_anon_folio_pmd_locked(), even though the data was rewritten after MADV_FREE; subsequent reads fault in fresh zero pages. NUMA hinting alone can trigger the same loss, as do_huge_pmd_numa_page() restores the PMD through pmd_modify() as well.
PMD-mapped file THPs are affected too: mprotect()/NUMA hinting dropping the dirty bit means rewritten data is never written back.
Fix it by keeping _PAGE_DIRTY in the preserved mask, exactly like pte_modify() and pud_modify() do. The existing pmd_mksaveddirty()/pmd_clear_saveddirty() pair then performs the hardware-dirty <-> saved-dirty transition based on the write bit, preserving the shadow-stack encoding rules.
--- arch/x86/include/asm/pgtable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/include/asm/pgtable.h +1 -1
@@ -813,7 +813,7 @@ static inline pmd_t pmd_modify(pmd_t pmdpmdval_t val =pmd_val (pmd), oldval = val;pmd_t pmd_result; - val &= (_HPAGE_CHG_MASK & ~_PAGE_DIRTY); + val &= _HPAGE_CHG_MASK; val |=check_pgprot (newprot) & ~_HPAGE_CHG_MASK; val =flip_protnone_guard (oldval, val,PHYSICAL_PMD_PAGE_MASK );
Greg Kroah-Hartman
maintainerPATCH 962/1250 x86/cfi: Fix FineIBT hash offset in cfi_get_func_hash()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Soheil Hassas Yeganeh <[email protected]>
commit 5a5d26f2cfe13467166219f6bf58099326912ddb upstream.
The switch of the FineIBT preamble from "subl $hash, %r10d" to the shorter "subl $hash, %eax" moved the hash immediate from offset 7 to offset 5 of the preamble. fineibt_preamble_hash was updated to match, but the open-coded offset in cfi_get_func_hash() was missed and it still reads the hash at offset 7.
cfi_get_func_hash() is used by the BPF JIT to give a struct_ops trampoline the CFI hash of the stub function it stands in for. With FineIBT the trampoline now gets the upper half of the real hash followed by the first two bytes of the next instruction, so the first indirect call from the kernel into a struct_ops program, tcp_init_congestion_control() calling ->init() of a BPF congestion control for example, fails the FineIBT check and the kernel dies with a CFI failure.
Move the FineIBT preamble template and its offset defines above cfi_get_func_hash() and use fineibt_preamble_hash there, so every reader of the preamble shares one definition of its layout. The CFI_FINEIBT arm is only built with CONFIG_FINEIBT, the only configuration in which cfi_mode can take that value. cfi_get_func_arity() does not need the same treatment: the __bhi_args call whose displacement it reads still ends at the function address.
--- arch/x86/kernel/alternative.c | 72 ++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 34 deletions(-)
arch/x86/kernel/alternative.c +38 -34
@@ -1193,6 +1193,41 @@ static bool cfi_debug __ro_after_init;bool cfi_bhi__ro_after_init = false;#endif +#ifdef CONFIG_FINEIBT +/* +* <fineibt_preamble_start>: +* 0: f3 0f 1e fa endbr64 +* 4: 2d 78 56 34 12 sub $0x12345678, %eax +* 9: 2e 0f 85 03 00 00 00 jne,pn 13 <fineibt_preamble_start+0x13> +* 10: 0f 1f 40 d6 nopl -0x2a(%rax) +* +* Note that the JNE target is the 0xD6 byte inside the NOPL, this decodes as +* UDB on x86_64 and raises #UD. +*/ +asm(".pushsection .rodata \n" +"fineibt_preamble_start: \n" +" endbr64 \n" +" subl $0x12345678, %eax \n" +"fineibt_preamble_bhi: \n" +" cs jne.d32 fineibt_preamble_start+0x13 \n" +"#fineibt_func: \n" +" nopl -42(%rax) \n" +"fineibt_preamble_end: \n" +".popsection\n" +); + +extern u8 fineibt_preamble_start[]; +extern u8 fineibt_preamble_bhi[]; +extern u8 fineibt_preamble_end[]; + +#define fineibt_preamble_size (fineibt_preamble_end - fineibt_preamble_start) +#define fineibt_preamble_bhi (fineibt_preamble_bhi - fineibt_preamble_start) +#define fineibt_preamble_ud 0x13 +#define fineibt_preamble_hash 5 + +#define fineibt_prefix_size (fineibt_preamble_size - ENDBR_INSN_SIZE) +#endif /* CONFIG_FINEIBT */ +#ifdef CONFIG_CFI u32 cfi_get_func_hash (void *func) {
@@ -1200,9 +1235,11 @@ u32 cfi_get_func_hash(void *func) func -=cfi_get_offset ();switch (cfi_mode) { +#ifdef CONFIG_FINEIBT case CFI_FINEIBT : - func +=7 ; + func += fineibt_preamble_hash;break ; +#endif case CFI_KCFI : func +=1 ;break ;
@@ -1345,39 +1382,6 @@ early_param("cfi", cfi_parse_cmdline);*/ /* -* <fineibt_preamble_start>: -* 0: f3 0f 1e fa endbr64 -* 4: 2d 78 56 34 12 sub $0x12345678, %eax -* 9: 2e 0f 85 03 00 00 00 jne,pn 13 <fineibt_preamble_start+0x13> -* 10: 0f 1f 40 d6 nopl -0x2a(%rax) -* -* Note that the JNE target is the 0xD6 byte inside the NOPL, this decodes as -* UDB on x86_64 and raises #UD. -*/ -asm(".pushsection .rodata \n" -"fineibt_preamble_start: \n" -" endbr64 \n" -" subl $0x12345678, %eax \n" -"fineibt_preamble_bhi: \n" -" cs jne.d32 fineibt_preamble_start+0x13 \n" -"#fineibt_func: \n" -" nopl -42(%rax) \n" -"fineibt_preamble_end: \n" -".popsection\n" -); - -extern u8 fineibt_preamble_start[]; -extern u8 fineibt_preamble_bhi[]; -extern u8 fineibt_preamble_end[]; - -#define fineibt_preamble_size (fineibt_preamble_end - fineibt_preamble_start) -#define fineibt_preamble_bhi (fineibt_preamble_bhi - fineibt_preamble_start) -#define fineibt_preamble_ud 0x13 -#define fineibt_preamble_hash 5 - -#define fineibt_prefix_size (fineibt_preamble_size - ENDBR_INSN_SIZE) - -/* * <fineibt_caller_start>: * 0: b8 78 56 34 12 mov $0x12345678, %eax * 5: 4d 8d 5b f0 lea -0x10(%r11), %r11
Greg Kroah-Hartman
maintainerPATCH 963/1250 x86/mm/pat: Acquire init_mm write lock on collapse to avoid UAF
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Stoakes (ARM) <[email protected]>
commit a1c7570cedd03372812a5b693732880867babbca upstream.
x86 implements page attribute modification using its Change Page Attributes (CPA) mechanism.
This tracks properties of ranges such as cache mode through x86 page attributes, and as part of that logic manipulates kernel page tables.
Since commit:
41d88484c71c ("x86/mm/pat: restore large ROX pages after fragmentation")
ranges of kernel page table entries can be collapsed into huge page table entries as part of this logic.
As part of this collapse, it frees the page tables which the collapsed entries previously pointed to, and it does so without any relevant locks being held to preclude concurrent kernel page table walkers.
The only way this code can be reached is if CPA_COLLAPSE is specified, and this is only set in set_memory_rox() via:
set_memory_rox()
-> change_page_attr_set_clr()
-> cpa_flush()
-> cpa_collapse_large_pages()
Notable users of this are execmem and BPF when manipulating executable mappings.
However, this is problematic for ptdump as it walks ranges it does not own and thus runs the risk of a use-after-free on page tables freed underneath it.
In addition, concurrent CPA collapse operations are possible which can also cause races.
Resolve the issue by acquiring the mmap write lock on init_mm across the whole operation.
It is safe to acquire a sleeping lock as all the callers invoke set_memory_rox() from process context and in any case, change_page_attr_set_clr() calls vm_unmap_alias() which ultimately takes a mutex, disallowing atomic context here.
--- arch/x86/mm/pat/set_memory.c | 15 ++++++++++++++- include/linux/mmap_lock.h | 2 ++ 2 files changed, 16 insertions(+), 1 deletion(-)
arch/x86/mm/pat/set_memory.c +14 -1
@@ -22,6 +22,7 @@#include <linux/cc_platform.h> #include <linux/set_memory.h> #include <linux/memregion.h> +#include <linux/cleanup.h> #include <asm/e820/api.h> #include <asm/processor.h>
@@ -401,7 +402,7 @@ static void cpa_flush_all(unsigned longstatic int collapse_large_pages (unsigned long addr,struct list_head *pgtables); -static void cpa_collapse_large_pages (struct cpa_data *cpa) +static void __cpa_collapse_large_pages (struct cpa_data *cpa) {unsigned long start, addr, end;struct ptdesc *ptdesc, *tmp;
@@ -439,6 +440,18 @@ static void cpa_collapse_large_pages(strspin_unlock (&cpa_lock); } +static void cpa_collapse_large_pages (struct cpa_data *cpa) +{ +/* +* Take the mmap write lock on init_mm to: +* - Avoid a use-after-free if raced by ptdump (which takes its own +* write lock on init_mm). +* - Serialise concurrent CPA walkers. +*/ + scoped_guard(mmap_write_lock, &init_mm) +__cpa_collapse_large_pages (cpa); +} +static void cpa_flush (struct cpa_data *cpa,int cache) {unsigned long start, end;
include/linux/mmap_lock.h +2 -0
@@ -398,6 +398,8 @@ static inline void mmap_read_unlock(stru DEFINE_GUARD(mmap_read_lock, struct mm_struct *, mmap_read_lock(_T), mmap_read_unlock(_T)) DEFINE_GUARD_COND(mmap_read_lock, _try, mmap_read_trylock(_T)) +DEFINE_GUARD(mmap_write_lock, struct mm_struct *, + mmap_write_lock(_T), mmap_write_unlock(_T))static inline void mmap_read_unlock_non_owner (struct mm_struct *mm) {
Greg Kroah-Hartman
maintainerPATCH 964/1250 x86/alternatives: Exclude text poking against change_page_attr()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pedro Falcato <[email protected]>
commit 1587d3394e254639cc36516256031334095e6ef3 upstream.
Quoted 1 line
From time to time, the following BUG can be observed
in the x86 alternatives patching code [0]:
Quoted 12 lines
kernel BUG at
arch/x86/kernel/alternative.c:2576!Oops: invalid opcode: 0000 [#1] SMP NOPTI CPU: 0 UID: 0 PID: 355 Comm: (udev-worker) Not tainted 7.1.3-1-default #1 PREEMPT(full) openSUSE Tumbleweed 8c1795b03ec64f997e57a8ad38b1161e3b98da64 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS unknown 02/02/2022 RIP: 0010:__text_poke+0x2aa/0x450 Call Trace: <TASK> smp_text_poke_batch_finish+0x2a7/0x320 __static_call_transform+0xb7/0x220 arch_static_call_transform+0x5b/0xb0 __static_call_init+0xe9/0x270 static_call_module_notify+0x11f/0x150
Quoted 8 lines
notifier_call_chain+0x61/0xe0 blocking_notifier_call_chain_robust+0x63/0xc0 load_module+0x1c92/0x20c0 init_module_from_file+0xd8/0x140 idempotent_init_module+0x100/0x2f0 __x64_sys_finit_module+0x71/0xe0 do_syscall_64+0xe1/0x610 entry_SYSCALL_64_after_hwframe+0x76/0x7e
which matches the following BUG_ON() in alternative.c:
/* * If something went wrong, crash and burn since recovery paths are not * implemented. */ BUG_ON(!pages[0] || (cross_page_boundary && !pages[1]));
This can happen if vmalloc_to_page() fails, for any reason. Such can happen if text poking races with CPA, which can possibly result in the collapsing of page tables (or breaking of PMD hugepages). It is not a problem for most users of vmalloc_to_page() (they solely own the vmalloc'd range) but, when CONFIG_ARCH_HAS_EXECMEM_ROX=y, various modules own a single execmem vmalloc range, and can call set_memory_*() in parallel on it. This can happen to race against __text_poke and cause havoc in vmalloc_to_page().
Fix it by excluding against CPA using the init_mm mmap read lock.
[ dhansen: Fix up SoB ordering. The actual code flow here was:
Pedro=>Lorenzo=>Mike=>Me which is reflected in the SoB chain now. I *believe* Mike simply picked up Lorenzo's update to Pedro's post from the Link ]
--- arch/x86/kernel/alternative.c | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-)
arch/x86/kernel/alternative.c +36 -3
@@ -6,6 +6,9 @@#include <linux/vmalloc.h> #include <linux/memory.h> #include <linux/execmem.h> +#include <linux/cleanup.h> +#include <linux/kgdb.h> +#include <linux/mmap_lock.h> #include <asm/text-patching.h> #include <asm/insn.h>
@@ -2502,6 +2505,38 @@ static void text_poke_memset(void *dst,typedef void text_poke_f (void *dst,const void *src,size_t len); +static void __poke_vmalloc_pages (struct page **pages,void *addr, +bool cross_page_boundary) +{ + pages[0 ] =vmalloc_to_page (addr); +if (cross_page_boundary) + pages[1 ] =vmalloc_to_page (addr +PAGE_SIZE ); +} + +static void poke_vmalloc_pages (struct page **pages,void *addr, +bool cross_page_boundary) +{ +if (in_dbg_master ()) { +/* +* If called from kgdb cannot sleep, but all other CPUs stopped +* anyway so safe to proceed without locks +*/ +__poke_vmalloc_pages (pages, addr, cross_page_boundary); + }else { +/* +* execmem ROX ranges are shared between modules and can be +* collapsed to huge PMD entries, and this collapse can happen +* concurrently with a racing set_memory_rox(). +* +* Prevent vmalloc_to_page() from racing by acquiring an +* init_mm read lock which pairs with the init_mm write lock in +* cpa_collapse_large_pages(). +*/ +guard (mmap_read_lock)(&init_mm); +__poke_vmalloc_pages (pages, addr, cross_page_boundary); + } +} +static void *__text_poke (text_poke_f func,void *addr,const void *src,size_t len) {bool cross_page_boundary =offset_in_page (addr) + len >PAGE_SIZE ;
@@ -2519,9 +2554,7 @@ static void *__text_poke(text_poke_f funBUG_ON (!after_bootmem);if (!core_kernel_text ((unsigned long )addr)) { - pages[0 ] =vmalloc_to_page (addr); -if (cross_page_boundary) - pages[1 ] =vmalloc_to_page (addr +PAGE_SIZE ); +poke_vmalloc_pages (pages, addr, cross_page_boundary); }else { pages[0 ] =virt_to_page (addr);WARN_ON (!PageReserved (pages[0 ]));
Greg Kroah-Hartman
maintainerPATCH 965/1250 ipv6: fix fib6 walker UAF on seq stop
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zihan Xi <[email protected]>
commit 19b4ed644d68098cc62ab612727f40d30f43476c upstream.
ipv6_route_iter_active() treats a walker in FWS_U at the table root as already unlinked. fib6_del_route() can move a still-linked walker into that same state when the current leaf is the last route at the root, so ipv6_route_native_seq_stop() skips fib6_walker_unlink(). The seq private object can then be freed while it remains on net->ipv6.fib6_walkers. A later route deletion walks the dangling list and uses the freed walker.
Use the list head as membership state and reinitialize it when unlinking. Keep the existing w->node check so a never-started iterator with a zeroed private object is not treated as linked.
The same stop helper is used by /proc/net/ipv6_route and by the BPF ipv6_route iterator. The BPF show path only widens the race.
--- net/ipv6/ip6_fib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/ipv6/ip6_fib.c +2 -2
@@ -85,7 +85,7 @@ static void fib6_walker_link(struct netstatic void fib6_walker_unlink (struct net *net,struct fib6_walker *w) {write_lock_bh (&net->ipv6.fib6_walker_lock); -list_del (&w->lh); +list_del_init (&w->lh);write_unlock_bh (&net->ipv6.fib6_walker_lock); }
@@ -2757,7 +2757,7 @@ static void *ipv6_route_seq_start(structstatic bool ipv6_route_iter_active (struct ipv6_route_iter *iter) {struct fib6_walker *w = &iter->w; -return w->node && !(w->state ==FWS_U && w->node == w->root); +return w->node && !list_empty (&w->lh); }static void ipv6_route_native_seq_stop (struct seq_file *seq,void *v)
Greg Kroah-Hartman
maintainerPATCH 966/1250 reboot: fix cad_pid use-after-free race
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cen Zhang (Microsoft) <[email protected]>
commit 5a88f78df753993469dab4d1831f8fb4256a9468 upstream.
cad_pid is a single kernel-wide struct pid pointer. proc_do_cad_pid() reads it and passes it to pid_vnr() without protecting the lifetime of the referenced struct pid. A concurrent writer can replace cad_pid and drop the final reference to the old struct pid after the reader has loaded the pointer but before pid_vnr() has finished dereferencing it, causing a use-after-free.
kill_cad_pid() has the same lifetime race when it passes cad_pid to kill_pid().
At the time this issue was reported, an unprivileged user could reach the sysctl through user and PID namespaces because cad_pid was registered in pid_table[]. Moving cad_pid back to the global reboot sysctl table corrected that namespace and permission mismatch, but did not fix the underlying lifetime race.
Fix this by treating cad_pid as an RCU-protected pointer at both read sites and by waiting for a grace period before dropping the old reference on the write side.
call_rcu(&old_pid->rcu, ...) cannot be used here because free_pid() also queues pid->rcu; queueing the same rcu_head twice can corrupt the RCU callback list.
Original KASAN crash stack:
kernel/pid.c:545 pid_nr_ns() # reads freed pid->level kernel/pid.c:556 pid_vnr() # calls pid_nr_ns() kernel/pid.c:775 proc_do_cad_pid() # calls pid_vnr(cad_pid)
--- include/linux/sched.h | 2 +- include/linux/sched/signal.h | 5 +---- init/main.c | 2 +- kernel/reboot.c | 19 +++++++++++++++---- kernel/signal.c | 12 ++++++++++++ 5 files changed, 30 insertions(+), 10 deletions(-)
include/linux/sched.h +1 -1
@@ -1735,7 +1735,7 @@ static inline char task_state_to_char(streturn task_index_to_char (task_state_index (tsk)); } -extern struct pid *cad_pid; +extern struct pid __rcu *cad_pid;/* * Per process flags
include/linux/sched/signal.h +1 -4
@@ -561,10 +561,7 @@ static inline sigset_t *sigmask_to_save(return res; } -static inline int kill_cad_pid (int sig,int priv) -{ -return kill_pid (cad_pid, sig, priv); -} +int kill_cad_pid (int sig,int priv);/* These can be the second arg to send_sig_info/send_group_sig_info. */ #define SEND_SIG_NOINFO ((struct kernel_siginfo *) 0)
init/main.c +1 -1
@@ -1525,7 +1525,7 @@ static noinline void __init kernel_init_*/ set_mems_allowed (node_states[N_MEMORY ]); - cad_pid =get_pid (task_pid (current)); +rcu_assign_pointer (cad_pid,get_pid (task_pid (current)));smp_prepare_cpus (setup_max_cpus);
kernel/reboot.c +15 -4
@@ -13,7 +13,9 @@#include <linux/kexec.h> #include <linux/kmod.h> #include <linux/kmsg_dump.h> +#include <linux/rcupdate.h> #include <linux/reboot.h> +#include <linux/sched/signal.h> #include <linux/suspend.h> #include <linux/syscalls.h> #include <linux/syscore_ops.h>
@@ -24,8 +26,7 @@*/ static int C_A_D =1 ; -struct pid *cad_pid; -EXPORT_SYMBOL (cad_pid); +struct pid __rcu *cad_pid;#if defined(CONFIG_ARM )#define DEFAULT_REBOOT_MODE = REBOOT_HARD
@@ -1371,10 +1372,14 @@ static int proc_do_cad_pid(const struct {struct ctl_table tmp_table = *table;struct pid *new_pid; +struct pid *old_pid;pid_t tmp_pid;int r; - tmp_pid =pid_vnr (cad_pid); +rcu_read_lock (); + tmp_pid =pid_vnr (rcu_dereference (cad_pid)); +rcu_read_unlock (); + tmp_table.data = &tmp_pid; r =proc_dointvec (&tmp_table, write, buffer, lenp, ppos);
@@ -1385,7 +1390,13 @@ static int proc_do_cad_pid(const structif (!new_pid)return -ESRCH ; -put_pid (xchg (&cad_pid, new_pid)); + old_pid =unrcu_pointer (xchg (&cad_pid,RCU_INITIALIZER (new_pid))); +/* +* Wait for cad_pid readers before put_pid(). We cannot use +* call_rcu() here because free_pid() already owns pid->rcu. +*/ +synchronize_rcu (); +put_pid (old_pid);return 0 ; }
kernel/signal.c +12 -0
@@ -1905,6 +1905,18 @@ int kill_pid(struct pid *pid, int sig, i }EXPORT_SYMBOL (kill_pid); +int kill_cad_pid (int sig,int priv) +{ +int ret; + +rcu_read_lock (); + ret =kill_pid (rcu_dereference (cad_pid), sig, priv); +rcu_read_unlock (); + +return ret; +} +EXPORT_SYMBOL (kill_cad_pid); +#ifdef CONFIG_POSIX_TIMERS /* * These functions handle POSIX timer signals. POSIX timers use
Greg Kroah-Hartman
maintainerPATCH 967/1250 tracing: Fix memory corruption from the histogram stacktrace modifier
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Donggeun Yoo <[email protected]>
commit a5e70ba87ca8ebc79b4e63de302d03b0625fe153 upstream.
parse_field() sets HIST_FIELD_FL_STACKTRACE from the ".stacktrace" modifier before it looks the field name up, and nothing afterwards checks that the name resolved to a field which holds a stacktrace. create_hist_field() picks HIST_FIELD_FN_STACK on the strength of the field pointer alone, which reads a __data_loc word from the record and follows its low 16 bits as an offset into the same record. event_hist_trigger() takes the first word there as an entry count and copies that many longs into a 31 entry array:
n_entries = *stack; memcpy(entries, ++stack, n_entries * sizeof(unsigned long));
Neither end of that copy is bounded, and the count is whatever the event holds at the offset, so any field will do:
# cd /sys/kernel/tracing/events/sched/sched_process_fork # echo 'hist:keys=parent_pid.stacktrace' > trigger # (true)
BUG: kernel NULL pointer dereference, address: 0000000000000008 RIP: 0010:rb_insert_color+0x18/0x130 timerqueue_linked_add+0x7e/0xd0 enqueue_hrtimer+0x39/0xb0 __hrtimer_run_queues+0x10f/0x1f0 </IRQ> RIP: 0010:memcpy+0xc/0x30 event_hist_trigger+0x165/0x690
The timer interrupt landed on the rbtree the copy had already run over. No debug options are needed for this; KASAN reports the same write as an out-of-bounds read of 13835058055416381440 bytes.
Documentation/trace/histogram.rst already states the rule, "must be a long[] type", so enforce it once the name has been resolved. Names which resolve to no field at all, "hitcount.stacktrace" and the common_* pseudo-fields, are refused for the same reason: they hold no stacktrace to read.
--- kernel/trace/trace_events_hist.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
kernel/trace/trace_events_hist.c +10 -2
@@ -2324,6 +2324,7 @@ parse_field(struct hist_trigger_data *histruct ftrace_event_field *field =NULL ;char *field_name, *modifier, *str;struct trace_array *tr = file->tr; +bool stack_modifier = false; modifier = str =kstrdup (field_str,GFP_KERNEL );if (!modifier)
@@ -2346,9 +2347,10 @@ parse_field(struct hist_trigger_data *hi *flags |=HIST_FIELD_FL_EXECNAME ; else if (strcmp(modifier, "syscall") == 0) *flags |= HIST_FIELD_FL_SYSCALL; - else if (strcmp(modifier, "stacktrace") == 0) + else if (strcmp(modifier, "stacktrace") == 0) { *flags |= HIST_FIELD_FL_STACKTRACE; - else if (strcmp(modifier, "log2") == 0) + stack_modifier = true; + } else if (strcmp(modifier, "log2") == 0) *flags |= HIST_FIELD_FL_LOG2; else if (strcmp(modifier, "usecs") == 0) *flags |= HIST_FIELD_FL_TIMESTAMP_USECS;
@@ -2419,6 +2421,12 @@ parse_field(struct hist_trigger_data *hi } } } + +if (stack_modifier && + (!field || field->filter_type !=FILTER_STACKTRACE )) { +hist_err (tr,HIST_ERR_BAD_FIELD_MODIFIER ,errpos (field_str)); + field =ERR_PTR (-EINVAL ); + } out:kfree (str);
Greg Kroah-Hartman
maintainerPATCH 968/1250 tracing: Restore :mod: trailer after parsing in ftrace_set_clr_event()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Weißschuh <[email protected]>
commit 911002e99e15f640f1fdc6d276206beaef59e790 upstream.
While ftrace_set_clr_event() modifies its input buffer during parsing, before returning to the caller the buffer is supposed to be restored to its original state.
This works correctly for the colon between the subsystem and event but not the colon at the beginning of :mod:.
Restore the colon, so the :mod: trailer is not stripped after ftrace_set_clr_event().
--- kernel/trace/trace_events.c | 2 ++ 1 file changed, 2 insertions(+)
kernel/trace/trace_events.c +2 -0
@@ -1442,6 +1442,8 @@ int ftrace_set_clr_event(struct trace_ar/* Put back the colon to allow this to be called again */ if (buf) *(buf -1 ) =':' ; +if (mod) + *(mod -5 ) =':' ;return ret; }
Greg Kroah-Hartman
maintainerPATCH 969/1250 tracing: Fix memory corruption from a "STACKTRACE" histogram key
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Donggeun Yoo <[email protected]>
commit 7f711e62355bb3123a2ca2f97a2facbfebc678c6 upstream.
"cpu", "CPU", "stacktrace" and "STACKTRACE" are generic fields, defined with an offset and a size of zero so that the filter code can match them by name. parse_field() maps them onto their common_* equivalents for backward compatibility, but unlike the common_* names it hands the placeholder back to the caller instead of NULL.
create_hist_field() takes a non-NULL field as a promise that the record carries a stacktrace and picks HIST_FIELD_FN_STACK, so the __data_loc word is read from offset 0, that is from common_type, and its low 16 bits are followed as an offset into the record. What is found there becomes the length of an unbounded memcpy. Pick an event whose id is small enough that the offset stays inside its own record and the length is a kernel text address:
# cd /sys/kernel/tracing # echo 'hist:keys=STACKTRACE' > events/ftrace/print/trigger # echo hello > trace_marker
Oops: general protection fault, probably for non-canonical address RIP: 0010:rb_next+0x23/0x60 </IRQ> RIP: 0010:memcpy+0xc/0x30 event_hist_trigger+0x2e7/0x12c0 Kernel panic - not syncing: Fatal exception in interrupt
Leave the field NULL, which is what the comment above the branch says the code does and what common_stacktrace already does. FILTER_CPU and FILTER_COMM are left alone, their create_hist_field() branches never look at the field.
--- kernel/trace/trace_events_hist.c | 1 + 1 file changed, 1 insertion(+)
kernel/trace/trace_events_hist.c +1 -0
@@ -2411,6 +2411,7 @@ parse_field(struct hist_trigger_data *hi *flags |=HIST_FIELD_FL_CPU ; }else if (field && field->filter_type ==FILTER_STACKTRACE ) { *flags |=HIST_FIELD_FL_STACKTRACE ; + field =NULL ; }else if (field && field->filter_type ==FILTER_COMM ) { *flags |=HIST_FIELD_FL_COMM |HIST_FIELD_FL_STRING ; }else {
Greg Kroah-Hartman
maintainerPATCH 970/1250 rust: allow `clippy::as_underscore` in the generated bindings
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: John Hubbard <[email protected]>
commit 2ac74c6db40adaa29c50cbb281ae9a6f63de18e1 upstream.
A CLIPPY=1 build emitted about 15000 as _ conversion warnings, all of them in bindgen's generated output and none in hand-written code.
[ The lint messages look like:
error: using as _ conversion
--> rust/bindings/bindings_generated.rs:18947:9
|
18947 | self._bitfield_1.get_const::<0usize, 16u8>() as u32 as _
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
| help: consider giving the type explicitly: u32
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.98.0/index.html#as_underscore
= note: -D clippy::as-underscore implied by -D warnings
= help: to override -D warnings add #[allow(clippy::as_underscore)]
- Miguel ]
bindgen 0.73 returns each bitfield read through a trailing as _, and 0.72 returns it through a transmute, which the lint ignores. The bindings and uapi crates allow clippy::all over the generated code. That group does not cover clippy::as_underscore, a restriction lint.
Allow clippy::as_underscore by name in the bindings and uapi crates.
--- rust/bindings/lib.rs | 1 + rust/uapi/lib.rs | 1 + 2 files changed, 2 insertions(+)
rust/bindings/lib.rs +1 -0
@@ -25,6 +25,7 @@ )]#[allow(dead_code)] +#[allow(clippy::as_underscore)] #[allow(clippy::cast_lossless)] #[allow(clippy::ptr_as_ptr)] #[allow(clippy::ref_as_ptr)]
rust/uapi/lib.rs +1 -0
@@ -14,6 +14,7 @@#![cfg_attr(test, allow(unsafe_op_in_unsafe_fn))] #![allow( clippy::all, + clippy::as_underscore, clippy::cast_lossless, clippy::ptr_as_ptr, clippy::ref_as_ptr,
Greg Kroah-Hartman
maintainerPATCH 971/1250 rust: allow `unknown_lints` in generated bindings for Rust < 1.88
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Miguel Ojeda <[email protected]>
commit f4c3e38111fd84c2c7ae5785755f4a4d476e1cba upstream.
Starting with bindgen 0.73.2 [1], #[allow(unnecessary_transmutes)] are used, even when --rust-target 1.85 is passed.
However, the lint was introduced in Rust 1.88.0. Thus building with older Rust versions warns like:
error: unknown lint: `unnecessary_transmutes`
--> rust/uapi/uapi_generated.rs:26294:13
|
26294 | #[allow(unnecessary_transmutes)]
| ^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D unknown-lints` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(unknown_lints)]`Thus allow unknown_lints in the generated bindings -- only when building with older Rust versions.
I have asked upstream if this is intentional [1], i.e. if we are supposed to always allow unknown lints in case bindgen uses such attributes, or whether it is an oversight.
[ Emilio said it wasn't intentional -- we will work around it for now
on the kernel side. - Miguel ]
[ Removed the cfg for allow(unnecessary_transmutes) as suggested by
Gary. - Miguel ]
--- rust/bindings/lib.rs | 3 ++- rust/uapi/lib.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-)
rust/bindings/lib.rs +2 -1
@@ -30,7 +30,8 @@#[allow(clippy::ptr_as_ptr)] #[allow(clippy::ref_as_ptr)] #[allow(clippy::undocumented_unsafe_blocks)] -#[cfg_attr( CONFIG_RUSTC_HAS_UNNECESSARY_TRANSMUTES , allow(unnecessary_transmutes))] +#[cfg_attr(not( CONFIG_RUSTC_HAS_UNNECESSARY_TRANSMUTES ), allow(unknown_lints))] +#[allow(unnecessary_transmutes)] #[cfg_attr( CONFIG_RUSTC_HAS_SUSPICIOUS_RUNTIME_SYMBOL_DEFINITIONS, allow(suspicious_runtime_symbol_definitions)
rust/uapi/lib.rs +2 -1
@@ -28,7 +28,8 @@ unreachable_pub, unsafe_op_in_unsafe_fn )] -#![cfg_attr( CONFIG_RUSTC_HAS_UNNECESSARY_TRANSMUTES , allow(unnecessary_transmutes))] +#![cfg_attr(not( CONFIG_RUSTC_HAS_UNNECESSARY_TRANSMUTES ), allow(unknown_lints))] +#![allow(unnecessary_transmutes)] #![cfg_attr( CONFIG_RUSTC_HAS_SUSPICIOUS_RUNTIME_SYMBOL_DEFINITIONS, allow(suspicious_runtime_symbol_definitions)
Greg Kroah-Hartman
maintainerPATCH 972/1250 drm/panic: clean new `clippy::needless_range_loop` lint for Rust 1.100.0
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Miguel Ojeda <[email protected]>
commit 97f8cb91a8c5658fe2ae6f5c2ff6e95474a5eb2f upstream.
Starting with Rust 1.100.0 (expected 2026-11-12), Clippy warns:
warning: the loop variable `i` is only used to index `self.decimals`
--> drivers/gpu/drm/drm_panic_qr.rs:410:18
|
410 | for i in 0..len {
| ^^^^^^
|
note: for this index operation
--> drivers/gpu/drm/drm_panic_qr.rs:411:13
|
411 | self.decimals[i] = (chunk % 10) as u8;
| ^^^^^^^^^^^^^^^^
= help: for further information visit https://rust-lang.github.io/rust-clippy/main/index.html#needless_range_loop
= note: `-W clippy::needless-range-loop` implied by `-W clippy::all`
= help: to override `-W clippy::all` add `#[allow(clippy::needless_range_loop)]`
help: consider using an iterator
|
410 - for i in 0..len {
410 + for <item> in self.decimals.iter_mut().take(len) {
|The lint did not trigger here before because it could not handle arrays behind a field access such as self.decimals -- Clippy was improved to catch those cases [1][2].
Thus clean the warning by iterating over a slice rather than using take() so that an out-of-range len still triggers the same bounds check as the indexed loop.
--- drivers/gpu/drm/drm_panic_qr.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/drm_panic_qr.rs +2 -2
@@ -407,8 +407,8 @@ fn push(&mut self, data: u64, len: usize) {for iin (0 ..self.len).rev () { self.decimals[i + len] = self.decimals[i]; } -for iin 0 ..len { - self.decimals[i] = (chunk %10 )as u8 ; +for decimalin &mut self.decimals[..len] { + *decimal = (chunk %10 )as u8 ; chunk =div10 (chunk); } self.len += len;
Signature · 1 line
2.55.0
Greg Kroah-Hartman
maintainerPATCH 973/1250 ALSA: ctxfi: Fix CA20K2 S/PDIF passthrough
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Roman Prucha <[email protected]>
commit b26a7a80e6bbf8dd17dacb127d12435d79375cf2 upstream.
dao_rsc_init() encodes the DAIO configuration as
conf = (desc->msr & 0x7) | (desc->passthru << 3);
S/PDIF passthrough uses msr=1 and passthru=1, resulting in conf=9.
daio_mgr_dao_init() masks conf with 0xf, but handles only values 1, 2, 4 and 8 when programming ATXCTL_NUC. As a result, conf=9 falls through to the default case and leaves NUC at its previous setting.
On a Creative X-Fi Titanium HD SB1270 (CA20K2), this breaks AC3 IEC61937 passthrough when snd_ctxfi runs with reference_rate=48000,multiple=2. The receiver detects a non-audio stream but cannot decode the AC3 payload.
With the unmodified driver, multiple=1 makes the same stream work. Handle conf=9 through the same NUC=0 path as conf=1.
The change was runtime tested on the SB1270 with multiple=2 using IEC958 stereo PCM, pre-encoded AC3 IEC61937 passthrough and ALSA A52 live 5.1 encoding.
--- sound/pci/ctxfi/cthw20k2.c | 1 + 1 file changed, 1 insertion(+)
sound/pci/ctxfi/cthw20k2.c +1 -0
@@ -993,6 +993,7 @@ static int daio_mgr_dao_init(void *blk,/* S/PDIF output */ switch ((conf &0xf )) {case 1 : +case 9 :set_field (&ctl->txctl[idx],ATXCTL_NUC ,0 );break ;case 2 :
Greg Kroah-Hartman
maintainerPATCH 974/1250 ALSA: us122l: Prevent write upgrades for read mappings
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kazuki Hanai <[email protected]>
commit 71c610aeb1770302ac9c9e0b9a4ecd37f1311928 upstream.
The hwdep mmap callback rejects read-buffer mappings that are initially writable, but leaves VM_MAYWRITE set on mappings created with PROT_READ. A process that can open the hwdep node O_RDWR can later use mprotect() to make the mapping writable.
The read allocation begins with struct usb_stream. Its read_size member is used by the fault handler to decide which pages belong to the read buffer. The read VMA intentionally remains expandable because pcm_usb_stream uses mremap() after reading that size. Changing read_size first can therefore map and access pages beyond the allocation. The same member is also consumed by usb_stream_free(), where changing it can make free_pages_exact() release pages outside the allocation.
Clear VM_MAYWRITE for read-buffer mappings after rejecting an initially writable VMA. This keeps the separate output-buffer mapping writable while preventing later permission upgrades.
--- sound/usb/usx2y/us122l.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
sound/usb/usx2y/us122l.c +5 -2
@@ -180,8 +180,11 @@ static int usb_stream_hwdep_mmap(structguard (mutex)(&us122l->mutex); s = us122l->sk.s; read = offset < s->read_size; -if (read && area->vm_flags &VM_WRITE ) -return -EPERM ; +if (read) { +if (area->vm_flags &VM_WRITE ) +return -EPERM ; +vm_flags_clear (area,VM_MAYWRITE ); + }/* if userspace tries to mmap beyond end of our buffer, fail */ if (size >PAGE_ALIGN (read ? s->read_size : s->write_size)) { dev_warn(hw->card->dev, "%s: size %lu > %u\n", __func__,
Greg Kroah-Hartman
maintainerPATCH 975/1250 ALSA: usbusx2y: fix in04_last array size mismatch with in04_buf
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tristan Madani <[email protected]>
commit 861111a14740e12c36d363e9830f8daa734279c9 upstream.
The in04_last array in struct usx2ydev is declared as char[24], but in04_buf is allocated as sizeof(struct us428_ctls) which is 21 bytes. In i_usx2y_in04_int(), when ctl_snapshot_last == -2 (initialization path):
memcpy(usx2y->in04_last, usx2y->in04_buf, sizeof(usx2y->in04_last));
This copies 24 bytes from a 21-byte slab allocation, reading 3 bytes past the end of the source object.
Introduce a USX2Y_IN04_SIZE constant defined as sizeof(struct us428_ctls) and use it consistently for the in04_last array, the in04_buf allocation, the URB transfer length, and the comparison loop, replacing the bare 24 and 21 literals throughout.
--- sound/usb/usx2y/usbusx2y.c | 6 +++--- sound/usb/usx2y/usbusx2y.h | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-)
sound/usb/usx2y/usbusx2y.c +3 -3
@@ -196,7 +196,7 @@ static void i_usx2y_in04_int(struct urbmemcpy (usx2y->in04_last, usx2y->in04_buf,sizeof (usx2y->in04_last)); us428ctls->ctl_snapshot_last =-1 ; }else { -for (i =0 ; i <21 ; i++) { +for (i =0 ; i <USX2Y_IN04_SIZE ; i++) {if (usx2y->in04_last[i] != ((char *)usx2y->in04_buf)[i]) {if (diff <0 ) diff = i;
@@ -305,7 +305,7 @@ int usx2y_in04_init(struct usx2ydev *usx goto error; } - usx2y->in04_buf =kmalloc (21 ,GFP_KERNEL ); + usx2y->in04_buf =kmalloc (USX2Y_IN04_SIZE ,GFP_KERNEL );if (!usx2y->in04_buf) { err = -ENOMEM ; goto error;
@@ -313,7 +313,7 @@ int usx2y_in04_init(struct usx2ydev *usxinit_waitqueue_head (&usx2y->in04_wait_queue);usb_fill_int_urb (usx2y->in04_urb, usx2y->dev,usb_rcvintpipe (usx2y->dev,0x4 ), - usx2y->in04_buf,21 , + usx2y->in04_buf,USX2Y_IN04_SIZE , i_usx2y_in04_int, usx2y,10 );if (usb_urb_ep_type_check (usx2y->in04_urb)) {
sound/usb/usx2y/usbusx2y.h +3 -1
@@ -5,6 +5,8 @@#include "../midi.h" #include "usbus428ctldefs.h" +#define USX2Y_IN04_SIZE sizeof(struct us428_ctls) +#define NRURBS 2/* Default value used for nr of packs per urb.
@@ -55,7 +57,7 @@ struct usx2ydev {int stride;struct urb *in04_urb;void *in04_buf; -char in04_last[24 ]; +char in04_last[USX2Y_IN04_SIZE ];unsigned int in04_int_calls;struct snd_usx2y_urb_seq *us04;wait_queue_head_t in04_wait_queue;
Greg Kroah-Hartman
maintainerPATCH 976/1250 ALSA: usbusx2y: validate URB actual_length in interrupt callback
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tristan Madani <[email protected]>
commit 8f5ef203abda9dd36b2af473c7b737d544f807bd upstream.
i_usx2y_in04_int() processes the interrupt URB data without checking urb->actual_length. A short transfer from a malfunctioning device would cause the handler to process uninitialized heap data from the kmalloc-allocated in04_buf, which is then copied to the mmap-accessible ctl_snapshot[] array.
Fix by using kzalloc() for in04_buf to zero-initialize the buffer, and adding an actual_length check to skip processing on short transfers while still resubmitting the URB.
--- sound/usb/usx2y/usbusx2y.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
sound/usb/usx2y/usbusx2y.c +5 -1
@@ -189,6 +189,9 @@ static void i_usx2y_in04_int(struct urbreturn ; } +if (urb->actual_length <USX2Y_IN04_SIZE ) + goto resubmit; +if (us428ctls) { diff =-1 ;if (us428ctls->ctl_snapshot_last ==-2 ) {
@@ -253,6 +256,7 @@ static void i_usx2y_in04_int(struct urbif (err)dev_err (&urb->dev->dev,"in04_int() usb_submit_urb err=%i\n" , err); +resubmit: urb->dev = usx2y->dev;usb_submit_urb (urb,GFP_ATOMIC ); }
@@ -305,7 +309,7 @@ int usx2y_in04_init(struct usx2ydev *usx goto error; } - usx2y->in04_buf =kmalloc (USX2Y_IN04_SIZE ,GFP_KERNEL ); + usx2y->in04_buf =kzalloc (USX2Y_IN04_SIZE ,GFP_KERNEL );if (!usx2y->in04_buf) { err = -ENOMEM ; goto error;
Greg Kroah-Hartman
maintainerPATCH 977/1250 Revert "riscv: Reset pmm when PR_TAGGED_ADDR_ENABLE is not set"
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Samuel Holland <[email protected]>
commit 2d2184ac90365a4af3274e23c98d469f09f91749 upstream.
This reverts commit 3033b2b1e3949274f33a140e2a97571b5a307298.
The reverted patch is userspace-visible behavior change, not a bug fix. The two variables here (pmm and pmlen) control two independent features:
pmm is the _hardware_ pointer masking mode that applies while executing in userspace. pmlen is the shift amount that the _kernel_ uses when untagging addresses; PMLEN_0 means no untagging occurs, so the kernel does not accept tagged addresses in syscall arguments.
It is valid (as documented and tested by the self test) to enable pointer masking without enabling the tagged address ABI. This separation is necessary to allow userspace to create an execution environment similar to what the kernel supports on arm64 by default, where TBI is enabled but the tagged address ABI is not. (On arm64, there is no equivalent to PR_PMLEN_MASK because TBI is always enabled.)
--- arch/riscv/kernel/process.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
arch/riscv/kernel/process.c +1 -3
@@ -324,10 +324,8 @@ long set_tagged_addr_ctrl(struct task_stif (arg &PR_TAGGED_ADDR_ENABLE && (tagged_addr_disabled || !pmlen))return -EINVAL ; -if (!(arg &PR_TAGGED_ADDR_ENABLE )) { +if (!(arg &PR_TAGGED_ADDR_ENABLE )) pmlen =PMLEN_0 ; - pmm =ENVCFG_PMM_PMLEN_0 ; - }if (mmap_write_lock_killable (mm))return -EINTR ;
Greg Kroah-Hartman
maintainerPATCH 978/1250 dm/amdgpu: fix malformed link_settings debugfs output
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 622b4e8505aa7453a53d17fa3a288871f270fc8b upstream.
[Why]dp_link_settings_read() passed strlen() of each format string as the size argument to snprintf() and then advanced rd_buf_ptr by that same fixed amount. The format-string length has no relation to the formatted output length, so snprintf() truncated each field at a NUL it wrote inside the buffer while the pointer was advanced past it. The result is a buffer peppered with embedded NUL bytes and fields that are silently cut short, so the data read back from the debugfs node does not reflect the actual link settings.
[How]
Use scnprintf() with the real remaining buffer size (rd_buf_size - (rd_buf_ptr - rd_buf)) and advance rd_buf_ptr by its return value, which is the number of characters actually written. This both bounds each write to the space left in rd_buf and keeps the output a single, properly terminated string. The now-unused str_len local is removed.
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 20 +++++--------- 1 file changed, 8 insertions(+), 12 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +8 -12
@@ -194,7 +194,6 @@ static ssize_t dp_link_settings_read(strchar *rd_buf_ptr =NULL ;const uint32_t rd_buf_size =100 ;uint32_t result =0 ; -uint8_t str_len =0 ;int r;if (*pos &3 || size &3 )
@@ -206,29 +205,26 @@ static ssize_t dp_link_settings_read(str rd_buf_ptr = rd_buf; - str_len =strlen ("Current: %d 0x%x %d " ); -snprintf (rd_buf_ptr, str_len,"Current: %d 0x%x %d " , + rd_buf_ptr +=scnprintf (rd_buf_ptr, rd_buf_size - (rd_buf_ptr - rd_buf), +"Current: %d 0x%x %d " , link->cur_link_settings.lane_count, link->cur_link_settings.link_rate, link->cur_link_settings.link_spread); - rd_buf_ptr += str_len; - str_len =strlen ("Verified: %d 0x%x %d " ); -snprintf (rd_buf_ptr, str_len,"Verified: %d 0x%x %d " , + rd_buf_ptr +=scnprintf (rd_buf_ptr, rd_buf_size - (rd_buf_ptr - rd_buf), +"Verified: %d 0x%x %d " , link->verified_link_cap.lane_count, link->verified_link_cap.link_rate, link->verified_link_cap.link_spread); - rd_buf_ptr += str_len; - str_len =strlen ("Reported: %d 0x%x %d " ); -snprintf (rd_buf_ptr, str_len,"Reported: %d 0x%x %d " , + rd_buf_ptr +=scnprintf (rd_buf_ptr, rd_buf_size - (rd_buf_ptr - rd_buf), +"Reported: %d 0x%x %d " , link->reported_link_cap.lane_count, link->reported_link_cap.link_rate, link->reported_link_cap.link_spread); - rd_buf_ptr += str_len; - str_len =strlen ("Preferred: %d 0x%x %d " ); -snprintf (rd_buf_ptr, str_len,"Preferred: %d 0x%x %d\n" , + rd_buf_ptr +=scnprintf (rd_buf_ptr, rd_buf_size - (rd_buf_ptr - rd_buf), +"Preferred: %d 0x%x %d\n" , link->preferred_link_setting.lane_count, link->preferred_link_setting.link_rate, link->preferred_link_setting.link_spread);
Greg Kroah-Hartman
maintainerPATCH 979/1250 drm/amdgpu: skip gfx switch_power_profile during GPU reset
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Prike Liang <[email protected]>
commit 1f1d43418d61c8511779e0f63a954a78b9433b43 upstream.
During resume from GPU reset, the gfx idle work may invoke switch_power_profile before the reset completes. This causes the following assert error because the register access occurs without first releasing the GPU reset semaphore:
[ 1576.768935] CR2: 0000559ea133ead0 CR3: 00000002e6c42000 CR4: 0000000000350ef0 [ 1576.768940] Call Trace: [ 1576.768944] <TASK> [ 1576.768953] amdgpu_device_rreg+0x21/0x50 [amdgpu] [ 1576.769158] smu_msg_v1_send_msg+0x1a4/0x6e0 [amdgpu] [ 1576.769437] smu_cmn_send_smc_msg_with_params_ext+0xba/0x120 [amdgpu] [ 1576.769721] smu_cmn_send_smc_msg_with_param+0x33/0x40 [amdgpu] [ 1576.769993] smu_v13_0_0_set_power_profile_mode+0x192/0x2b0 [amdgpu] [ 1576.770267] smu_bump_power_profile_mode+0x5d/0x80 [amdgpu] [ 1576.770538] smu_switch_power_profile+0xa4/0xf0 [amdgpu] [ 1576.770839] amdgpu_dpm_switch_power_profile+0x6f/0x90 [amdgpu] [ 1576.771210] amdgpu_gfx_profile_idle_work_handler+0xe9/0x130 [amdgpu] [ 1576.771460] process_one_work+0x23e/0x6f0 [ 1576.771491] worker_thread+0x1c4/0x380 [ 1576.771506] kthread+0x10c/0x150 [ 1576.771512] ? __pfx_worker_thread+0x10/0x10 [ 1576.771518] ? __pfx_kthread+0x10/0x10 [ 1576.771530] ret_from_fork+0x314/0x390 [ 1576.771537] ? __pfx_kthread+0x10/0x10 [ 1576.771546] ret_from_fork_asm+0x1a/0x30
--- drivers/gpu/drm/amd/pm/amdgpu_dpm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/pm/amdgpu_dpm.c +4 -2
@@ -348,7 +348,8 @@ int amdgpu_dpm_switch_power_profile(struconst struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;int ret =0 ; -if (amdgpu_sriov_vf (adev)) +if (amdgpu_sriov_vf (adev) || +amdgpu_in_reset (adev))return 0 ;if (pp_funcs && pp_funcs->switch_power_profile) {
@@ -367,7 +368,8 @@ int amdgpu_dpm_pause_power_profile(strucconst struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;int ret =0 ; -if (amdgpu_sriov_vf (adev)) +if (amdgpu_sriov_vf (adev) || +amdgpu_in_reset (adev))return 0 ;if (pp_funcs && pp_funcs->pause_power_profile) {
Greg Kroah-Hartman
maintainerPATCH 980/1250 watchdog: sunxi_wdt: preserve boot-enabled watchdog
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Hilliard <[email protected]>
commit aab55360fa11a2c054798a484ac67ad606f563e4 upstream.
sunxi_wdt_probe() unconditionally stops the watchdog even when firmware left it running. This opens an unprotected interval during boot and prevents CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED from taking over the active watchdog.
Detect an enabled watchdog and decode its programmed interval. Preserve representable timeouts, and round the 0.5-second interval up to the minimum representable one-second timeout. Use the configured timeout for reserved interval encodings. Set the Linux reset mode and ping the watchdog without clearing its enable bit, then mark it hardware-running before registration so the watchdog core services it until userspace takes control. Leave disabled watchdogs untouched.
--- drivers/watchdog/sunxi_wdt.c | 45 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-)
drivers/watchdog/sunxi_wdt.c +44 -1
@@ -128,6 +128,38 @@ static int sunxi_wdt_ping(struct watchdoreturn 0 ; } +static bool sunxi_wdt_is_running (struct watchdog_device *wdt_dev) +{ +struct sunxi_wdt_dev *sunxi_wdt =watchdog_get_drvdata (wdt_dev); +const struct sunxi_wdt_reg *regs = sunxi_wdt->wdt_regs; + +return readl (sunxi_wdt->wdt_base + regs->wdt_mode) &WDT_MODE_EN ; +} + +static unsigned int sunxi_wdt_get_timeout (struct watchdog_device *wdt_dev) +{ +struct sunxi_wdt_dev *sunxi_wdt =watchdog_get_drvdata (wdt_dev); +const struct sunxi_wdt_reg *regs = sunxi_wdt->wdt_regs; +unsigned int timeout; +u32 interval; + + interval =readl (sunxi_wdt->wdt_base + regs->wdt_mode); + interval >>= regs->wdt_timeout_shift; + interval &=WDT_TIMEOUT_MASK ; +/* Round the 0.5-second interval up to the minimum representable timeout. */ +if (!interval) +return WDT_MIN_TIMEOUT ; + +for (timeout =WDT_MIN_TIMEOUT ; + timeout <ARRAY_SIZE (wdt_timeout_map); timeout++) { +if (wdt_timeout_map[timeout] == interval) +return timeout; + } + +/* Reserved interval encoding. */ +return 0 ; +} +static int sunxi_wdt_set_timeout (struct watchdog_device *wdt_dev,unsigned int timeout) {
@@ -259,6 +291,7 @@ static int sunxi_wdt_probe(struct platfo {struct device *dev = &pdev->dev;struct sunxi_wdt_dev *sunxi_wdt; +unsigned int running_timeout;int err; sunxi_wdt =devm_kzalloc (dev,sizeof (*sunxi_wdt),GFP_KERNEL );
@@ -286,7 +319,17 @@ static int sunxi_wdt_probe(struct platfowatchdog_set_drvdata (&sunxi_wdt->wdt_dev, sunxi_wdt); -sunxi_wdt_stop (&sunxi_wdt->wdt_dev); +if (sunxi_wdt_is_running (&sunxi_wdt->wdt_dev)) { + running_timeout =sunxi_wdt_get_timeout (&sunxi_wdt->wdt_dev); +if (running_timeout) + sunxi_wdt->wdt_dev.timeout = running_timeout; + + err =sunxi_wdt_start (&sunxi_wdt->wdt_dev); +if (err) +return err; + +set_bit (WDOG_HW_RUNNING , &sunxi_wdt->wdt_dev.status); + }watchdog_stop_on_reboot (&sunxi_wdt->wdt_dev); err =devm_watchdog_register_device (dev, &sunxi_wdt->wdt_dev);
Greg Kroah-Hartman
maintainerPATCH 981/1250 virtio_mmio: disable IRQ wake before free_irq
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiong Weimin <[email protected]>
commit d14d693adb055e98ca705822ba6daebc18602d9a upstream.
When the DT node has "wakeup-source", vm_find_vqs() calls enable_irq_wake() on the shared IRQ, but vm_del_vqs() freed that IRQ without a matching disable_irq_wake(). That leaves a wake reference behind and can warn on later free_irq()/request_irq() cycles.
Record whether enable_irq_wake() succeeded, and disable it in vm_del_vqs() before free_irq().
Message-ID: <[email protected]>
--- drivers/virtio/virtio_mmio.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-)
drivers/virtio/virtio_mmio.c +13 -3
@@ -87,6 +87,9 @@ struct virtio_mmio_device {void __iomem *base;unsigned long version; + +/* True if enable_irq_wake() succeeded for the shared IRQ. */ +bool wake_irq_enabled; };/* Configuration interface */
@@ -329,11 +332,17 @@ static void vm_del_vqs(struct virtio_dev {struct virtio_mmio_device *vm_dev =to_virtio_mmio_device (vdev);struct virtqueue *vq, *n; +int irq =platform_get_irq (vm_dev->pdev,0 );list_for_each_entry_safe (vq, n, &vdev->vqs, list)vm_del_vq (vq); -free_irq (platform_get_irq (vm_dev->pdev,0 ), vm_dev); +if (vm_dev->wake_irq_enabled) { +disable_irq_wake (irq); + vm_dev->wake_irq_enabled = false; + } + +free_irq (irq, vm_dev); }static void vm_synchronize_cbs (struct virtio_device *vdev)
@@ -460,8 +469,9 @@ static int vm_find_vqs(struct virtio_devif (err)return err; -if (of_property_read_bool (vm_dev->pdev->dev.of_node,"wakeup-source" )) -enable_irq_wake (irq); +if (of_property_read_bool (vm_dev->pdev->dev.of_node,"wakeup-source" ) && + !enable_irq_wake (irq)) + vm_dev->wake_irq_enabled = true;for (i =0 ; i < nvqs; ++i) {struct virtqueue_info *vqi = &vqs_info[i];
Greg Kroah-Hartman
maintainerPATCH 982/1250 ufs: create the root dentry after loading cylinder metadata
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ali Ahmet Memis <[email protected]>
commit 55a4c98abb9694b067c6a031d11501f06b6b523c upstream.
ufs_fill_super() installed sb->s_root before it loaded the cylinder group structures for a writable mount:
sb->s_root = d_make_root(inode); ... if (!sb_rdonly(sb)) if (!ufs_read_cylinder_structures(sb)) goto failed;
When ufs_read_cylinder_structures() failed, the error path freed the in-core superblock information and set sb->s_fs_info to NULL while sb->s_root stayed installed. get_tree_bdev() then reached deactivate_locked_super(), and because s_root was present, generic_shutdown_super() called sync_filesystem() and the put_super operation. Both dereference UFS_SB(sb), which is now NULL, so a mount that fails only while reading the cylinder groups oopses during teardown. A crafted image whose first cylinder group cannot be read reaches this path.
Load the cylinder group metadata first and create the root dentry last, so the superblock is published to the VFS only once it is fully set up. ufs_setup_cstotal() and ufs_read_cylinder_structures() take only the super_block and do not use the root inode, so the reordering is safe.
--- fs/ufs/super.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-)
fs/ufs/super.c +9 -8
@@ -1200,6 +1200,15 @@ magic_found: sb->s_maxbytes =ufs_max_bytes (sb); sb->s_max_links =UFS_LINK_MAX ; +ufs_setup_cstotal (sb); +/* +* Read cylinder group structures +*/ +if (!sb_rdonly (sb)) +if (!ufs_read_cylinder_structures (sb)) + goto failed; + +/* create the root dentry last, once UFS_SB(sb) is fully set up */ inode =ufs_iget (sb,UFS_ROOTINO );if (IS_ERR (inode)) { ret =PTR_ERR (inode);
@@ -1211,14 +1220,6 @@ magic_found: goto failed; } -ufs_setup_cstotal (sb); -/* -* Read cylinder group structures -*/ -if (!sb_rdonly (sb)) -if (!ufs_read_cylinder_structures (sb)) - goto failed; -UFSD ("EXIT\n" );return 0 ;
Greg Kroah-Hartman
maintainerPATCH 983/1250 ufs: validate cylinder group metadata before caching it
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ali Ahmet Memis <[email protected]>
commit c9d263be26806d388129fab8c6904bed197fc6af upstream.
ufs_read_cylinder() copies the cylinder group index and the rotor positions straight from the on-disk group and caches them without any check:
ucpi->c_cgx = fs32_to_cpu(sb, ucg->cg_cgx); ucpi->c_rotor = fs32_to_cpu(sb, ucg->cg_rotor); ucpi->c_frotor = fs32_to_cpu(sb, ucg->cg_frotor); ucpi->c_irotor = fs32_to_cpu(sb, ucg->cg_irotor);
They are then used as indices during allocation and free:
- c_cgx indexes the cylinder summary array as UFS_SB(sb)->fs_cs(ucpi->c_cgx), so a value past s_ncg writes a 32 bit count outside the s_csp allocation.
- c_frotor becomes a bitmap scan start, start = c_frotor >> 3, and then length = ((s_fpg + 7) >> 3) - start. A start beyond the block bitmap wraps the unsigned length to a huge value, so ubh_scanc() walks far past the cylinder group buffers. c_irotor drives the inode bitmap the same way.
A crafted image can set any of these freely, turning an ordinary allocation into an out of bounds access.
Reject a cylinder group whose recorded index does not match the group being read, or whose rotors fall outside the group, before the metadata is cached. Valid filesystems keep cg_cgx equal to the group number and the rotors within the group, so only malformed images are rejected.
--- fs/ufs/cylinder.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
fs/ufs/cylinder.c +10 -0
@@ -68,6 +68,16 @@ static bool ufs_read_cylinder(struct sup ucpi->c_clustersumoff =fs32_to_cpu (sb, ucg->cg_u.cg_44.cg_clustersumoff); ucpi->c_clusteroff =fs32_to_cpu (sb, ucg->cg_u.cg_44.cg_clusteroff); ucpi->c_nclusterblks =fs32_to_cpu (sb, ucg->cg_u.cg_44.cg_nclusterblks); + +/* these on-disk values become array and bitmap indices */ +if (ucpi->c_cgx != cgno || + ucpi->c_rotor >= uspi->s_fpg || + ucpi->c_frotor >= uspi->s_fpg || + ucpi->c_irotor >= uspi->s_ipg) { +ufs_error (sb, __func__, +"inconsistent metadata in cylinder group %u\n" , cgno); + goto failed; + }UFSD ("EXIT\n" );return true;
Greg Kroah-Hartman
maintainerPATCH 984/1250 tunnels: Drop stale dst when building an ICMP error for PMTUD
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ido Schimmel <[email protected]>
commit b58d749633203d92c265317b45fccee555090352 upstream.
Bridged UDP tunnels such as VXLAN and GENEVE build an ICMP error packet around an overlay packet if the packet is going to exceed the underlay path MTU. The ICMP error packet is then injected back into the Rx path with the source and destination addresses swapped, so that it will be delivered to the overlay source.
If the overlay packet was routed to the UDP tunnel or locally generated, then it is already carrying a valid dst entry and this entry is not dropped when transforming the packet to an ICMP error packet. This causes the IP layer to reuse the dst entry, leading to the ICMP error packet being dropped or routed out of the UDP tunnel interface in case of forwarding.
Prior to the blamed commit this could not happen, as skb_tunnel_check_pmtu() did not build ICMP errors for PACKET_HOST packets. Such packets were instead encapsulated and, unless the DF bit was set in the outer header, fragmented by the underlay.
Fix this by making sure that the ICMP error packet does not have a valid dst entry, thereby forcing the IP layer to perform a route lookup.
Adjust the bridged PMTU exception selftests accordingly. When the local sender in ns_a pings the overlay destination with a deadline (-w), ping exits on the first socket error before any reply is received and returns a non-zero exit code. The test therefore only passed because the ICMP error was never delivered. Use a packet count (-c) like the ns_c line above it, so that the ICMP error counts against the packet budget and the exit code depends on whether echo replies were received. This passes with and without the fix.
--- net/ipv4/ip_tunnel_core.c | 6 ++++++ tools/testing/selftests/net/pmtu.sh | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-)
net/ipv4/ip_tunnel_core.c +6 -0
@@ -268,6 +268,9 @@ static int iptunnel_pmtud_build_icmp(streth_header (skb, skb->dev,ntohs (eh.h_proto), eh.h_source, eh.h_dest,0 );skb_reset_mac_header (skb); +if (skb_valid_dst (skb)) +skb_dst_drop (skb); +return skb->len; }
@@ -371,6 +374,9 @@ static int iptunnel_pmtud_build_icmpv6(seth_header (skb, skb->dev,ntohs (eh.h_proto), eh.h_source, eh.h_dest,0 );skb_reset_mac_header (skb); +if (skb_valid_dst (skb)) +skb_dst_drop (skb); +return skb->len; }
tools/testing/selftests/net/pmtu.sh +1 -1
@@ -1457,7 +1457,7 @@ test_pmtu_ipvX_over_bridged_vxlanY_or_ge mtu "${ns_b}" ${type}_b $((${ll_mtu} + 1000)) run_cmd ${ns_c} ${ping} -q -M want -i 0.1 -c 10 -s $((${ll_mtu} + 500)) ${dst} || return 1 - run_cmd ${ns_a} ${ping} -q -M want -i 0.1 -w 1 -s $((${ll_mtu} + 500)) ${dst} || return 1 + run_cmd ${ns_a} ${ping} -q -M want -i 0.1 -c 10 -s $((${ll_mtu} + 500)) ${dst} || return 1 # Check that exceptions were created pmtu="$(route_get_dst_pmtu_from_exception "${ns_c}" ${dst})"
Greg Kroah-Hartman
maintainerPATCH 985/1250 tick/broadcast: Plug clockevents replacement race
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Gleixner <[email protected]>
commit 113a9796effe3376d2ec5aabcca1fef4fef4cd62 upstream.
朱恺乾 reported and decoded the following race condition when a broadcast device is replaced:
CPUA CPUB
__tick_broadcast_oneshot_control()
bc = tick_broadcast_device.evtdev;
tick_install_broadcast_device(dev)
clockevents_exchange_device(cur, dev)
shutdown(cur);
detach(cur);
cur->handler = noop;
tick_broadcast_device.evtdev = dev; tick_broadcast_set_event(bc, next_event); <- FAIL: arms a detached device.
If the original broadcast device has a restricted interrupt affinity mask and the last CPU in that mask goes offline then the BUG() in tick_cleanup_dead_cpu() triggers because the clockevent device is not in detached state.
The reason for this is that tick_install_broadcast_device() is not serialized vs. tick broadcast operations.
The obvious cure is to serialize tick_install_broadcast_device() with tick_broadcast_lock against a concurrent tick broadcast operation.
That requires to split clockevents_exchange_device() into two parts, one which does the exchange, shutdown and detach operation and the other which drops the module reference count. This is required because the module reference cannot be dropped while holding tick_broadcast_lock.
Let clockevents_exchange_device() do both operations as before, but let the broadcast device code take the two step approach and do the device exchange under tick_broadcast_lock and drop the module reference count after releasing it.
--- kernel/time/clockevents.c | 33 ++++++++++++++++++++------------- kernel/time/tick-broadcast.c | 36 ++++++++++++++++++++++-------------- kernel/time/tick-internal.h | 2 ++ 3 files changed, 44 insertions(+), 27 deletions(-)
kernel/time/clockevents.c +20 -13
@@ -565,34 +565,41 @@ void clockevents_handle_noop(struct cloc { } -/** -* clockevents_exchange_device - release and request clock devices -* @old: device to release (can be NULL) -* @new: device to request (can be NULL) -* -* Called from various tick functions with clockevents_lock held and -* interrupts disabled. -*/ -void clockevents_exchange_device (struct clock_event_device *old, -struct clock_event_device *new) +void __clockevents_exchange_device (struct clock_event_device *old, +struct clock_event_device *new) {/* * Caller releases a clock event device. We queue it into the * released list and do a notify add later. */ if (old) { -module_put (old->owner);clockevents_switch_state (old,CLOCK_EVT_STATE_DETACHED );list_move (&old->list, &clockevents_released); }if (new) { -BUG_ON (!clockevent_state_detached (new)); +WARN_ON (!clockevent_state_detached (new));clockevents_shutdown (new); } }/** +* clockevents_exchange_device - release and request clock devices +* @old: device to release (can be NULL) +* @new: device to request (can be NULL) +* +* Called from various tick functions with clockevents_lock held and +* interrupts disabled. +*/ +void clockevents_exchange_device (struct clock_event_device *old, +struct clock_event_device *new) +{ +__clockevents_exchange_device (old, new); +if (old) +module_put (old->owner); +} + +/** * clockevents_suspend - suspend clock devices */ void clockevents_suspend (void )
@@ -649,7 +656,7 @@ void tick_offline_cpu(unsigned int cpu)if (cpumask_test_cpu (cpu, dev->cpumask) &&cpumask_weight (dev->cpumask) ==1 && !tick_is_broadcast_device (dev)) { -BUG_ON (!clockevent_state_detached (dev)); +WARN_ON (!clockevent_state_detached (dev));list_del (&dev->list); } }
kernel/time/tick-broadcast.c +22 -14
@@ -162,23 +162,31 @@ static bool tick_set_oneshot_wakeup_devi*/ void tick_install_broadcast_device (struct clock_event_device *dev,int cpu) { -struct clock_event_device *cur = tick_broadcast_device.evtdev; +struct clock_event_device *cur; -if (tick_set_oneshot_wakeup_device (dev, cpu)) -return ; + scoped_guard(raw_spinlock_irqsave, &tick_broadcast_lock) { -if (!tick_check_broadcast_device (cur, dev)) -return ; +if (tick_set_oneshot_wakeup_device (dev, cpu)) +return ; -if (!try_module_get (dev->owner)) -return ; + cur = tick_broadcast_device.evtdev; +if (!tick_check_broadcast_device (cur, dev)) +return ; -clockevents_exchange_device (cur, dev); +if (!try_module_get (dev->owner)) +return ; + +__clockevents_exchange_device (cur, dev); +if (cur) + cur->event_handler = clockevents_handle_noop; +WRITE_ONCE (tick_broadcast_device.evtdev, dev); +if (!cpumask_empty (tick_broadcast_mask)) +tick_broadcast_start_periodic (dev); + } + +/* Module release must be outside of the lock */ if (cur) - cur->event_handler = clockevents_handle_noop; - tick_broadcast_device.evtdev = dev; -if (!cpumask_empty (tick_broadcast_mask)) -tick_broadcast_start_periodic (dev); +module_put (cur->owner);if (!(dev->features &CLOCK_EVT_FEAT_ONESHOT ))return ;
@@ -1211,7 +1219,7 @@ int tick_broadcast_oneshot_active(void)*/ bool tick_broadcast_oneshot_available (void ) { -struct clock_event_device *bc = tick_broadcast_device.evtdev; +struct clock_event_device *bc =READ_ONCE (tick_broadcast_device.evtdev);return bc ? bc->features &CLOCK_EVT_FEAT_ONESHOT : false; }
@@ -1219,7 +1227,7 @@ bool tick_broadcast_oneshot_available(vo#else int __tick_broadcast_oneshot_control (enum tick_broadcast_state state) { -struct clock_event_device *bc = tick_broadcast_device.evtdev; +struct clock_event_device *bc =READ_ONCE (tick_broadcast_device.evtdev);if (!bc || (bc->features &CLOCK_EVT_FEAT_HRTIMER ))return -EBUSY ;
kernel/time/tick-internal.h +2 -0
@@ -54,6 +54,8 @@ static inline void clockevent_set_state( }extern void clockevents_shutdown (struct clock_event_device *dev); +extern void __clockevents_exchange_device (struct clock_event_device *old, +struct clock_event_device *new);extern void clockevents_exchange_device (struct clock_event_device *old,struct clock_event_device *new); extern void clockevents_switch_state(struct clock_event_device *dev,
Greg Kroah-Hartman
maintainerPATCH 986/1250 tools/bootconfig: Fix integer overflow and truncation in size checks
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 462d0b066b613103f579793031429db2ca23abc0 upstream.
Sashiko reported that on 32-bit systems, if an attacker crafts size in the bootconfig footer such that adding BOOTCONFIG_FOOTER_SIZE wraps around (for instance, if size is 0xFFFFFFFF), the size check in load_xbc_from_initrd() can be bypassed:
if (stat.st_size < size + BOOTCONFIG_FOOTER_SIZE) {
pr_err("bootconfig size is too big\n");
return -E2BIG;
}Furthermore, on 64-bit systems with an initrd > 4.29 GB, comparing a corrupted 32-bit size (e.g. 0xFFFFFFFF) against
stat.st_size - BOOTCONFIG_FOOTER_SIZE can also bypass the check if size is not bounded. Similarly, load_xbc_file() passes 64-bit stat.st_size directly into the 32-bit int size parameter of load_xbc_fd(), truncating large standalone files (>= 2GB).
In both cases, passing 0xFFFFFFFF to load_xbc_fd() truncates to -1, resulting in malloc(0), an integer overflow in read(), and an out-of-bounds null-byte write.
Fix this by:
1. Rejecting size > XBC_DATA_MAX or
size > stat.st_size - BOOTCONFIG_FOOTER_SIZE in load_xbc_from_initrd().
2. Rejecting stat.st_size > XBC_DATA_MAX in load_xbc_file() before passing it to load_xbc_fd().
3. Checking size < 0 || size > XBC_DATA_MAX defensively in load_xbc_fd().
--- tools/bootconfig/main.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
tools/bootconfig/main.c +12 -1
@@ -140,6 +140,9 @@ static int load_xbc_fd(int fd, char **bu {int ret; +if (size <0 || size >XBC_DATA_MAX ) +return -EINVAL ; + *buf =malloc (size +1 );if (!*buf)return -ENOMEM ;
@@ -168,6 +171,13 @@ static int load_xbc_file(const char *patreturn ret; } +if (stat.st_size >XBC_DATA_MAX ) { +pr_err ("%s size is too big\n" , path); + ret = -E2BIG ; +close (fd); +return ret; + } + ret =load_xbc_fd (fd, buf, stat.st_size);close (fd);
@@ -218,7 +228,8 @@ static int load_xbc_from_initrd(int fd, csum =le32toh (csum);/* Wrong size error */ -if (stat.st_size < size +BOOTCONFIG_FOOTER_SIZE ) { +if (size >XBC_DATA_MAX || + size > stat.st_size -BOOTCONFIG_FOOTER_SIZE ) {pr_err ("bootconfig size is too big\n" );return -E2BIG ; }
Greg Kroah-Hartman
maintainerPATCH 987/1250 tracing/user_events: Dont destroy fields when event removal fails
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Henry Martin <[email protected]>
commit 2deb753127d7b7035e893955c5e91875e767d1f8 upstream.
destroy_user_event() destroys the event's fields before attempting to remove the trace event call. If user_event_set_call_visible() fails, e.g. because the event is still enabled and trace_remove_event_call() returns -EBUSY, the event is left registered with an irreversibly destroyed field list. Any subsequent interaction with the event then operates on an empty field list while it is still fully visible in tracefs.
Move the field destruction after the call removal, and splice the field list back onto the event when the removal fails so the event remains in a consistent state.
--- kernel/trace/trace_events_user.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-)
kernel/trace/trace_events_user.c +20 -6
@@ -1122,10 +1122,9 @@ static void user_event_destroy_validator } } -static void user_event_destroy_fields (struct user_event *user) +static void user_event_destroy_fields (struct list_head *head) {struct ftrace_event_field *field, *next; -struct list_head *head = &user->fields;list_for_each_entry_safe (field, next, head, link) {list_del (&field->link);
@@ -1512,17 +1511,32 @@ static int user_event_set_call_visible(sstatic int destroy_user_event (struct user_event *user) { +LIST_HEAD (fields);int ret =0 ;lockdep_assert_held (&event_mutex); -/* Must destroy fields before call removal */ -user_event_destroy_fields (user); +/* +* Detach the fields before removing the call. Removing the event +* frees the field list memory (trace_destroy_fields() is run on +* successful removal and kmem_cache_free()s the fields), but the +* fields here are allocated and owned by user_events. Destroy +* them separately once removal has succeeded. +*/ +list_splice_init (&user->fields, &fields); ret =user_event_set_call_visible (user, false); -if (ret) +if (ret) { +/* +* Removal failed and the event stays registered, recover +* the fields so it is left in a consistent state. +*/ +list_splice (&fields, &user->fields);return ret; + } + +user_event_destroy_fields (&fields);dyn_event_remove (&user->devent);hash_del (&user->node);
@@ -2222,7 +2236,7 @@ static int user_event_parse(struct user_ put_user_lock:mutex_unlock (&event_mutex); put_user: -user_event_destroy_fields (user); +user_event_destroy_fields (&user->fields);user_event_destroy_validators (user);kfree (user->call.print_fmt);
Greg Kroah-Hartman
maintainerPATCH 988/1250 tracing: Free histogram the var ref when its initialization fails
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Donggeun Yoo <[email protected]>
commit 516001d53e6b2ea95a251ee2ef54a1a689a3fd58 upstream.
create_var_ref() allocates a VAR_REF hist_field and then calls init_var_ref() to fill it in. When that fails the field is leaked.
commit 656fe2ba85e8 ("tracing: Use hist trigger's var_ref array to destroy var_refs") made destroy_hist_field() return early for HIST_FIELD_FL_VAR_REF, since var refs are freed by walking the trigger's var_refs[] array instead. create_var_ref() adds the field to that array only after init_var_ref() has succeeded, so on this path the field is in neither place and nothing frees it. The call was correct when it was written, before var refs were taken out of destroy_hist_field().
init_var_ref() cannot free it either. The caller owns the field, so init_var_ref() undoes only its own string allocations and leaves the field alone. Freeing it there would leave create_var_ref() passing freed memory to destroy_hist_field(), which reads its flags.
Call __destroy_hist_field(), which frees the field without consulting the flag.
--- kernel/trace/trace_events_hist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/trace/trace_events_hist.c +1 -1
@@ -2228,7 +2228,7 @@ static struct hist_field *create_var_ref ref_field =create_hist_field (var_field->hist_data,NULL , flags,NULL );if (ref_field) {if (init_var_ref (ref_field, var_field, system, event_name)) { -destroy_hist_field (ref_field,0 ); +__destroy_hist_field (ref_field);return NULL ; }
Greg Kroah-Hartman
maintainerPATCH 989/1250 tracing: Free histogram var refs regardless of how often they are referenced
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Donggeun Yoo <[email protected]>
commit 4bddcb346a6cf4615ca77f69a589623b877ca267 upstream.
Using the same variable three or more times in one hist trigger leaks the variable reference and its strings when the trigger is removed.
commit 656fe2ba85e8 ("tracing: Use hist trigger's var_ref array to destroy var_refs") made a trigger's var_refs[] array the only owner of a var ref:destroy_hist_field() returns early for HIST_FIELD_FL_VAR_REF, so the field expressions never destroy one. One entry, freed once, no count needed.
commit 8bcebc77e85f ("tracing: Fix histogram code when expression has same var as value") then made repeated references share one object and added a count of them. Only the increment side exists, since those expressions still return early and never drop a reference, so __destroy_hist_field() sees how many references were created rather than how many are left. It frees when the decremented count is 0 or 1, so two references work and three or more leak.
Sharing kept one array entry per object, and create_var_ref() searches and appends within a single trigger, so nothing outside it holds the object. Removing a trigger whose variables are still referenced is already refused by check_var_refs() with -EBUSY. Drop the count and free unconditionally.
--- kernel/trace/trace_events_hist.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-)
kernel/trace/trace_events_hist.c +1 -15
@@ -164,7 +164,6 @@ struct hist_field {struct hist_field *operands[HIST_FIELD_OPERANDS_MAX ];struct hist_trigger_data *hist_data;enum hist_field_fn fn_num; -unsigned int ref;unsigned int size;unsigned int offset;unsigned int is_signed;
@@ -1905,16 +1904,8 @@ out:return field_op; } -static void get_hist_field (struct hist_field *hist_field) -{ - hist_field->ref++; -} -static void __destroy_hist_field (struct hist_field *hist_field) { -if (--hist_field->ref >1 ) -return ; -kfree (hist_field->var.name);kfree (hist_field->name);
@@ -1961,8 +1952,6 @@ static struct hist_field *create_hist_fiif (!hist_field)return NULL ; - hist_field->ref =1 ; - hist_field->hist_data = hist_data;if (flags &HIST_FIELD_FL_EXPR || flags &HIST_FIELD_FL_ALIAS )
@@ -2217,10 +2206,8 @@ static struct hist_field *create_var_reffor (i =0 ; i < hist_data->n_var_refs; i++) { ref_field = hist_data->var_refs[i];if (ref_field->var.idx == var_field->var.idx && - ref_field->var.hist_data == var_field->hist_data) { -get_hist_field (ref_field); + ref_field->var.hist_data == var_field->hist_data)return ref_field; - } }/* Sanity check to avoid out-of-bound write on 'hist_data->var_refs' */ if (hist_data->n_var_refs >=TRACING_MAP_VARS_MAX )
@@ -3264,7 +3251,6 @@ static struct hist_field *create_var(str goto out; } - var->ref =1 ; var->flags =HIST_FIELD_FL_VAR ; var->var.idx = idx; var->var.hist_data = var->hist_data = hist_data;
Greg Kroah-Hartman
maintainerPATCH 990/1250 tracing: Free histogram the field rejected for a bad modifier
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Donggeun Yoo <[email protected]>
commit 230234d12ce42ab04132a32c3a848f07a5d27a71 upstream.
Writing a hist trigger whose value or variable carries a modifier that is not allowed there leaks the fields that were built for it.
__create_val_field() takes the field from parse_expr() and stores it in hist_data->fields[] only after the modifier checks have run:
hist_field = parse_expr(hist_data, file, field_str, flags, var_name,
&n_subexprs);
...
if (hist_field->flags & HIST_FIELD_FL_VAR) {
if (hist_field->flags & (...))
goto err;
} else {
if (hist_field->flags & (...))
goto err;
}
hist_data->fields[val_idx] = hist_field;Both checks jump past that store, and the err label returns without freeing anything. The error unwinds to create_hist_data(), which calls destroy_hist_data() -> destroy_hist_fields(), and that reaches a field only by walking fields[]. A field that never got there is unreachable.
commit e0213434fe3e ("tracing: Do not let histogram values have some modifiers") set ret to -EINVAL and fell through to the store, which left the field owned by fields[] and freed along with the rest of hist_data. Splitting the check into a value case and a variable case replaced that fall-through with a goto that skips it.
With CONFIG_DEBUG_KMEMLEAK, 200 writes of
# echo 'hist:keys=prev_pid:vals=next_pid.log2' > \ events/sched/sched_switch/trigger
each correctly rejected with -EINVAL, leave 332 unreferenced objects (63744 bytes) reported at create_hist_field(); 200 install and remove cycles of a valid trigger leave none. A '.log2' field is two allocations, since create_hist_field() puts the plain field in operands[0] of the log2 field, and both are reported.
Use destroy_hist_field() rather than __destroy_hist_field() so that operands[0] is freed as well. It returns early for HIST_FIELD_FL_VAR_REF, which is what an operand owned by hist_data->var_refs[] needs; the rejected field itself is never a var ref, because a var ref never carries a modifier flag.
--- kernel/trace/trace_events_hist.c | 1 + 1 file changed, 1 insertion(+)
kernel/trace/trace_events_hist.c +1 -0
@@ -4305,6 +4305,7 @@ static int __create_val_field(struct hisreturn ret; err:hist_err (file->tr,HIST_ERR_BAD_FIELD_MODIFIER ,errpos (field_str)); +destroy_hist_field (hist_field,0 );return -EINVAL ; }
Greg Kroah-Hartman
maintainerPATCH 991/1250 tracing: Let histogram values keep the percent and graph modifiers
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Donggeun Yoo <[email protected]>
commit 3d617bfd79330ae3acf94862c18bb3ccf5f5a0f9 upstream.
The .percent and .graph modifiers exist only for histogram values, but a value carrying either of them has been rejected since v6.3. The example in Documentation/trace/histogram.rst,
# echo 'hist:keys=prev_comm:vals=hitcount.percent:nohitcount' > \ events/sched/sched_switch/trigger
returns -EINVAL.
parse_field() sets the two flags only when the field is neither a key nor a variable, that is, only on a value:
} else if (strncmp(modifier, "percent", 7) == 0) {
if (*flags & (HIST_FIELD_FL_VAR | HIST_FIELD_FL_KEY))
goto error;
*flags |= HIST_FIELD_FL_PERCENT;__create_val_field() then rejects a value for carrying them, so no field can reach hist_trigger_print_val(), where both are implemented.
commit e0213434fe3e ("tracing: Do not let histogram values have some modifiers") added the check after a value with .buckets oopsed in hist_field_name(). That happens because .buckets and .log2 make create_hist_field() build a nested field in operands[0] which hist_field_name() then walks into. The percent and graph flags do not create an operand and are not read by hist_field_name(); they are only used when printing a value.
Stop rejecting the two flags on a value. The check for variables is left alone, where they are unreachable anyway because parse_field() rejects a variable carrying them first.
With the two flags removed, the trigger above installs and prints as documented:
{ prev_comm: rcu_preempt } hitcount (%): 0.00
{ prev_comm: init } hitcount (%): 99.98
Totals:
Hits: 237896--- kernel/trace/trace_events_hist.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
kernel/trace/trace_events_hist.c +1 -2
@@ -4287,8 +4287,7 @@ static int __create_val_field(struct his goto err; }else {/* Value */ -if (hist_field->flags & (HIST_FIELD_FL_GRAPH |HIST_FIELD_FL_PERCENT | -HIST_FIELD_FL_BUCKET |HIST_FIELD_FL_LOG2 | +if (hist_field->flags & (HIST_FIELD_FL_BUCKET |HIST_FIELD_FL_LOG2 |HIST_FIELD_FL_SYM |HIST_FIELD_FL_SYM_OFFSET |HIST_FIELD_FL_SYSCALL |HIST_FIELD_FL_STACKTRACE )) goto err;